unix_io.c revision 31dbecd482405e0d3a67eb58e1a1c8cb9f2ad83e
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 *
619c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
719c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
819c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header%
919c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
1019c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * License.
1119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header%
123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
14dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE_SOURCE
15dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE64_SOURCE
16dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o
173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
194cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H
203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
214cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif
22c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#if HAVE_ERRNO_H
23c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#include <errno.h>
24c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#endif
253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <time.h>
271d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H
283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h>
291d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
301d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H
313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h>
321d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
34b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#if EXT2_FLAT_INCLUDES
35b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
36b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#else
377b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include <linux/ext2_fs.h>
38b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#endif
397b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
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;
3013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
30250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (name == 0)
30350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return EXT2_ET_BAD_DEVICE_NAME;
3047b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct struct_io_channel),
3057b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o				(void **) &io);
3067b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3077b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		return retval;
308f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	memset(io, 0, sizeof(struct struct_io_channel));
309f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
3107b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct unix_private_data),
3117b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o				(void **) &data);
3127b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3147b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
3153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->manager = unix_io_manager;
3167b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(strlen(name)+1, (void **) &io->name);
3177b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3197b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
3203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	strcpy(io->name, name);
3213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->private_data = data;
322f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->block_size = 1024;
323f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->read_error = 0;
324f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->write_error = 0;
325a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	io->refcount = 1;
3263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(data, 0, sizeof(struct unix_private_data));
328f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
3297b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
330adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if ((retval = alloc_cache(io, data)))
331adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto cleanup;
332adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
333dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
334dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64
335dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	data->dev = open64(name, open_flags);
336dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else
337dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	data->dev = open(name, open_flags);
338dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif
3393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data->dev < 0) {
3403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
3413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*channel = io;
3443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
3453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup:
3473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data) {
348adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		free_cache(io, data);
3497b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &data);
3503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
351adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (io)
352adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		ext2fs_free_mem((void **) &io);
3533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
3543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
3553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel)
3573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
3593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval = 0;
3603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
361f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
3623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
363f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
364a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
365a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	if (--channel->refcount > 0)
366a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		return 0;
367adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
368adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
369adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
3703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (close(data->dev) < 0)
3713839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
372adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	free_cache(channel, data);
3733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->private_data)
3747b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &channel->private_data);
3753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->name)
3767b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &channel->name);
3777b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	ext2fs_free_mem((void **) &channel);
3783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
3793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
3803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize)
3823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
3847b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
3853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
386f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
3873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
388f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
389f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
3903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->block_size != blksize) {
391adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
392adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
393adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
3943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		channel->block_size = blksize;
395adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		free_cache(channel, data);
396adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = alloc_cache(channel, data)))
3977b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
3993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
4003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
4043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *buf)
4053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
407adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache *cache;
4083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
40931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	char		*cp;
410adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		i, j;
4113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
412f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
414f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
4153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
417adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * If we're doing an odd-sized read, flush out the cache and
418adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * then do a direct read.
4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
420adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (count < 0) {
421adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
422adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
423adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_read_blk(channel, data, block, count, buf);
4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
425adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
42631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
427adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
428adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* If it's in the cache, use it! */
429adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((cache = find_cached_block(channel, data, block, 0))) {
430adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
431adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			printf("Using cached block %d\n", block);
432f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif
43331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			memcpy(cp, cache->buf, channel->block_size);
434adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
435adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			block++;
43631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
437adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
438adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
439adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/*
440adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * Find the number of uncached blocks so we can do a
441adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * single read request
442adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 */
443adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (i=1; i < count; i++)
444adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			if (find_cached_block(channel, data, block+i, 0))
445adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				break;
446adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
447adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		printf("Reading %d blocks starting at %d\n", i, block);
448adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif
44931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		if ((retval = raw_read_blk(channel, data, block, i, cp)))
450adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
451adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
452adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* Save the results in the cache */
453adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (j=0; j < i; j++) {
454adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
455adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache = find_cached_block(channel, data, block++, 1);
456adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			if (cache)
45731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o				memcpy(cache->buf, cp, channel->block_size);
45831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
459adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
4623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
4653839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *buf)
4663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4673839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
468adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache *cache;
469adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval = 0, retval2;
47031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	const char	*cp;
47131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	int		writethrough;
4723839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
473f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
475f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
4763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
477adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
478adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * If we're doing an odd-sized write or a very large write,
479adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * flush out the cache completely and then do a direct write.
480adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
481adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (count < 0 || count > WRITE_VIA_CACHE_SIZE) {
482adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 1)))
483adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
484adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_write_blk(channel, data, block, count, buf);
4853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
487adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
488adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * For a moderate-sized multi-block write, first force a write
489adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * if we're in write-through cache mode, and then fill the
490adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * cache with the blocks.
491adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
492adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
493adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (writethrough)
494adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data, block, count, buf);
4953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
49631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
497adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
498adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache = find_cached_block(channel, data, block, 1);
499adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache) {
500adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			/*
501adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			 * Oh shit, we couldn't get cache descriptor.
502adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			 * Force the write directly.
503adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			 */
504adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			if ((retval2 = raw_write_blk(channel, data, block,
50531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o						1, cp)))
506adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				retval = retval2;
507adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		} else {
50831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			memcpy(cache->buf, cp, channel->block_size);
509adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->dirty = !writethrough;
510adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
511adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		count--;
512adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		block++;
51331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		cp += channel->block_size;
514adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
5153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
5163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
518c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
519c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				 int size, const void *buf)
520c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{
521c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	struct unix_private_data *data;
52231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	errcode_t	retval = 0;
523c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	size_t		actual;
524c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
525c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
526c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
527c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
528c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
529c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	/*
530c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 * Flush out the cache completely
531c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 */
532c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if ((retval = flush_cached_blocks(channel, data, 1)))
533c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return retval;
534c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
535c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (lseek(data->dev, offset, SEEK_SET) < 0)
536c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return errno;
537c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
538c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	actual = write(data->dev, buf, size);
539c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (actual != size)
540c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return EXT2_ET_SHORT_WRITE;
541c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
542c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	return 0;
543c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o}
544c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
5453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
54636f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk.
5473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
5483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel)
5493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
550f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	struct unix_private_data *data;
551adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t retval = 0;
552f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
553f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
554f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
555f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
556adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
557adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
55836f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o	fsync(data->dev);
559adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
5603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
562