unix_io.c revision f154d2f687e922f8444ef3050dc83f5d8e0e2178
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
23839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * unix_io.c --- This is the Unix I/O interface to the I/O manager.
33839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
43839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Implements a one-block write-through cache.
53839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o * 	2002 by Theodore Ts'o.
819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header%
1019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
1119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * License.
1219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header%
133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
15dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE_SOURCE
16dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE64_SOURCE
17dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o
183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
204cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H
213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
224cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif
23c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#if HAVE_ERRNO_H
24c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#include <errno.h>
25c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#endif
263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <time.h>
28f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
29f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#include <sys/utsname.h>
30f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
311d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H
323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h>
331d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
341d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h>
361d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
378880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o#include <sys/resource.h>
383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
39b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
407b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include "ext2fs.h"
413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
42f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o/*
43f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * For checking structure magic numbers...
44f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o */
45f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
46f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#define EXT2_CHECK_MAGIC(struct, code) \
47f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	  if ((struct)->magic != (code)) return (code)
48adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
49adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostruct unix_cache {
50adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	char		*buf;
51adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	unsigned long	block;
52adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		access_time;
53adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		dirty:1;
54adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		in_use:1;
55adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o};
56adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
57adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define CACHE_SIZE 8
58adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define WRITE_VIA_CACHE_SIZE 4	/* Must be smaller than CACHE_SIZE */
59adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data {
61f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	int	magic;
623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	dev;
633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	flags;
64adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int	access_time;
65adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache cache[CACHE_SIZE];
663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel);
693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel);
703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize);
713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *data);
733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *data);
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel);
76c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
77c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				int size, const void *data);
783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
79f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = {
80f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_ET_MAGIC_IO_MANAGER,
813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	"Unix I/O Manager",
823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_open,
833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_close,
843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_set_blksize,
853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_read_blk,
863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_write_blk,
87c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_flush,
88c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_write_byte
893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager;
923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
93adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
94adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions
95adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
96adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
97adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      struct unix_private_data *data,
98adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      unsigned long block,
99adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      int count, void *buf)
100adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
101adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
102adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size_t		size;
103adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
104adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
105adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
106adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
107adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	location = (ext2_loff_t) block * channel->block_size;
108adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
109adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
110adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
111adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
112adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = read(data->dev, buf, size);
113adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
114adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (actual < 0)
115adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			actual = 0;
116adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_READ;
117adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
118adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
119adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
120adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
121adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
122adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	memset((char *) buf+actual, 0, size-actual);
123adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->read_error)
124adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
125adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o					       size, actual, retval);
126adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
127adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
128adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
129adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel,
130adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       struct unix_private_data *data,
131adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       unsigned long block,
132adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       int count, const void *buf)
133adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
134adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size_t		size;
135adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
136adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
137adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
138adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
139adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (count == 1)
140adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		size = channel->block_size;
141adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	else {
142adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (count < 0)
143adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = -count;
144adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
145adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = count * channel->block_size;
146adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
147adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
148adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	location = (ext2_loff_t) block * channel->block_size;
149adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
150adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
151adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
152adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
153adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
154adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = write(data->dev, buf, size);
155adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
156adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_WRITE;
157adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
158adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
159adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
160adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
161adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
162adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->write_error)
163adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->write_error)(channel, block, count, buf,
164adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o						size, actual, retval);
165adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
166adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
167adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
168adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
169adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
170adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions
171adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
172adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
173adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */
174adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel,
175adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			     struct unix_private_data *data)
176adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
177adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval;
178adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
179adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
180adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
181adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
182adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
183adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
184adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
185adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
186adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
187adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = ext2fs_get_mem(channel->block_size,
188adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o					     (void **) &cache->buf)))
189adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
190adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
191adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
192adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
193adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
194adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */
195adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic void free_cache(io_channel channel,
196adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		       struct unix_private_data *data)
197adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
198adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
199adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
200adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
201adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
202adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
203adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
204adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
205adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
206adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
207adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->buf)
208adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			ext2fs_free_mem((void **) &cache->buf);
209adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->buf = 0;
210adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
211adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
212adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
213adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
214adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Try to find a block in the cache.  If get_cache is non-zero, then
215adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * if the block isn't in the cache, evict the oldest block in the
216adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * cache and create a new cache entry for the requested block.
217adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
21831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'ostatic struct unix_cache *find_cached_block(io_channel channel,
21931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o					    struct unix_private_data *data,
22031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o					    unsigned long block,
22131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o					    int get_cache)
222adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
22331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	struct unix_cache	*cache, *unused_cache, *oldest_cache;
224adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
225adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
22631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	unused_cache = oldest_cache = 0;
227adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
228adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use) {
22931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			unused_cache = cache;
230adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
231adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
232adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->block == block) {
233adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->access_time = ++data->access_time;
234adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return cache;
235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!oldest_cache ||
237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		    (cache->access_time < oldest_cache->access_time))
238adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			oldest_cache = cache;
239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (!get_cache)
241adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return 0;
242adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
243adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
244adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * Try to allocate cache slot.
245adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
24631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	if (unused_cache)
24731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		cache = unused_cache;
248adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	else {
249adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache = oldest_cache;
250adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->dirty)
251adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			raw_write_blk(channel, data,
252adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				      cache->block, 1, cache->buf);
253adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
254adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->in_use = 1;
255adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->block = block;
256adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->access_time = ++data->access_time;
257adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return cache;
258adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
260adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache
262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
263adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel,
264adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     struct unix_private_data *data,
265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     int invalidate)
266adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
268adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval, retval2;
270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
271adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval2 = 0;
273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use)
275adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
276adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (invalidate)
278adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->in_use = 0;
279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
280adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->dirty)
281adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
282adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
283adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data,
284adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				       cache->block, 1, cache->buf);
285adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (retval)
286adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			retval2 = retval;
287adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->dirty = 0;
289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
290adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval2;
291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
292adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
2953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel)
2963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
2973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io_channel	io = NULL;
2983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data = NULL;
2993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
300dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	int		open_flags;
3018880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	struct stat	st;
302f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
303f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	struct 		utsname ut;
304f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
3053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
30650e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (name == 0)
30750e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return EXT2_ET_BAD_DEVICE_NAME;
3087b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct struct_io_channel),
3097b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o				(void **) &io);
3107b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3117b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		return retval;
312f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	memset(io, 0, sizeof(struct struct_io_channel));
313f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
3147b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct unix_private_data),
3157b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o				(void **) &data);
3167b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3187b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
3193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->manager = unix_io_manager;
3207b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(strlen(name)+1, (void **) &io->name);
3217b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3237b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	strcpy(io->name, name);
3253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->private_data = data;
326f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->block_size = 1024;
327f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->read_error = 0;
328f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->write_error = 0;
329a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	io->refcount = 1;
3303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(data, 0, sizeof(struct unix_private_data));
332f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
3337b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
334adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if ((retval = alloc_cache(io, data)))
335adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto cleanup;
336adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
337dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
338dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64
339dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	data->dev = open64(name, open_flags);
340dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else
341dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	data->dev = open(name, open_flags);
342dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif
3433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data->dev < 0) {
3443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
3453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
34764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o
34864e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__
34964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY
35064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
35164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY	((unsigned long)(~0UL>>1))
35264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else
35364e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY  (~0UL)
35464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
3558880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	/*
356f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
357f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * block devices are wrongly getting hit by the filesize
358f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * limit.  This workaround isn't perfect, since it won't work
359f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * if glibc wasn't built against 2.2 header files.  (Sigh.)
360f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 *
3618880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	 */
362f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	if ((flags & IO_FLAG_RW) &&
363f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    (uname(&ut) == 0) &&
364f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    ((ut.release[0] == '2') && (ut.release[1] == '.') &&
365f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[2] == '4') && (ut.release[3] == '.') &&
366f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[4] == '1') && (ut.release[5] >= '0') &&
367f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[5] < '8')) &&
3688880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (fstat(data->dev, &st) == 0) &&
3698880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (S_ISBLK(st.st_mode))) {
3708880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		struct rlimit	rlim;
3718880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o
37264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o		rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
3738880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		setrlimit(RLIMIT_FSIZE, &rlim);
3748880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		getrlimit(RLIMIT_FSIZE, &rlim);
375bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		if (((unsigned long) rlim.rlim_cur) <
376bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		    ((unsigned long) rlim.rlim_max)) {
3778880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			rlim.rlim_cur = rlim.rlim_max;
3788880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			setrlimit(RLIMIT_FSIZE, &rlim);
3798880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		}
3808880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	}
38164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
3823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*channel = io;
3833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
3843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup:
3863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data) {
387adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		free_cache(io, data);
3887b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &data);
3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
390adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (io)
391adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		ext2fs_free_mem((void **) &io);
3923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
3933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
3943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel)
3963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval = 0;
3993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
400f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
402f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
403a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
404a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	if (--channel->refcount > 0)
405a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		return 0;
406adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
407adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
408adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
4093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (close(data->dev) < 0)
4103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
411adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	free_cache(channel, data);
412f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o
413f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o	ext2fs_free_mem((void **) &channel->private_data);
4143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->name)
4157b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &channel->name);
4167b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	ext2fs_free_mem((void **) &channel);
4173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
4183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize)
4213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
4237b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
425f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
427f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
428f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
4293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->block_size != blksize) {
430adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
431adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
432adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
4333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		channel->block_size = blksize;
434adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		free_cache(channel, data);
435adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = alloc_cache(channel, data)))
4367b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
4373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
4433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *buf)
4443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
446adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache *cache;
4473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
44831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	char		*cp;
449adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		i, j;
4503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
451f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
453f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
4543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
456adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * If we're doing an odd-sized read, flush out the cache and
457adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * then do a direct read.
4583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
459adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (count < 0) {
460adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
461adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
462adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_read_blk(channel, data, block, count, buf);
4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
464adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
46531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
466adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
467adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* If it's in the cache, use it! */
468adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((cache = find_cached_block(channel, data, block, 0))) {
469adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
470adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			printf("Using cached block %d\n", block);
471f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif
47231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			memcpy(cp, cache->buf, channel->block_size);
473adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
474adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			block++;
47531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
476adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
477adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
478adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/*
479adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * Find the number of uncached blocks so we can do a
480adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * single read request
481adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 */
482adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (i=1; i < count; i++)
483adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			if (find_cached_block(channel, data, block+i, 0))
484adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				break;
485adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
486adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		printf("Reading %d blocks starting at %d\n", i, block);
487adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif
48831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		if ((retval = raw_read_blk(channel, data, block, i, cp)))
489adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
490adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
491adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* Save the results in the cache */
492adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (j=0; j < i; j++) {
493adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
494adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache = find_cached_block(channel, data, block++, 1);
495adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			if (cache)
49631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o				memcpy(cache->buf, cp, channel->block_size);
49731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
498adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
4993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
5013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
5043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *buf)
5053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
507adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache *cache;
508adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval = 0, retval2;
50931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	const char	*cp;
51031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	int		writethrough;
5113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
512f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
514f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
5153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
516adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
517adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * If we're doing an odd-sized write or a very large write,
518adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * flush out the cache completely and then do a direct write.
519adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
520adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (count < 0 || count > WRITE_VIA_CACHE_SIZE) {
521adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 1)))
522adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
523adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_write_blk(channel, data, block, count, buf);
5243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
526adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
527adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * For a moderate-sized multi-block write, first force a write
528adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * if we're in write-through cache mode, and then fill the
529adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * cache with the blocks.
530adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
531adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
532adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (writethrough)
533adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data, block, count, buf);
5343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
53531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
536adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
537adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache = find_cached_block(channel, data, block, 1);
538adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache) {
539adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			/*
540adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			 * Oh shit, we couldn't get cache descriptor.
541adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			 * Force the write directly.
542adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			 */
543adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			if ((retval2 = raw_write_blk(channel, data, block,
54431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o						1, cp)))
545adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				retval = retval2;
546adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		} else {
54731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			memcpy(cache->buf, cp, channel->block_size);
548adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->dirty = !writethrough;
549adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
550adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		count--;
551adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		block++;
55231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		cp += channel->block_size;
553adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
5543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
5553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
557c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
558c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				 int size, const void *buf)
559c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{
560c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	struct unix_private_data *data;
56131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	errcode_t	retval = 0;
562c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	size_t		actual;
563c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
564c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
565c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
566c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
567c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
568c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	/*
569c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 * Flush out the cache completely
570c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 */
571c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if ((retval = flush_cached_blocks(channel, data, 1)))
572c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return retval;
573c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
574c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (lseek(data->dev, offset, SEEK_SET) < 0)
575c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return errno;
576c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
577c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	actual = write(data->dev, buf, size);
578c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (actual != size)
579c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return EXT2_ET_SHORT_WRITE;
580c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
581c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	return 0;
582c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o}
583c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
5843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
58536f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk.
5863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
5873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel)
5883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
589f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	struct unix_private_data *data;
590adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t retval = 0;
591f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
592f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
593f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
594f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
595adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
596adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
59736f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o	fsync(data->dev);
598adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
5993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
601