unix_io.c revision 82c4660c756fba5eae289e6fbf03fab55393e3e2
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
5882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define WRITE_DIRECT_SIZE 4	/* Must be smaller than CACHE_SIZE */
5982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define READ_DIRECT_SIZE 4	/* Should be smaller than CACHE_SIZE */
60adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data {
62f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	int	magic;
633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	dev;
643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	flags;
65adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int	access_time;
66adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache cache[CACHE_SIZE];
673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel);
703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel);
713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize);
723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *data);
743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *data);
763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel);
77c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
78c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				int size, const void *data);
793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
80f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = {
81f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_ET_MAGIC_IO_MANAGER,
823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	"Unix I/O Manager",
833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_open,
843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_close,
853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_set_blksize,
863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_read_blk,
873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_write_blk,
88c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_flush,
89c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_write_byte
903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager;
933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
94adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
95adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions
96adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
97adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
98adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      struct unix_private_data *data,
99adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      unsigned long block,
100adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      int count, void *buf)
101adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
102adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
103adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size_t		size;
104adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
105adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
106adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
107adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
108adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	location = (ext2_loff_t) block * channel->block_size;
109adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
110adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
111adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
112adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
113adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = read(data->dev, buf, size);
114adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
115adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (actual < 0)
116adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			actual = 0;
117adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_READ;
118adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
119adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
120adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
121adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
122adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
123adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	memset((char *) buf+actual, 0, size-actual);
124adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->read_error)
125adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
126adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o					       size, actual, retval);
127adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
128adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
129adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
130adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel,
131adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       struct unix_private_data *data,
132adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       unsigned long block,
133adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       int count, const void *buf)
134adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
135adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size_t		size;
136adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
137adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
138adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
139adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
140adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (count == 1)
141adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		size = channel->block_size;
142adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	else {
143adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (count < 0)
144adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = -count;
145adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
146adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = count * channel->block_size;
147adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
148adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
149adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	location = (ext2_loff_t) block * channel->block_size;
150adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
151adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
152adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
153adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
154adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
155adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = write(data->dev, buf, size);
156adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
157adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_WRITE;
158adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
159adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
160adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
161adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
162adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
163adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->write_error)
164adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->write_error)(channel, block, count, buf,
165adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o						size, actual, retval);
166adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
167adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
168adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
169adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
170adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
171adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions
172adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
173adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
174adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */
175adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel,
176adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			     struct unix_private_data *data)
177adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
178adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval;
179adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
180adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
181adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
182adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
183adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
184adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
185adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
186adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
187adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
188adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = ext2fs_get_mem(channel->block_size,
189adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o					     (void **) &cache->buf)))
190adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
191adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
192adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
193adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
194adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
195adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */
196adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic void free_cache(io_channel channel,
197adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		       struct unix_private_data *data)
198adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
199adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
200adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
201adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
202adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
203adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
204adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
205adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
206adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
207adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
208adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->buf)
209adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			ext2fs_free_mem((void **) &cache->buf);
210adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->buf = 0;
211adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
212adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
213adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
214adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
21582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Try to find a block in the cache.  If the block is not found, and
21682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * eldest is a non-zero pointer, then fill in eldest with the cache
21782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * entry to that should be reused.
218adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
21931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'ostatic struct unix_cache *find_cached_block(io_channel channel,
22031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o					    struct unix_private_data *data,
22131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o					    unsigned long block,
22282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					    struct unix_cache **eldest)
223adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
22431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	struct unix_cache	*cache, *unused_cache, *oldest_cache;
225adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
226adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
22731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	unused_cache = oldest_cache = 0;
228adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
229adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use) {
23082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			if (!unused_cache)
23182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o				unused_cache = cache;
232adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
233adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
234adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->block == block) {
235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->access_time = ++data->access_time;
236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return cache;
237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
238adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!oldest_cache ||
239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		    (cache->access_time < oldest_cache->access_time))
240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			oldest_cache = cache;
241adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
24282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (eldest)
24382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		*eldest = (unused_cache) ? unused_cache : oldest_cache;
24482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	return 0;
24582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o}
24682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
24782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o/*
24882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Reuse a particular cache entry for another block.
24982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o */
25082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'ovoid reuse_cache(io_channel channel, struct unix_private_data *data,
25182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		 struct unix_cache *cache, unsigned long block)
25282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o{
25382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (cache->dirty && cache->in_use)
25482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		raw_write_blk(channel, data, cache->block, 1, cache->buf);
25582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
256adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->in_use = 1;
2571d47dfb91ef010c506e9354dec102385d8494d8fTheodore Ts'o	cache->dirty = 0;
258adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->block = block;
259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->access_time = ++data->access_time;
260adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
263adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache
264adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel,
266adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     struct unix_private_data *data,
267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     int invalidate)
268adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
271adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval, retval2;
272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval2 = 0;
275adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
276adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use)
277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
278adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (invalidate)
280adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->in_use = 0;
281adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
282adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->dirty)
283adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
284adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
285adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data,
286adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				       cache->block, 1, cache->buf);
287adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (retval)
288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			retval2 = retval;
289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
290adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->dirty = 0;
291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
292adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval2;
293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
295adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
296adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
2973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel)
2983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
2993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io_channel	io = NULL;
3003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data = NULL;
3013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
302dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	int		open_flags;
3038880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	struct stat	st;
304f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
305f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	struct 		utsname ut;
306f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
3073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
30850e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (name == 0)
30950e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return EXT2_ET_BAD_DEVICE_NAME;
3107b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct struct_io_channel),
3117b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o				(void **) &io);
3127b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3137b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		return retval;
314f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	memset(io, 0, sizeof(struct struct_io_channel));
315f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
3167b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct unix_private_data),
3177b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o				(void **) &data);
3187b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3207b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
3213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->manager = unix_io_manager;
3227b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(strlen(name)+1, (void **) &io->name);
3237b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3257b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
3263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	strcpy(io->name, name);
3273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->private_data = data;
328f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->block_size = 1024;
329f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->read_error = 0;
330f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->write_error = 0;
331a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	io->refcount = 1;
3323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(data, 0, sizeof(struct unix_private_data));
334f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
3357b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
336adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if ((retval = alloc_cache(io, data)))
337adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto cleanup;
338adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
339dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
340dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64
341dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	data->dev = open64(name, open_flags);
342dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else
343dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	data->dev = open(name, open_flags);
344dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif
3453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data->dev < 0) {
3463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
3473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
34964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o
35064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__
35164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY
35264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
35364e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY	((unsigned long)(~0UL>>1))
35464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else
35564e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY  (~0UL)
35664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
3578880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	/*
358f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
359f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * block devices are wrongly getting hit by the filesize
360f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * limit.  This workaround isn't perfect, since it won't work
361f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * if glibc wasn't built against 2.2 header files.  (Sigh.)
362f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 *
3638880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	 */
364f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	if ((flags & IO_FLAG_RW) &&
365f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    (uname(&ut) == 0) &&
366f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    ((ut.release[0] == '2') && (ut.release[1] == '.') &&
367f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[2] == '4') && (ut.release[3] == '.') &&
368f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[4] == '1') && (ut.release[5] >= '0') &&
369f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[5] < '8')) &&
3708880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (fstat(data->dev, &st) == 0) &&
3718880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (S_ISBLK(st.st_mode))) {
3728880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		struct rlimit	rlim;
3738880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o
37464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o		rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
3758880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		setrlimit(RLIMIT_FSIZE, &rlim);
3768880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		getrlimit(RLIMIT_FSIZE, &rlim);
377bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		if (((unsigned long) rlim.rlim_cur) <
378bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		    ((unsigned long) rlim.rlim_max)) {
3798880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			rlim.rlim_cur = rlim.rlim_max;
3808880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			setrlimit(RLIMIT_FSIZE, &rlim);
3818880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		}
3828880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	}
38364e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
3843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*channel = io;
3853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
3863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup:
3883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data) {
389adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		free_cache(io, data);
3907b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &data);
3913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
392adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (io)
393adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		ext2fs_free_mem((void **) &io);
3943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
3953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
3963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel)
3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
4003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval = 0;
4013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
402f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
404f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
405a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
406a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	if (--channel->refcount > 0)
407a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		return 0;
408adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
409adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
410adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
4113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (close(data->dev) < 0)
4123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
413adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	free_cache(channel, data);
414f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o
415f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o	ext2fs_free_mem((void **) &channel->private_data);
4163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->name)
4177b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &channel->name);
4187b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	ext2fs_free_mem((void **) &channel);
4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
4203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize)
4233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
4257b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
4263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
427f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
429f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
430f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
4313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->block_size != blksize) {
432adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
433adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
434adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
4353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		channel->block_size = blksize;
436adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		free_cache(channel, data);
437adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = alloc_cache(channel, data)))
4387b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
4413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
4453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *buf)
4463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
44882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
4493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
45031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	char		*cp;
451adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		i, j;
4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
453f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
455f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
4563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
45882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * If we're doing an odd-sized read or a very large read,
45982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * flush out the cache and then do a direct read.
4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
46182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
462adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
463adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
464adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_read_blk(channel, data, block, count, buf);
4653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
466adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
46731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
468adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
469adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* If it's in the cache, use it! */
47082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		if ((cache = find_cached_block(channel, data, block,
47182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					       &reuse[0]))) {
472adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
473adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			printf("Using cached block %d\n", block);
474f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif
47531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			memcpy(cp, cache->buf, channel->block_size);
476adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
477adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			block++;
47831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
479adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
480adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
481adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/*
482adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * Find the number of uncached blocks so we can do a
483adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * single read request
484adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 */
485adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (i=1; i < count; i++)
48682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			if (find_cached_block(channel, data, block+i,
48782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					      &reuse[i]))
488adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				break;
489adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
490adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		printf("Reading %d blocks starting at %d\n", i, block);
491adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif
49231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		if ((retval = raw_read_blk(channel, data, block, i, cp)))
493adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
494adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
495adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* Save the results in the cache */
496adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (j=0; j < i; j++) {
497adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
49882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse[j];
49982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block++);
50082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			memcpy(cache->buf, cp, channel->block_size);
50131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
502adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
5033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
5053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
5083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *buf)
5093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
51182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse;
512adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval = 0, retval2;
51331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	const char	*cp;
51431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	int		writethrough;
5153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
516f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
518f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
5193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
520adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
521adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * If we're doing an odd-sized write or a very large write,
522adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * flush out the cache completely and then do a direct write.
523adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
52482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
525adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 1)))
526adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
527adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_write_blk(channel, data, block, count, buf);
5283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
530adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
531adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * For a moderate-sized multi-block write, first force a write
532adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * if we're in write-through cache mode, and then fill the
533adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * cache with the blocks.
534adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
535adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
536adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (writethrough)
537adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data, block, count, buf);
5383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
53931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
540adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
54182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		cache = find_cached_block(channel, data, block, &reuse);
542adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache) {
54382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse;
54482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block);
545adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
54682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		memcpy(cache->buf, cp, channel->block_size);
54782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		cache->dirty = !writethrough;
548adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		count--;
549adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		block++;
55031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		cp += channel->block_size;
551adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
5523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
5533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
555c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
556c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				 int size, const void *buf)
557c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{
558c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	struct unix_private_data *data;
55931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	errcode_t	retval = 0;
560c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	size_t		actual;
561c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
562c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
563c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
564c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
565c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
566c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	/*
567c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 * Flush out the cache completely
568c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 */
569c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if ((retval = flush_cached_blocks(channel, data, 1)))
570c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return retval;
571c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
572c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (lseek(data->dev, offset, SEEK_SET) < 0)
573c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return errno;
574c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
575c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	actual = write(data->dev, buf, size);
576c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (actual != size)
577c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return EXT2_ET_SHORT_WRITE;
578c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
579c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	return 0;
580c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o}
581c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
5823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
58336f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk.
5843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
5853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel)
5863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
587f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	struct unix_private_data *data;
588adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t retval = 0;
589f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
590f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
591f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
592f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
593adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
594adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
59536f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o	fsync(data->dev);
596adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
5973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
599