unix_io.c revision 543547a52a20cb7e69d74921b2f691078fd55d83
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 *
7efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore 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%
13543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * This file may be redistributed under the terms of the GNU Library
14543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * General Public License, version 2.
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
347ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#ifdef HAVE_SYS_IOCTL_H
357ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#include <sys/ioctl.h>
367ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif
377ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#ifdef HAVE_SYS_MOUNT_H
387ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#include <sys/mount.h>
397ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif
401d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_STAT_H
413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/stat.h>
421d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
431d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#if HAVE_SYS_TYPES_H
443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o#include <sys/types.h>
451d2ff46ae7533ffd038534b189f272d2a4122e4eTheodore Ts'o#endif
46fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#if HAVE_SYS_RESOURCE_H
478880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o#include <sys/resource.h>
48fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
507ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
517ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#define BLKROGET   _IO(0x12, 94) /* Get read-only status (0 = read_write).  */
527ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif
537ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen
54b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
557b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o#include "ext2fs.h"
563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
57f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o/*
58f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o * For checking structure magic numbers...
59f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o */
60f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
61f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#define EXT2_CHECK_MAGIC(struct, code) \
62f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	  if ((struct)->magic != (code)) return (code)
63adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
64adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostruct unix_cache {
65adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	char		*buf;
66adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	unsigned long	block;
67adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		access_time;
6883e692e88bf2d01edb089010bdfc07b7dcc78642Matthias Andree	unsigned	dirty:1;
6983e692e88bf2d01edb089010bdfc07b7dcc78642Matthias Andree	unsigned	in_use:1;
70adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o};
71adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
72adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#define CACHE_SIZE 8
7382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define WRITE_DIRECT_SIZE 4	/* Must be smaller than CACHE_SIZE */
7482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o#define READ_DIRECT_SIZE 4	/* Should be smaller than CACHE_SIZE */
75adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostruct unix_private_data {
77f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	int	magic;
783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	dev;
793839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	int	flags;
80adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int	access_time;
812e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	ext2_loff_t offset;
82adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache cache[CACHE_SIZE];
836d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	struct struct_io_stats io_stats;
843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
853839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
863839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel);
873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel);
883839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize);
893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
903839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *data);
913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
923839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *data);
933839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel);
94c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
95c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				int size, const void *data);
96efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'ostatic errcode_t unix_set_option(io_channel channel, const char *option,
972e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o				 const char *arg);
986d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'ostatic errcode_t unix_get_stats(io_channel channel, io_stats *stats)
996d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o;
10023b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
10159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos		 struct unix_cache *cache, unsigned long long block);
10259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
10359ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			       int count, void *data);
10459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
10559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos				int count, const void *data);
10623b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o
107289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree/* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel
108289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree * does not know buffered block devices - everything is raw. */
109289e0557c24c68290b6d9b73b09674447801fdacMatthias Andree#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
110b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#define NEED_BOUNCE_BUFFER
111b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#else
112b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#undef NEED_BOUNCE_BUFFER
113b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#endif
114b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree
115f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'ostatic struct struct_io_manager struct_unix_manager = {
116f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_ET_MAGIC_IO_MANAGER,
1173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	"Unix I/O Manager",
1183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_open,
1193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_close,
1203839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_set_blksize,
1213839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_read_blk,
1223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	unix_write_blk,
123c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	unix_flush,
124b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#ifdef NEED_BOUNCE_BUFFER
1252e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	0,
126fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#else
1272e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	unix_write_byte,
128fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
1296d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	unix_set_option,
1306d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	unix_get_stats,
13159ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	unix_read_blk64,
13259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	unix_write_blk64,
1333839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o};
1343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1353839e65723771b85975f4263102dd3ceec4523cTheodore Ts'oio_manager unix_io_manager = &struct_unix_manager;
1363839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
1376d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'ostatic errcode_t unix_get_stats(io_channel channel, io_stats *stats)
1386d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o{
1396d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	errcode_t 	retval = 0;
1406d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1416d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	struct unix_private_data *data;
1426d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1436d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
1446d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
1456d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
1466d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1476d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	if (stats)
1486d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o		*stats = &data->io_stats;
1496d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
1506d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	return retval;
1516d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o}
1526d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o
153adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
154adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here are the raw I/O functions
155adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
156b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#ifndef NEED_BOUNCE_BUFFER
157adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
158adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      struct unix_private_data *data,
15959ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			      unsigned long long block,
160adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			      int count, void *buf)
161adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
162adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
163544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		size;
164adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
165adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
166adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
167adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
1686d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data->io_stats.bytes_read += size;
1692e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
170adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
171adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
172adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
173adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
174adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = read(data->dev, buf, size);
175adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
176adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (actual < 0)
177adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			actual = 0;
178adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_READ;
179adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
180adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
181adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
182efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
183adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
184adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	memset((char *) buf+actual, 0, size-actual);
185adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->read_error)
186adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
187adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o					       size, actual, retval);
188adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
189adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
190b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree#else /* NEED_BOUNCE_BUFFER */
191fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o/*
192b34cbddbd66baedc163d36dd281b63ef478f547aMatthias Andree * Windows and FreeBSD block devices only allow sector alignment IO in offset and size
193fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o */
194fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'ostatic errcode_t raw_read_blk(io_channel channel,
195fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      struct unix_private_data *data,
196fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      unsigned long block,
197fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			      int count, void *buf)
198fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o{
199fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	errcode_t	retval;
200fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	size_t		size, alignsize, fragment;
201fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	ext2_loff_t	location;
202fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	int		total = 0, actual;
203fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#define BLOCKALIGN 512
204fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	char		sector[BLOCKALIGN];
205fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
206fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	size = (count < 0) ? -count : count * channel->block_size;
2076d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data->io_stats.bytes_read += size;
2082e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
209fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#ifdef DEBUG
210d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen	printf("count=%d, size=%d, block=%lu, blk_size=%d, location=%llx\n",
211d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen	 		count, size, block, channel->block_size, (long long)location);
212fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
213fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
214fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
215fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		goto error_out;
216fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
217fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	fragment = size % BLOCKALIGN;
218fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	alignsize = size - fragment;
219fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (alignsize) {
220fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		actual = read(data->dev, buf, alignsize);
221fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		if (actual != alignsize)
222fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			goto short_read;
223fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
224fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (fragment) {
225fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		actual = read(data->dev, sector, BLOCKALIGN);
226fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		if (actual != BLOCKALIGN)
227fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o			goto short_read;
228fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		memcpy(buf+alignsize, sector, fragment);
229fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	}
230fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	return 0;
231fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
232fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oshort_read:
233fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (actual>0)
234fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		total += actual;
235fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	retval = EXT2_ET_SHORT_READ;
236fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o
237fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'oerror_out:
238fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	memset((char *) buf+total, 0, size-actual);
239fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	if (channel->read_error)
240fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o		retval = (channel->read_error)(channel, block, count, buf,
241fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o					       size, actual, retval);
242fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o	return retval;
243fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o}
244fff45483ede7fe38a31b3364a9c07e2418776deeTheodore Ts'o#endif
245adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
246adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t raw_write_blk(io_channel channel,
247adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       struct unix_private_data *data,
24859ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			       unsigned long long block,
249adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			       int count, const void *buf)
250adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
251544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		size;
252adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	ext2_loff_t	location;
253adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		actual = 0;
254adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t	retval;
255adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
256adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (count == 1)
257adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		size = channel->block_size;
258adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	else {
259adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (count < 0)
260adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = -count;
261adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
262adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			size = count * channel->block_size;
263adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
2646d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data->io_stats.bytes_written += size;
265adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
2662e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
267adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
268adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
269adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
270adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
271efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
272adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	actual = write(data->dev, buf, size);
273adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (actual != size) {
274adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = EXT2_ET_SHORT_WRITE;
275adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto error_out;
276adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
277adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
278efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
279adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'oerror_out:
280adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (channel->write_error)
281adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = (channel->write_error)(channel, block, count, buf,
282adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o						size, actual, retval);
283adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
284adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
285adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
286adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
287adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
288adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Here we implement the cache functions
289adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
290adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
291adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Allocate the cache buffers */
292adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t alloc_cache(io_channel channel,
293adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			     struct unix_private_data *data)
294adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
295adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval;
296adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
297adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
298efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
299adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
300adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
301adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
302adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
303adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
304adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
305adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = ext2fs_get_mem(channel->block_size,
306c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o					     &cache->buf)))
307adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
308adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
309adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return 0;
310adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
311adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
312adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/* Free the cache buffers */
313544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic void free_cache(struct unix_private_data *data)
314adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
315adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
316adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
317efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
318adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	data->access_time = 0;
319adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
320adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->block = 0;
321adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->access_time = 0;
322adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->dirty = 0;
323adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->in_use = 0;
324adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->buf)
325c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o			ext2fs_free_mem(&cache->buf);
326adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		cache->buf = 0;
327adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
328adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
329adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
330b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
331adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
33282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Try to find a block in the cache.  If the block is not found, and
33382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * eldest is a non-zero pointer, then fill in eldest with the cache
33482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * entry to that should be reused.
335adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
336544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'ostatic struct unix_cache *find_cached_block(struct unix_private_data *data,
33759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos					    unsigned long long block,
33882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o					    struct unix_cache **eldest)
339adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
34031dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	struct unix_cache	*cache, *unused_cache, *oldest_cache;
341adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
342efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
34331dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	unused_cache = oldest_cache = 0;
344adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
345adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use) {
34682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			if (!unused_cache)
34782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o				unused_cache = cache;
348adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
349adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
350adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (cache->block == block) {
351adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->access_time = ++data->access_time;
352adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return cache;
353adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
354adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!oldest_cache ||
355adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		    (cache->access_time < oldest_cache->access_time))
356adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			oldest_cache = cache;
357adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
35882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (eldest)
35982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		*eldest = (unused_cache) ? unused_cache : oldest_cache;
36082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	return 0;
36182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o}
36282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
36382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o/*
36482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o * Reuse a particular cache entry for another block.
36582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o */
36623b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'ostatic void reuse_cache(io_channel channel, struct unix_private_data *data,
36759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos		 struct unix_cache *cache, unsigned long long block)
36882c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o{
36982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (cache->dirty && cache->in_use)
37082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		raw_write_blk(channel, data, cache->block, 1, cache->buf);
37182c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o
372adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->in_use = 1;
3731d47dfb91ef010c506e9354dec102385d8494d8fTheodore Ts'o	cache->dirty = 0;
374adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->block = block;
375adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	cache->access_time = ++data->access_time;
376adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
377adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
378adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o/*
379adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o * Flush all of the blocks in the cache
380adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o */
381adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'ostatic errcode_t flush_cached_blocks(io_channel channel,
382adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     struct unix_private_data *data,
383adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				     int invalidate)
384adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
385adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o{
386adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	struct unix_cache	*cache;
387adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t		retval, retval2;
388adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int			i;
389efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
390adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval2 = 0;
391adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
392adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->in_use)
393adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
394efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
395adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (invalidate)
396adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->in_use = 0;
397efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
398adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache->dirty)
399adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
400efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
401adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data,
402adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				       cache->block, 1, cache->buf);
403adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (retval)
404adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			retval2 = retval;
405adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		else
406adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			cache->dirty = 0;
407adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
408adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval2;
409adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o}
410b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
411adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
4123839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_open(const char *name, int flags, io_channel *channel)
4133839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
4143839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io_channel	io = NULL;
4153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data = NULL;
4163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
417dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	int		open_flags;
4188880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	struct stat	st;
419f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#ifdef __linux__
420f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	struct 		utsname ut;
421f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o#endif
4223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
42350e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o	if (name == 0)
42450e1e10fa0ac12a3e2a9d20a75ee9041873cda96Theodore Ts'o		return EXT2_ET_BAD_DEVICE_NAME;
425c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
4267b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
4277b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		return retval;
428f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	memset(io, 0, sizeof(struct struct_io_channel));
429f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
430c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
4317b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
4323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
4337b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
4343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->manager = unix_io_manager;
435c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
4367b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	if (retval)
4373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
4387b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
4393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	strcpy(io->name, name);
4403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	io->private_data = data;
441f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->block_size = 1024;
442f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->read_error = 0;
443f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	io->write_error = 0;
444a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	io->refcount = 1;
4453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
4463839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	memset(data, 0, sizeof(struct unix_private_data));
447f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
4486d96b00d57d236e2746f8245df6c8ea64abc64c1Theodore Ts'o	data->io_stats.num_fields = 2;
4497b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o
450adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if ((retval = alloc_cache(io, data)))
451adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		goto cleanup;
4522e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
453dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o	open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
454fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4aTheodore Ts'o	if (flags & IO_FLAG_EXCLUSIVE)
455fa6c653ec3117dd689c8adb4ea2ebfc10f8cdd4aTheodore Ts'o		open_flags |= O_EXCL;
456dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#ifdef HAVE_OPEN64
4572e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	data->dev = open64(io->name, open_flags);
458dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#else
4592e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	data->dev = open(io->name, open_flags);
460dc5f68cad3c8ee4c583acf9afbfdb7354cd3d6afTheodore Ts'o#endif
4613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data->dev < 0) {
4623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
4633839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		goto cleanup;
4643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
46564e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o
4667ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#ifdef BLKROGET
4677ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen	if (flags & IO_FLAG_RW) {
4687ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		int error;
4697ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		int readonly = 0;
4707ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen
4717ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		/* Is the block device actually writable? */
4727ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		error = ioctl(data->dev, BLKROGET, &readonly);
4737ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		if (!error && readonly) {
4747ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen			close(data->dev);
4757ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen			retval = EPERM;
4767ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen			goto cleanup;
4777ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen		}
4787ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen	}
4797ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen#endif
4807ed7a4b6ed8b2fce891874a0eafdc8f77c3ffc34Eric Sandeen
48164e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#ifdef __linux__
48264e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#undef RLIM_INFINITY
48364e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
48464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY	((unsigned long)(~0UL>>1))
48564e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#else
48664e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#define RLIM_INFINITY  (~0UL)
48764e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
4888880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	/*
489f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
490f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * block devices are wrongly getting hit by the filesize
491f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * limit.  This workaround isn't perfect, since it won't work
492f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	 * if glibc wasn't built against 2.2 header files.  (Sigh.)
493efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	 *
4948880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	 */
495f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	if ((flags & IO_FLAG_RW) &&
496f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    (uname(&ut) == 0) &&
497f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	    ((ut.release[0] == '2') && (ut.release[1] == '.') &&
498f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[2] == '4') && (ut.release[3] == '.') &&
499f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[4] == '1') && (ut.release[5] >= '0') &&
500f154d2f687e922f8444ef3050dc83f5d8e0e2178Theodore Ts'o	     (ut.release[5] < '8')) &&
5018880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (fstat(data->dev, &st) == 0) &&
5028880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	    (S_ISBLK(st.st_mode))) {
5038880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		struct rlimit	rlim;
504efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
50564e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o		rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
5068880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		setrlimit(RLIMIT_FSIZE, &rlim);
5078880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		getrlimit(RLIMIT_FSIZE, &rlim);
508bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		if (((unsigned long) rlim.rlim_cur) <
509bd27880b4ba42544f30a08ac3b6ba86190da021bTheodore Ts'o		    ((unsigned long) rlim.rlim_max)) {
5108880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			rlim.rlim_cur = rlim.rlim_max;
5118880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o			setrlimit(RLIMIT_FSIZE, &rlim);
5128880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o		}
5138880e7599ced6d047626dd45665b765d0f5eded5Theodore Ts'o	}
51464e1b274edc48553c76511ff9b30f85c52aff046Theodore Ts'o#endif
5153839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	*channel = io;
5163839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
5173839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5183839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ocleanup:
5193839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (data) {
520544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		free_cache(data);
521c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&data);
5223839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
523adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (io)
524c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&io);
5253839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
5263839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5273839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5283839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_close(io_channel channel)
5293839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5303839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
5313839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval = 0;
5323839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
533f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5343839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
535f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
536a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o
537a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o	if (--channel->refcount > 0)
538a29f4d30f24d68f1f1c75548e020689ede532c05Theodore Ts'o		return 0;
539adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
540b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
541adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
542b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
543adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
5443839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (close(data->dev) < 0)
5453839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		retval = errno;
546544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	free_cache(data);
547f12e285ffd9ff0b37c4f91d5ab2b021ed1eb43beTheodore Ts'o
548c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&channel->private_data);
5493839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->name)
550c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&channel->name);
551c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o	ext2fs_free_mem(&channel);
5523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
5533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_set_blksize(io_channel channel, int blksize)
5563839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5573839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
5587b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o	errcode_t		retval;
5593839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
560f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5613839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
562f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
563f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o
5643839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	if (channel->block_size != blksize) {
565b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
566adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
567adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
568b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
569efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
5703839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o		channel->block_size = blksize;
571544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		free_cache(data);
572adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = alloc_cache(channel, data)))
5737b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
5743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
5753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
5763839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
5773839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
5783839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
57959ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
5803839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o			       int count, void *buf)
5813839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
5823839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
58382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
5843839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	errcode_t	retval;
58531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	char		*cp;
586adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	int		i, j;
5873839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
588f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
5893839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
590f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
5913839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
592b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE
593b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o	return raw_read_blk(channel, data, block, count, buf);
594b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#else
5953839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	/*
59682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * If we're doing an odd-sized read or a very large read,
59782c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	 * flush out the cache and then do a direct read.
5983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	 */
59982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
600adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 0)))
601adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
602adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_read_blk(channel, data, block, count, buf);
6033839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
604adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
60531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
606adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
607adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* If it's in the cache, use it! */
608544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		if ((cache = find_cached_block(data, block, &reuse[0]))) {
609adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
610d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen			printf("Using cached block %lu\n", block);
611f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o#endif
61231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			memcpy(cp, cache->buf, channel->block_size);
613adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
614adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			block++;
61531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
616adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			continue;
617adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
618adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/*
619adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * Find the number of uncached blocks so we can do a
620adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 * single read request
621adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		 */
622adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (i=1; i < count; i++)
623544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o			if (find_cached_block(data, block+i, &reuse[i]))
624adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o				break;
625adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#ifdef DEBUG
626d0ff90d5202428583c78a60c3042e7b60d88bc45Eric Sandeen		printf("Reading %d blocks starting at %lu\n", i, block);
627adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o#endif
62831dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		if ((retval = raw_read_blk(channel, data, block, i, cp)))
629adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
630efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
631adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		/* Save the results in the cache */
632adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		for (j=0; j < i; j++) {
633adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			count--;
63482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse[j];
63582c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block++);
63682c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			memcpy(cache->buf, cp, channel->block_size);
63731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o			cp += channel->block_size;
638adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
6393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return 0;
641b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
6423839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
6433839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
64459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_read_blk(io_channel channel, unsigned long block,
64559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos			       int count, void *buf)
64659ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos{
64759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	return unix_read_blk64(channel, block, count, buf);
64859ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos}
64959ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos
65059ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
6513839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o				int count, const void *buf)
6523839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
6533839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	struct unix_private_data *data;
65482c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	struct unix_cache *cache, *reuse;
65523b7c8b88673248b1f93abc717943867ad037bb4Theodore Ts'o	errcode_t	retval = 0;
65631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	const char	*cp;
65731dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	int		writethrough;
6583839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
659f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
6603839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
661f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
6623839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
663b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifdef NO_IO_CACHE
664b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o	return raw_write_blk(channel, data, block, count, buf);
665efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o#else
666adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
667adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * If we're doing an odd-sized write or a very large write,
668adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * flush out the cache completely and then do a direct write.
669adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
67082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o	if (count < 0 || count > WRITE_DIRECT_SIZE) {
671adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if ((retval = flush_cached_blocks(channel, data, 1)))
672adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o			return retval;
673adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		return raw_write_blk(channel, data, block, count, buf);
6743839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	}
6753839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
676adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	/*
677adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * For a moderate-sized multi-block write, first force a write
678adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * if we're in write-through cache mode, and then fill the
679adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 * cache with the blocks.
680adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	 */
681adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
682adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	if (writethrough)
683adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		retval = raw_write_blk(channel, data, block, count, buf);
684efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
68531dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	cp = buf;
686adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	while (count > 0) {
687544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o		cache = find_cached_block(data, block, &reuse);
688adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		if (!cache) {
68982c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			cache = reuse;
69082c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o			reuse_cache(channel, data, cache, block);
691adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		}
69282c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		memcpy(cache->buf, cp, channel->block_size);
69382c4660c756fba5eae289e6fbf03fab55393e3e2Theodore Ts'o		cache->dirty = !writethrough;
694adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		count--;
695adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o		block++;
69631dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o		cp += channel->block_size;
697adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	}
6983839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o	return retval;
699b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif /* NO_IO_CACHE */
7003839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
7013839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
70259ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santosstatic errcode_t unix_write_blk(io_channel channel, unsigned long block,
70359ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos				int count, const void *buf)
70459ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos{
70559ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos	return unix_write_blk64(channel, block, count, buf);
70659ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos}
70759ecd32dcb1d890bd52444c7cdeaabf8d9b2dbd1Jose R. Santos
708c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'ostatic errcode_t unix_write_byte(io_channel channel, unsigned long offset,
709c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o				 int size, const void *buf)
710c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o{
711c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	struct unix_private_data *data;
71231dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'o	errcode_t	retval = 0;
713544349270e4c74a6feb971123884a8cf5052a7eeTheodore Ts'o	ssize_t		actual;
714c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
715c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
716c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
717c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
718c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
719b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
720c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	/*
721c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 * Flush out the cache completely
722c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	 */
723c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if ((retval = flush_cached_blocks(channel, data, 1)))
724c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return retval;
725b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
726c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
7272e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
728c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return errno;
729efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
730c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	actual = write(data->dev, buf, size);
731c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	if (actual != size)
732c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o		return EXT2_ET_SHORT_WRITE;
733c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
734c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o	return 0;
735c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o}
736c180ac86533bcbfb1560bd4aa01464785a760f70Theodore Ts'o
7373839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o/*
738efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o * Flush data buffers to disk.
7393839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o */
7403839e65723771b85975f4263102dd3ceec4523cTheodore Ts'ostatic errcode_t unix_flush(io_channel channel)
7413839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o{
742f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	struct unix_private_data *data;
743adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	errcode_t retval = 0;
744efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
745f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
746f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	data = (struct unix_private_data *) channel->private_data;
747f3db3566b5e1342e49dffc5ec3f418a838584194Theodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
748adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o
749b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#ifndef NO_IO_CACHE
750adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	retval = flush_cached_blocks(channel, data, 0);
751b8a953157bce577bff6f9d8437e8d7f2c881fe63Theodore Ts'o#endif
75236f21439f5d8b2233d13e042833d4d921a5c2c40Theodore Ts'o	fsync(data->dev);
753adfc8c6c9902c3f08c79a44c1927971175f9d947Theodore Ts'o	return retval;
7543839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o}
7553839e65723771b85975f4263102dd3ceec4523cTheodore Ts'o
756efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'ostatic errcode_t unix_set_option(io_channel channel, const char *option,
7572e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o				 const char *arg)
7582e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o{
7592e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	struct unix_private_data *data;
7602aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o	unsigned long long tmp;
7612e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	char *end;
7622e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
7632e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
7642e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	data = (struct unix_private_data *) channel->private_data;
7652e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
7662e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
7672e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	if (!strcmp(option, "offset")) {
7682e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		if (!arg)
7692e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o			return EXT2_ET_INVALID_ARGUMENT;
7702e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o
7712aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o		tmp = strtoull(arg, &end, 0);
7722e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		if (*end)
7732e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o			return EXT2_ET_INVALID_ARGUMENT;
7742e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		data->offset = tmp;
7752aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o		if (data->offset < 0)
7762aee23f325037fce1db32d556e6cf9adaa97ce04Theodore Ts'o			return EXT2_ET_INVALID_ARGUMENT;
7772e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o		return 0;
7782e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	}
7792e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o	return EXT2_ET_INVALID_ARGUMENT;
7802e8ca9a26b0bd7dae546a3f9a98df67b043fe3beTheodore Ts'o}
781