unix_io.c revision 59ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1
13839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
2fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * unix_io.c --- This is the Unix (well, really POSIX) implementation
3fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * 	of the I/O manager.
43839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
53839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o * Implements a one-block write-through cache.
63839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o *
7fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o * Includes support for Windows NT support under Cygwin.
8fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o *
964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
1064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o * 	2002 by Theodore Ts'o.
1119c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o *
1219c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %Begin-Header%
1319c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * This file may be redistributed under the terms of the GNU Public
1419c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * License.
1519c78dc07fce2d6f39b5e541562afc3ca1ea38ffTheodore Ts'o * %End-Header%
163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
18dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE_SOURCE
19dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#define _LARGEFILE64_SOURCE
20dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o
213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <stdio.h>
223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <string.h>
234cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#if HAVE_UNISTD_H
243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <unistd.h>
254cbe8af4b0d0c72fb28bb500c1bd8a46b00fdde3Theodore Ts'o#endif
26c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#if HAVE_ERRNO_H
27c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#include <errno.h>
28c4e749abd8451f02418fe552b2af14f226f7bd1eTheodore Ts'o#endif
293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <fcntl.h>
303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <time.h>
31f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
32f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#include <sys/utsname.h>
33f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
341d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H
353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h>
361d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
371d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H
383839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h>
391d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
40fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#if HAVE_SYS_RESOURCE_H
418880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o#include <sys/resource.h>
42fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
44b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
457b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include "ext2fs.h"
463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
47f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o/*
48f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * For checking structure magic numbers...
49f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o */
50f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
51f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#define EXT2_CHECK_MAGIC(struct, code) \
52f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	  if ((struct)->magic != (code)) return (code)
53adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
54adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostruct unix_cache {
55adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	char		*buf;
56adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	unsigned long	block;
57adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		access_time;
5883e692e88bf2d01edb089010bdfc07b7dcc78642Matthias Andree	unsigned	dirty:1;
5983e692e88bf2d01edb089010bdfc07b7dcc78642Matthias Andree	unsigned	in_use:1;
60adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o};
61adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
62adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define CACHE_SIZE 8
6382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define WRITE_DIRECT_SIZE 4	/* Must be smaller than CACHE_SIZE */
6482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define READ_DIRECT_SIZE 4	/* Should be smaller than CACHE_SIZE */
65adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data {
67f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	int	magic;
683839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	dev;
693839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	flags;
70adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int	access_time;
712e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	ext2_loff_t offset;
72adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache cache[CACHE_SIZE];
736d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	struct struct_io_stats io_stats;
743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel);
773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel);
783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize);
793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *data);
813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *data);
833839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel);
84c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
85c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				int size, const void *data);
862e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'ostatic errcode_t unix_set_option(io_channel channel, const char *option,
872e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o				 const char *arg);
886d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'ostatic errcode_t unix_get_stats(io_channel channel, io_stats *stats)
896d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o;
9023b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
9159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos		 struct unix_cache *cache, unsigned long long block);
9259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
9359ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			       int count, void *data);
9459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
9559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos				int count, const void *data);
9623b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o
97289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree/* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel
98289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree * does not know buffered block devices - everything is raw. */
99289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
100b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#define NEED_BOUNCE_BUFFER
101b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#else
102b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#undef NEED_BOUNCE_BUFFER
103b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#endif
104b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree
105f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = {
106f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_ET_MAGIC_IO_MANAGER,
1073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	"Unix I/O Manager",
1083839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_open,
1093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_close,
1103839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_set_blksize,
1113839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_read_blk,
1123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_write_blk,
113c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_flush,
114b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#ifdef NEED_BOUNCE_BUFFER
1152e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	0,
116fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#else
1172e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	unix_write_byte,
118fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
1196d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	unix_set_option,
1206d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	unix_get_stats,
12159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	unix_read_blk64,
12259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	unix_write_blk64,
1233839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
1243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager;
1263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1276d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'ostatic errcode_t unix_get_stats(io_channel channel, io_stats *stats)
1286d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o{
1296d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	errcode_t 	retval = 0;
1306d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1316d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	struct unix_private_data *data;
1326d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1336d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1346d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
1356d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1366d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1376d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	if (stats)
1386d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o		*stats = &data->io_stats;
1396d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1406d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	return retval;
1416d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o}
1426d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
143adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
144adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions
145adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
146b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#ifndef NEED_BOUNCE_BUFFER
147adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
148adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      struct unix_private_data *data,
14959ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			      unsigned long long block,
150adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      int count, void *buf)
151adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
152adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
153544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		size;
154adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
155adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
156adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
157adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
1586d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data->io_stats.bytes_read += size;
1592e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
160adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
161adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
162adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
163adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
164adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = read(data->dev, buf, size);
165adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
166adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (actual < 0)
167adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			actual = 0;
168adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_READ;
169adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
170adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
171adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
172adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
173adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
174adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	memset((char *) buf+actual, 0, size-actual);
175adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->read_error)
176adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
177adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o					       size, actual, retval);
178adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
179adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
180b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#else /* NEED_BOUNCE_BUFFER */
181fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o/*
182b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree * Windows and FreeBSD block devices only allow sector alignment IO in offset and size
183fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o */
184fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
185fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      struct unix_private_data *data,
186fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      unsigned long block,
187fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      int count, void *buf)
188fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o{
189fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	errcode_t	retval;
190fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	size_t		size, alignsize, fragment;
191fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	ext2_loff_t	location;
192fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	int		total = 0, actual;
193fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#define BLOCKALIGN 512
194fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	char		sector[BLOCKALIGN];
195fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
196fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
1976d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data->io_stats.bytes_read += size;
1982e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
199fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#ifdef DEBUG
200d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen	printf("count=%d, size=%d, block=%lu, blk_size=%d, location=%llx\n",
201d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen	 		count, size, block, channel->block_size, (long long)location);
202fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
203fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
204fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
205fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		goto error_out;
206fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
207fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	fragment = size % BLOCKALIGN;
208fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	alignsize = size - fragment;
209fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (alignsize) {
210fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		actual = read(data->dev, buf, alignsize);
211fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		if (actual != alignsize)
212fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			goto short_read;
213fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
214fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (fragment) {
215fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		actual = read(data->dev, sector, BLOCKALIGN);
216fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		if (actual != BLOCKALIGN)
217fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			goto short_read;
218fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		memcpy(buf+alignsize, sector, fragment);
219fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
220fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	return 0;
221fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
222fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oshort_read:
223fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (actual>0)
224fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		total += actual;
225fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	retval = EXT2_ET_SHORT_READ;
226fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
227fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oerror_out:
228fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	memset((char *) buf+total, 0, size-actual);
229fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (channel->read_error)
230fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
231fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o					       size, actual, retval);
232fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	return retval;
233fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o}
234fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
235adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
236adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel,
237adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       struct unix_private_data *data,
23859ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			       unsigned long long block,
239adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       int count, const void *buf)
240adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
241544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		size;
242adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
243adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
244adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
245adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
246adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (count == 1)
247adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		size = channel->block_size;
248adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	else {
249adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (count < 0)
250adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = -count;
251adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
252adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = count * channel->block_size;
253adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
2546d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data->io_stats.bytes_written += size;
255adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
2562e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
257adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
258adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
260adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = write(data->dev, buf, size);
263adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
264adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_WRITE;
265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
266adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
268adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->write_error)
271adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->write_error)(channel, block, count, buf,
272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o						size, actual, retval);
273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
275adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
276adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
278adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions
279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
280adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
281adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */
282adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel,
283adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			     struct unix_private_data *data)
284adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
285adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval;
286adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
287adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
290adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
292adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
295adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = ext2fs_get_mem(channel->block_size,
296c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o					     &cache->buf)))
297adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
298adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
299adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
300adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
301adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
302adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */
303544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic void free_cache(struct unix_private_data *data)
304adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
305adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
306adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
307adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
308adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
309adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
310adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
311adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
312adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
313adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
314adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->buf)
315c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o			ext2fs_free_mem(&cache->buf);
316adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->buf = 0;
317adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
318adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
319adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
320b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
321adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
32282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Try to find a block in the cache.  If the block is not found, and
32382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * eldest is a non-zero pointer, then fill in eldest with the cache
32482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * entry to that should be reused.
325adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
326544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic struct unix_cache *find_cached_block(struct unix_private_data *data,
32759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos					    unsigned long long block,
32882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					    struct unix_cache **eldest)
329adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
33031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	struct unix_cache	*cache, *unused_cache, *oldest_cache;
331adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
332adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
33331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	unused_cache = oldest_cache = 0;
334adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
335adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use) {
33682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			if (!unused_cache)
33782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o				unused_cache = cache;
338adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
339adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
340adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->block == block) {
341adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->access_time = ++data->access_time;
342adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return cache;
343adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
344adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!oldest_cache ||
345adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		    (cache->access_time < oldest_cache->access_time))
346adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			oldest_cache = cache;
347adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
34882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (eldest)
34982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		*eldest = (unused_cache) ? unused_cache : oldest_cache;
35082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	return 0;
35182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o}
35282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
35382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o/*
35482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Reuse a particular cache entry for another block.
35582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o */
35623b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
35759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos		 struct unix_cache *cache, unsigned long long block)
35882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o{
35982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (cache->dirty && cache->in_use)
36082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		raw_write_blk(channel, data, cache->block, 1, cache->buf);
36182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
362adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->in_use = 1;
3631d47dfb91ef010c506e9354dec102385d8494d8fTheodore Ts'o	cache->dirty = 0;
364adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->block = block;
365adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->access_time = ++data->access_time;
366adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
367adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
368adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
369adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache
370adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
371adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel,
372adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     struct unix_private_data *data,
373adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     int invalidate)
374adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
375adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
376adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
377adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval, retval2;
378adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
379adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
380adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval2 = 0;
381adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
382adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use)
383adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
384adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
385adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (invalidate)
386adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->in_use = 0;
387adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
388adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->dirty)
389adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
390adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
391adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data,
392adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				       cache->block, 1, cache->buf);
393adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (retval)
394adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			retval2 = retval;
395adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
396adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->dirty = 0;
397adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
398adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval2;
399adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
400b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
401adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
4023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel)
4033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io_channel	io = NULL;
4053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data = NULL;
4063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
407dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	int		open_flags;
4088880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	struct stat	st;
409f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
410f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	struct 		utsname ut;
411f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
4123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
41350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (name == 0)
41450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return EXT2_ET_BAD_DEVICE_NAME;
415c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
4167b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
4177b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		return retval;
418f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	memset(io, 0, sizeof(struct struct_io_channel));
419f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
420c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
4217b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
4237b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
4243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->manager = unix_io_manager;
425c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
4267b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
4273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
4287b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
4293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	strcpy(io->name, name);
4303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->private_data = data;
431f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->block_size = 1024;
432f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->read_error = 0;
433f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->write_error = 0;
434a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	io->refcount = 1;
4353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(data, 0, sizeof(struct unix_private_data));
437f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
4386d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data->io_stats.num_fields = 2;
4397b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
440adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if ((retval = alloc_cache(io, data)))
441adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto cleanup;
4422e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
443dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
444fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4aTheodore Ts'o	if (flags & IO_FLAG_EXCLUSIVE)
445fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4aTheodore Ts'o		open_flags |= O_EXCL;
446dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64
4472e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	data->dev = open64(io->name, open_flags);
448dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else
4492e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	data->dev = open(io->name, open_flags);
450dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif
4513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data->dev < 0) {
4523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
4533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
4543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
45564e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o
45664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__
45764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY
45864e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
45964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY	((unsigned long)(~0UL>>1))
46064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else
46164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY  (~0UL)
46264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
4638880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	/*
464f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
465f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * block devices are wrongly getting hit by the filesize
466f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * limit.  This workaround isn't perfect, since it won't work
467f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * if glibc wasn't built against 2.2 header files.  (Sigh.)
468f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 *
4698880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	 */
470f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	if ((flags & IO_FLAG_RW) &&
471f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    (uname(&ut) == 0) &&
472f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    ((ut.release[0] == '2') && (ut.release[1] == '.') &&
473f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[2] == '4') && (ut.release[3] == '.') &&
474f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[4] == '1') && (ut.release[5] >= '0') &&
475f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[5] < '8')) &&
4768880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (fstat(data->dev, &st) == 0) &&
4778880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (S_ISBLK(st.st_mode))) {
4788880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		struct rlimit	rlim;
4798880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o
48064e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o		rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
4818880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		setrlimit(RLIMIT_FSIZE, &rlim);
4828880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		getrlimit(RLIMIT_FSIZE, &rlim);
483bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		if (((unsigned long) rlim.rlim_cur) <
484bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		    ((unsigned long) rlim.rlim_max)) {
4858880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			rlim.rlim_cur = rlim.rlim_max;
4868880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			setrlimit(RLIMIT_FSIZE, &rlim);
4878880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		}
4888880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	}
48964e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
4903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*channel = io;
4913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
4923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup:
4943839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data) {
495544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		free_cache(data);
496c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&data);
4973839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
498adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (io)
499c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&io);
5003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
5013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5023839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel)
5043839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5053839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
5063839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval = 0;
5073839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
508f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5093839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
510f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
511a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
512a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	if (--channel->refcount > 0)
513a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		return 0;
514adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
515b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
516adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
517b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
518adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
5193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (close(data->dev) < 0)
5203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
521544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	free_cache(data);
522f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o
523c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&channel->private_data);
5243839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->name)
525c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&channel->name);
526c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&channel);
5273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
5283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize)
5313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
5337b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
5343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
535f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
537f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
538f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
5393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->block_size != blksize) {
540b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
541adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
542adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
543b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
544adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
5453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		channel->block_size = blksize;
546544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		free_cache(data);
547adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = alloc_cache(channel, data)))
5487b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
5493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
5513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
55459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
5553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *buf)
5563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
55882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
5593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
56031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	char		*cp;
561adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		i, j;
5623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
563f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
565f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
5663839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
567b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE
568b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o	return raw_read_blk(channel, data, block, count, buf);
569b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#else
5703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
57182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * If we're doing an odd-sized read or a very large read,
57282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * flush out the cache and then do a direct read.
5733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
57482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
575adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
576adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
577adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_read_blk(channel, data, block, count, buf);
5783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
579adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
58031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
581adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
582adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* If it's in the cache, use it! */
583544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		if ((cache = find_cached_block(data, block, &reuse[0]))) {
584adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
585d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen			printf("Using cached block %lu\n", block);
586f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif
58731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			memcpy(cp, cache->buf, channel->block_size);
588adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
589adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			block++;
59031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
591adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
592adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
593adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/*
594adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * Find the number of uncached blocks so we can do a
595adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * single read request
596adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 */
597adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (i=1; i < count; i++)
598544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			if (find_cached_block(data, block+i, &reuse[i]))
599adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				break;
600adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
601d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen		printf("Reading %d blocks starting at %lu\n", i, block);
602adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif
60331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		if ((retval = raw_read_blk(channel, data, block, i, cp)))
604adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
605adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
606adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* Save the results in the cache */
607adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (j=0; j < i; j++) {
608adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
60982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse[j];
61082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block++);
61182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			memcpy(cache->buf, cp, channel->block_size);
61231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
613adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
6143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
616b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
6173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
61959ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
62059ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			       int count, void *buf)
62159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos{
62259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	return unix_read_blk64(channel, block, count, buf);
62359ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos}
62459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos
62559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
6263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *buf)
6273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
6283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
62982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse;
63023b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o	errcode_t	retval = 0;
63131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	const char	*cp;
63231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	int		writethrough;
6333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
634f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
6353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
636f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
6373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
638b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE
639b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o	return raw_write_blk(channel, data, block, count, buf);
640b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#else
641adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
642adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * If we're doing an odd-sized write or a very large write,
643adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * flush out the cache completely and then do a direct write.
644adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
64582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
646adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 1)))
647adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
648adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_write_blk(channel, data, block, count, buf);
6493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6503839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
651adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
652adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * For a moderate-sized multi-block write, first force a write
653adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * if we're in write-through cache mode, and then fill the
654adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * cache with the blocks.
655adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
656adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
657adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (writethrough)
658adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data, block, count, buf);
6593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
66031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
661adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
662544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		cache = find_cached_block(data, block, &reuse);
663adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache) {
66482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse;
66582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block);
666adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
66782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		memcpy(cache->buf, cp, channel->block_size);
66882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		cache->dirty = !writethrough;
669adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		count--;
670adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		block++;
67131dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		cp += channel->block_size;
672adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
6733839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
674b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
6753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
67759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
67859ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos				int count, const void *buf)
67959ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos{
68059ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	return unix_write_blk64(channel, block, count, buf);
68159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos}
68259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos
683c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
684c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				 int size, const void *buf)
685c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{
686c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	struct unix_private_data *data;
68731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	errcode_t	retval = 0;
688544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		actual;
689c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
690c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
691c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
692c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
693c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
694b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
695c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	/*
696c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 * Flush out the cache completely
697c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 */
698c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if ((retval = flush_cached_blocks(channel, data, 1)))
699c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return retval;
700b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
701c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
7022e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
703c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return errno;
704c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
705c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	actual = write(data->dev, buf, size);
706c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (actual != size)
707c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return EXT2_ET_SHORT_WRITE;
708c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
709c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	return 0;
710c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o}
711c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
7123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
71336f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o * Flush data buffers to disk.
7143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
7153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel)
7163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
717f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	struct unix_private_data *data;
718adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t retval = 0;
719f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
720f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
721f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
722f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
723adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
724b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
725adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
726b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
72736f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o	fsync(data->dev);
728adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
7293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
7303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
7312e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'ostatic errcode_t unix_set_option(io_channel channel, const char *option,
7322e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o				 const char *arg)
7332e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o{
7342e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	struct unix_private_data *data;
7352aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o	unsigned long long tmp;
7362e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	char *end;
7372e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
7382e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
7392e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
7402e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
7412e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
7422e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	if (!strcmp(option, "offset")) {
7432e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		if (!arg)
7442e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o			return EXT2_ET_INVALID_ARGUMENT;
7452e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
7462aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o		tmp = strtoull(arg, &end, 0);
7472e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		if (*end)
7482e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o			return EXT2_ET_INVALID_ARGUMENT;
7492e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		data->offset = tmp;
7502aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o		if (data->offset < 0)
7512aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o			return EXT2_ET_INVALID_ARGUMENT;
7522e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		return 0;
7532e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	}
7542e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	return EXT2_ET_INVALID_ARGUMENT;
7552e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o}
756