unix_io.c revision 23b7c8b88673248b1f93abc717943867ad037bb4
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
8023b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
8123b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o		 struct unix_cache *cache, unsigned long block);
8223b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o
83f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = {
84f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_ET_MAGIC_IO_MANAGER,
853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	"Unix I/O Manager",
863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_open,
873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_close,
883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_set_blksize,
893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_read_blk,
903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_write_blk,
91c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_flush,
92c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_write_byte
933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager;
963839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
97adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
98adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions
99adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
100adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
101adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      struct unix_private_data *data,
102adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      unsigned long block,
103adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      int count, void *buf)
104adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
105adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
106adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size_t		size;
107adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
108adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
109adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
110adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
111adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	location = (ext2_loff_t) block * channel->block_size;
112adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
113adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
114adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
115adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
116adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = read(data->dev, buf, size);
117adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
118adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (actual < 0)
119adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			actual = 0;
120adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_READ;
121adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
122adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
123adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
124adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
125adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
126adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	memset((char *) buf+actual, 0, size-actual);
127adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->read_error)
128adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
129adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o					       size, actual, retval);
130adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
131adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
132adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
133adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel,
134adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       struct unix_private_data *data,
135adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       unsigned long block,
136adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       int count, const void *buf)
137adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
138adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size_t		size;
139adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
140adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
141adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
142adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
143adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (count == 1)
144adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		size = channel->block_size;
145adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	else {
146adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (count < 0)
147adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = -count;
148adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
149adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = count * channel->block_size;
150adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
151adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
152adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	location = (ext2_loff_t) block * channel->block_size;
153adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
154adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
155adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
156adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
157adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
158adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = write(data->dev, buf, size);
159adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
160adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_WRITE;
161adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
162adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
163adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
164adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
165adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
166adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->write_error)
167adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->write_error)(channel, block, count, buf,
168adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o						size, actual, retval);
169adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
170adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
171adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
172adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
173adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
174adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions
175adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
176adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
177adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */
178adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel,
179adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			     struct unix_private_data *data)
180adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
181adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval;
182adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
183adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
184adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
185adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
186adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
187adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
188adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
189adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
190adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
191adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = ext2fs_get_mem(channel->block_size,
192adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o					     (void **) &cache->buf)))
193adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
194adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
195adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
196adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
197adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
198adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */
199adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic void free_cache(io_channel channel,
200adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		       struct unix_private_data *data)
201adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
202adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
203adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
204adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
205adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
206adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
207adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
208adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
209adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
210adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
211adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->buf)
212adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			ext2fs_free_mem((void **) &cache->buf);
213adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->buf = 0;
214adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
215adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
216adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
217adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
21882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Try to find a block in the cache.  If the block is not found, and
21982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * eldest is a non-zero pointer, then fill in eldest with the cache
22082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * entry to that should be reused.
221adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
22231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'ostatic struct unix_cache *find_cached_block(io_channel channel,
22331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o					    struct unix_private_data *data,
22431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o					    unsigned long block,
22582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					    struct unix_cache **eldest)
226adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
22731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	struct unix_cache	*cache, *unused_cache, *oldest_cache;
228adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
229adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
23031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	unused_cache = oldest_cache = 0;
231adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
232adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use) {
23382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			if (!unused_cache)
23482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o				unused_cache = cache;
235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->block == block) {
238adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->access_time = ++data->access_time;
239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return cache;
240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
241adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!oldest_cache ||
242adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		    (cache->access_time < oldest_cache->access_time))
243adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			oldest_cache = cache;
244adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
24582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (eldest)
24682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		*eldest = (unused_cache) ? unused_cache : oldest_cache;
24782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	return 0;
24882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o}
24982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
25082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o/*
25182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Reuse a particular cache entry for another block.
25282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o */
25323b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
25482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		 struct unix_cache *cache, unsigned long block)
25582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o{
25682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (cache->dirty && cache->in_use)
25782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		raw_write_blk(channel, data, cache->block, 1, cache->buf);
25882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->in_use = 1;
2601d47dfb91ef010c506e9354dec102385d8494d8fTheodore Ts'o	cache->dirty = 0;
261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->block = block;
262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->access_time = ++data->access_time;
263adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
264adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
266adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache
267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
268adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel,
269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     struct unix_private_data *data,
270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     int invalidate)
271adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval, retval2;
275adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
276adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval2 = 0;
278adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use)
280adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
281adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
282adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (invalidate)
283adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->in_use = 0;
284adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
285adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->dirty)
286adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
287adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data,
289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				       cache->block, 1, cache->buf);
290adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (retval)
291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			retval2 = retval;
292adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->dirty = 0;
294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
295adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval2;
296adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
297adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
298adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
299adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
3003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel)
3013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
3023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io_channel	io = NULL;
3033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data = NULL;
3043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
305dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	int		open_flags;
3068880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	struct stat	st;
307f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
308f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	struct 		utsname ut;
309f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
3103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
31150e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (name == 0)
31250e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return EXT2_ET_BAD_DEVICE_NAME;
3137b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct struct_io_channel),
3147b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o				(void **) &io);
3157b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3167b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		return retval;
317f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	memset(io, 0, sizeof(struct struct_io_channel));
318f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
3197b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct unix_private_data),
3207b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o				(void **) &data);
3217b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3237b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
3243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->manager = unix_io_manager;
3257b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	retval = ext2fs_get_mem(strlen(name)+1, (void **) &io->name);
3267b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
3273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3287b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
3293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	strcpy(io->name, name);
3303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->private_data = data;
331f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->block_size = 1024;
332f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->read_error = 0;
333f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->write_error = 0;
334a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	io->refcount = 1;
3353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(data, 0, sizeof(struct unix_private_data));
337f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
3387b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
339adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if ((retval = alloc_cache(io, data)))
340adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto cleanup;
341adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
342dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
343dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64
344dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	data->dev = open64(name, open_flags);
345dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else
346dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	data->dev = open(name, open_flags);
347dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif
3483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data->dev < 0) {
3493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
3503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
3513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
35264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o
35364e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__
35464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY
35564e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
35664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY	((unsigned long)(~0UL>>1))
35764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else
35864e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY  (~0UL)
35964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
3608880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	/*
361f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
362f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * block devices are wrongly getting hit by the filesize
363f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * limit.  This workaround isn't perfect, since it won't work
364f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * if glibc wasn't built against 2.2 header files.  (Sigh.)
365f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 *
3668880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	 */
367f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	if ((flags & IO_FLAG_RW) &&
368f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    (uname(&ut) == 0) &&
369f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    ((ut.release[0] == '2') && (ut.release[1] == '.') &&
370f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[2] == '4') && (ut.release[3] == '.') &&
371f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[4] == '1') && (ut.release[5] >= '0') &&
372f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[5] < '8')) &&
3738880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (fstat(data->dev, &st) == 0) &&
3748880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (S_ISBLK(st.st_mode))) {
3758880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		struct rlimit	rlim;
3768880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o
37764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o		rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
3788880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		setrlimit(RLIMIT_FSIZE, &rlim);
3798880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		getrlimit(RLIMIT_FSIZE, &rlim);
380bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		if (((unsigned long) rlim.rlim_cur) <
381bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		    ((unsigned long) rlim.rlim_max)) {
3828880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			rlim.rlim_cur = rlim.rlim_max;
3838880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			setrlimit(RLIMIT_FSIZE, &rlim);
3848880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		}
3858880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	}
38664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
3873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*channel = io;
3883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
3893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
3903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup:
3913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data) {
392adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		free_cache(io, data);
3937b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &data);
3943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
395adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (io)
396adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		ext2fs_free_mem((void **) &io);
3973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
3983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
3993839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel)
4013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval = 0;
4043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
405f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
407f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
408a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
409a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	if (--channel->refcount > 0)
410a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		return 0;
411adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
412adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
413adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
4143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (close(data->dev) < 0)
4153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
416adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	free_cache(channel, data);
417f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o
418f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o	ext2fs_free_mem((void **) &channel->private_data);
4193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->name)
4207b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		ext2fs_free_mem((void **) &channel->name);
4217b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	ext2fs_free_mem((void **) &channel);
4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
4233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize)
4263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
4287b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
4293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
430f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
432f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
433f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
4343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->block_size != blksize) {
435adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
436adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
437adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
4383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		channel->block_size = blksize;
439adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		free_cache(channel, data);
440adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = alloc_cache(channel, data)))
4417b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
4423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
4433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
4443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
4453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4473839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
4483839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *buf)
4493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
45182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
45331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	char		*cp;
454adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		i, j;
4553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
456f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
4573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
458f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
4593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
46182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * If we're doing an odd-sized read or a very large read,
46282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * flush out the cache and then do a direct read.
4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
46482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
465adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
466adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
467adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_read_blk(channel, data, block, count, buf);
4683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
469adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
47031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
471adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
472adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* If it's in the cache, use it! */
47382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		if ((cache = find_cached_block(channel, data, block,
47482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					       &reuse[0]))) {
475adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
476adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			printf("Using cached block %d\n", block);
477f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif
47831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			memcpy(cp, cache->buf, channel->block_size);
479adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
480adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			block++;
48131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
482adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
483adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
484adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/*
485adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * Find the number of uncached blocks so we can do a
486adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * single read request
487adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 */
488adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (i=1; i < count; i++)
48982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			if (find_cached_block(channel, data, block+i,
49082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					      &reuse[i]))
491adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				break;
492adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
493adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		printf("Reading %d blocks starting at %d\n", i, block);
494adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif
49531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		if ((retval = raw_read_blk(channel, data, block, i, cp)))
496adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
497adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
498adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* Save the results in the cache */
499adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (j=0; j < i; j++) {
500adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
50182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse[j];
50282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block++);
50382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			memcpy(cache->buf, cp, channel->block_size);
50431dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
505adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
5063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
5083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
5113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *buf)
5123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
51482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse;
51523b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o	errcode_t	retval = 0;
51631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	const char	*cp;
51731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	int		writethrough;
5183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
519f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
521f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
5223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
523adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
524adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * If we're doing an odd-sized write or a very large write,
525adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * flush out the cache completely and then do a direct write.
526adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
52782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
528adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 1)))
529adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
530adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_write_blk(channel, data, block, count, buf);
5313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
533adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
534adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * For a moderate-sized multi-block write, first force a write
535adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * if we're in write-through cache mode, and then fill the
536adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * cache with the blocks.
537adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
538adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
539adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (writethrough)
540adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data, block, count, buf);
5413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
54231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
543adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
54482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		cache = find_cached_block(channel, data, block, &reuse);
545adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache) {
54682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse;
54782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block);
548adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
54982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		memcpy(cache->buf, cp, channel->block_size);
55082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		cache->dirty = !writethrough;
551adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		count--;
552adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		block++;
55331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		cp += channel->block_size;
554adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
5553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
5563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
558c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
559c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				 int size, const void *buf)
560c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{
561c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	struct unix_private_data *data;
56231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	errcode_t	retval = 0;
563c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	size_t		actual;
564c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
565c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
566c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
567c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
568c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
569c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	/*
570c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 * Flush out the cache completely
571c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 */
572c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if ((retval = flush_cached_blocks(channel, data, 1)))
573c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return retval;
574c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
575c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (lseek(data->dev, offset, SEEK_SET) < 0)
576c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return errno;
577c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
578c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	actual = write(data->dev, buf, size);
579c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (actual != size)
580c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return EXT2_ET_SHORT_WRITE;
581c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
582c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	return 0;
583c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o}
584c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
5853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
58636f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk.
5873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
5883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel)
5893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
590f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	struct unix_private_data *data;
591adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t retval = 0;
592f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
593f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
594f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
595f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
596adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
597adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
59836f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o	fsync(data->dev);
599adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
6003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
602