Home | History | Annotate | Download | only in ext2fs
      1 /*
      2  * unix_io.c --- This is the Unix (well, really POSIX) implementation
      3  * 	of the I/O manager.
      4  *
      5  * Implements a one-block write-through cache.
      6  *
      7  * Includes support for Windows NT support under Cygwin.
      8  *
      9  * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
     10  * 	2002 by Theodore Ts'o.
     11  *
     12  * %Begin-Header%
     13  * This file may be redistributed under the terms of the GNU Public
     14  * License.
     15  * %End-Header%
     16  */
     17 
     18 #define _LARGEFILE_SOURCE
     19 #define _LARGEFILE64_SOURCE
     20 
     21 #include <stdio.h>
     22 #include <string.h>
     23 #if HAVE_UNISTD_H
     24 #include <unistd.h>
     25 #endif
     26 #if HAVE_ERRNO_H
     27 #include <errno.h>
     28 #endif
     29 #include <fcntl.h>
     30 #include <time.h>
     31 #ifdef __linux__
     32 #include <sys/utsname.h>
     33 #endif
     34 #ifdef HAVE_SYS_IOCTL_H
     35 #include <sys/ioctl.h>
     36 #endif
     37 #ifdef HAVE_SYS_MOUNT_H
     38 #include <sys/mount.h>
     39 #endif
     40 #if HAVE_SYS_STAT_H
     41 #include <sys/stat.h>
     42 #endif
     43 #if HAVE_SYS_TYPES_H
     44 #include <sys/types.h>
     45 #endif
     46 #if HAVE_SYS_RESOURCE_H
     47 #include <sys/resource.h>
     48 #endif
     49 
     50 #if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
     51 #define BLKROGET   _IO(0x12, 94) /* Get read-only status (0 = read_write).  */
     52 #endif
     53 
     54 #include "ext2_fs.h"
     55 #include "ext2fs.h"
     56 
     57 /*
     58  * For checking structure magic numbers...
     59  */
     60 
     61 #define EXT2_CHECK_MAGIC(struct, code) \
     62 	  if ((struct)->magic != (code)) return (code)
     63 
     64 struct unix_cache {
     65 	char		*buf;
     66 	unsigned long	block;
     67 	int		access_time;
     68 	unsigned	dirty:1;
     69 	unsigned	in_use:1;
     70 };
     71 
     72 #define CACHE_SIZE 8
     73 #define WRITE_DIRECT_SIZE 4	/* Must be smaller than CACHE_SIZE */
     74 #define READ_DIRECT_SIZE 4	/* Should be smaller than CACHE_SIZE */
     75 
     76 struct unix_private_data {
     77 	int	magic;
     78 	int	dev;
     79 	int	flags;
     80 	int	access_time;
     81 	ext2_loff_t offset;
     82 	struct unix_cache cache[CACHE_SIZE];
     83 	struct struct_io_stats io_stats;
     84 };
     85 
     86 static errcode_t unix_open(const char *name, int flags, io_channel *channel);
     87 static errcode_t unix_close(io_channel channel);
     88 static errcode_t unix_set_blksize(io_channel channel, int blksize);
     89 static errcode_t unix_read_blk(io_channel channel, unsigned long block,
     90 			       int count, void *data);
     91 static errcode_t unix_write_blk(io_channel channel, unsigned long block,
     92 				int count, const void *data);
     93 static errcode_t unix_flush(io_channel channel);
     94 static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
     95 				int size, const void *data);
     96 static errcode_t unix_set_option(io_channel channel, const char *option,
     97 				 const char *arg);
     98 static errcode_t unix_get_stats(io_channel channel, io_stats *stats)
     99 ;
    100 static void reuse_cache(io_channel channel, struct unix_private_data *data,
    101 		 struct unix_cache *cache, unsigned long long block);
    102 static errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
    103 			       int count, void *data);
    104 static errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
    105 				int count, const void *data);
    106 
    107 /* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel
    108  * does not know buffered block devices - everything is raw. */
    109 #if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
    110 #define NEED_BOUNCE_BUFFER
    111 #else
    112 #undef NEED_BOUNCE_BUFFER
    113 #endif
    114 
    115 static struct struct_io_manager struct_unix_manager = {
    116 	EXT2_ET_MAGIC_IO_MANAGER,
    117 	"Unix I/O Manager",
    118 	unix_open,
    119 	unix_close,
    120 	unix_set_blksize,
    121 	unix_read_blk,
    122 	unix_write_blk,
    123 	unix_flush,
    124 #ifdef NEED_BOUNCE_BUFFER
    125 	0,
    126 #else
    127 	unix_write_byte,
    128 #endif
    129 	unix_set_option,
    130 	unix_get_stats,
    131 	unix_read_blk64,
    132 	unix_write_blk64,
    133 };
    134 
    135 io_manager unix_io_manager = &struct_unix_manager;
    136 
    137 static errcode_t unix_get_stats(io_channel channel, io_stats *stats)
    138 {
    139 	errcode_t 	retval = 0;
    140 
    141 	struct unix_private_data *data;
    142 
    143 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
    144 	data = (struct unix_private_data *) channel->private_data;
    145 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
    146 
    147 	if (stats)
    148 		*stats = &data->io_stats;
    149 
    150 	return retval;
    151 }
    152 
    153 /*
    154  * Here are the raw I/O functions
    155  */
    156 #ifndef NEED_BOUNCE_BUFFER
    157 static errcode_t raw_read_blk(io_channel channel,
    158 			      struct unix_private_data *data,
    159 			      unsigned long long block,
    160 			      int count, void *buf)
    161 {
    162 	errcode_t	retval;
    163 	ssize_t		size;
    164 	ext2_loff_t	location;
    165 	int		actual = 0;
    166 
    167 	size = (count < 0) ? -count : count * channel->block_size;
    168 	data->io_stats.bytes_read += size;
    169 	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
    170 	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
    171 		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
    172 		goto error_out;
    173 	}
    174 	actual = read(data->dev, buf, size);
    175 	if (actual != size) {
    176 		if (actual < 0)
    177 			actual = 0;
    178 		retval = EXT2_ET_SHORT_READ;
    179 		goto error_out;
    180 	}
    181 	return 0;
    182 
    183 error_out:
    184 	memset((char *) buf+actual, 0, size-actual);
    185 	if (channel->read_error)
    186 		retval = (channel->read_error)(channel, block, count, buf,
    187 					       size, actual, retval);
    188 	return retval;
    189 }
    190 #else /* NEED_BOUNCE_BUFFER */
    191 /*
    192  * Windows and FreeBSD block devices only allow sector alignment IO in offset and size
    193  */
    194 static errcode_t raw_read_blk(io_channel channel,
    195 			      struct unix_private_data *data,
    196 			      unsigned long block,
    197 			      int count, void *buf)
    198 {
    199 	errcode_t	retval;
    200 	size_t		size, alignsize, fragment;
    201 	ext2_loff_t	location;
    202 	int		total = 0, actual;
    203 #define BLOCKALIGN 512
    204 	char		sector[BLOCKALIGN];
    205 
    206 	size = (count < 0) ? -count : count * channel->block_size;
    207 	data->io_stats.bytes_read += size;
    208 	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
    209 #ifdef DEBUG
    210 	printf("count=%d, size=%d, block=%lu, blk_size=%d, location=%llx\n",
    211 	 		count, size, block, channel->block_size, (long long)location);
    212 #endif
    213 	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
    214 		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
    215 		goto error_out;
    216 	}
    217 	fragment = size % BLOCKALIGN;
    218 	alignsize = size - fragment;
    219 	if (alignsize) {
    220 		actual = read(data->dev, buf, alignsize);
    221 		if (actual != alignsize)
    222 			goto short_read;
    223 	}
    224 	if (fragment) {
    225 		actual = read(data->dev, sector, BLOCKALIGN);
    226 		if (actual != BLOCKALIGN)
    227 			goto short_read;
    228 		memcpy(buf+alignsize, sector, fragment);
    229 	}
    230 	return 0;
    231 
    232 short_read:
    233 	if (actual>0)
    234 		total += actual;
    235 	retval = EXT2_ET_SHORT_READ;
    236 
    237 error_out:
    238 	memset((char *) buf+total, 0, size-actual);
    239 	if (channel->read_error)
    240 		retval = (channel->read_error)(channel, block, count, buf,
    241 					       size, actual, retval);
    242 	return retval;
    243 }
    244 #endif
    245 
    246 static errcode_t raw_write_blk(io_channel channel,
    247 			       struct unix_private_data *data,
    248 			       unsigned long long block,
    249 			       int count, const void *buf)
    250 {
    251 	ssize_t		size;
    252 	ext2_loff_t	location;
    253 	int		actual = 0;
    254 	errcode_t	retval;
    255 
    256 	if (count == 1)
    257 		size = channel->block_size;
    258 	else {
    259 		if (count < 0)
    260 			size = -count;
    261 		else
    262 			size = count * channel->block_size;
    263 	}
    264 	data->io_stats.bytes_written += size;
    265 
    266 	location = ((ext2_loff_t) block * channel->block_size) + data->offset;
    267 	if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
    268 		retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
    269 		goto error_out;
    270 	}
    271 
    272 	actual = write(data->dev, buf, size);
    273 	if (actual != size) {
    274 		retval = EXT2_ET_SHORT_WRITE;
    275 		goto error_out;
    276 	}
    277 	return 0;
    278 
    279 error_out:
    280 	if (channel->write_error)
    281 		retval = (channel->write_error)(channel, block, count, buf,
    282 						size, actual, retval);
    283 	return retval;
    284 }
    285 
    286 
    287 /*
    288  * Here we implement the cache functions
    289  */
    290 
    291 /* Allocate the cache buffers */
    292 static errcode_t alloc_cache(io_channel channel,
    293 			     struct unix_private_data *data)
    294 {
    295 	errcode_t		retval;
    296 	struct unix_cache	*cache;
    297 	int			i;
    298 
    299 	data->access_time = 0;
    300 	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
    301 		cache->block = 0;
    302 		cache->access_time = 0;
    303 		cache->dirty = 0;
    304 		cache->in_use = 0;
    305 		if ((retval = ext2fs_get_mem(channel->block_size,
    306 					     &cache->buf)))
    307 			return retval;
    308 	}
    309 	return 0;
    310 }
    311 
    312 /* Free the cache buffers */
    313 static void free_cache(struct unix_private_data *data)
    314 {
    315 	struct unix_cache	*cache;
    316 	int			i;
    317 
    318 	data->access_time = 0;
    319 	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
    320 		cache->block = 0;
    321 		cache->access_time = 0;
    322 		cache->dirty = 0;
    323 		cache->in_use = 0;
    324 		if (cache->buf)
    325 			ext2fs_free_mem(&cache->buf);
    326 		cache->buf = 0;
    327 	}
    328 }
    329 
    330 #ifndef NO_IO_CACHE
    331 /*
    332  * Try to find a block in the cache.  If the block is not found, and
    333  * eldest is a non-zero pointer, then fill in eldest with the cache
    334  * entry to that should be reused.
    335  */
    336 static struct unix_cache *find_cached_block(struct unix_private_data *data,
    337 					    unsigned long long block,
    338 					    struct unix_cache **eldest)
    339 {
    340 	struct unix_cache	*cache, *unused_cache, *oldest_cache;
    341 	int			i;
    342 
    343 	unused_cache = oldest_cache = 0;
    344 	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
    345 		if (!cache->in_use) {
    346 			if (!unused_cache)
    347 				unused_cache = cache;
    348 			continue;
    349 		}
    350 		if (cache->block == block) {
    351 			cache->access_time = ++data->access_time;
    352 			return cache;
    353 		}
    354 		if (!oldest_cache ||
    355 		    (cache->access_time < oldest_cache->access_time))
    356 			oldest_cache = cache;
    357 	}
    358 	if (eldest)
    359 		*eldest = (unused_cache) ? unused_cache : oldest_cache;
    360 	return 0;
    361 }
    362 
    363 /*
    364  * Reuse a particular cache entry for another block.
    365  */
    366 static void reuse_cache(io_channel channel, struct unix_private_data *data,
    367 		 struct unix_cache *cache, unsigned long long block)
    368 {
    369 	if (cache->dirty && cache->in_use)
    370 		raw_write_blk(channel, data, cache->block, 1, cache->buf);
    371 
    372 	cache->in_use = 1;
    373 	cache->dirty = 0;
    374 	cache->block = block;
    375 	cache->access_time = ++data->access_time;
    376 }
    377 
    378 /*
    379  * Flush all of the blocks in the cache
    380  */
    381 static errcode_t flush_cached_blocks(io_channel channel,
    382 				     struct unix_private_data *data,
    383 				     int invalidate)
    384 
    385 {
    386 	struct unix_cache	*cache;
    387 	errcode_t		retval, retval2;
    388 	int			i;
    389 
    390 	retval2 = 0;
    391 	for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
    392 		if (!cache->in_use)
    393 			continue;
    394 
    395 		if (invalidate)
    396 			cache->in_use = 0;
    397 
    398 		if (!cache->dirty)
    399 			continue;
    400 
    401 		retval = raw_write_blk(channel, data,
    402 				       cache->block, 1, cache->buf);
    403 		if (retval)
    404 			retval2 = retval;
    405 		else
    406 			cache->dirty = 0;
    407 	}
    408 	return retval2;
    409 }
    410 #endif /* NO_IO_CACHE */
    411 
    412 static errcode_t unix_open(const char *name, int flags, io_channel *channel)
    413 {
    414 	io_channel	io = NULL;
    415 	struct unix_private_data *data = NULL;
    416 	errcode_t	retval;
    417 	int		open_flags;
    418 	struct stat	st;
    419 #ifdef __linux__
    420 	struct 		utsname ut;
    421 #endif
    422 
    423 	if (name == 0)
    424 		return EXT2_ET_BAD_DEVICE_NAME;
    425 	retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
    426 	if (retval)
    427 		return retval;
    428 	memset(io, 0, sizeof(struct struct_io_channel));
    429 	io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
    430 	retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
    431 	if (retval)
    432 		goto cleanup;
    433 
    434 	io->manager = unix_io_manager;
    435 	retval = ext2fs_get_mem(strlen(name)+1, &io->name);
    436 	if (retval)
    437 		goto cleanup;
    438 
    439 	strcpy(io->name, name);
    440 	io->private_data = data;
    441 	io->block_size = 1024;
    442 	io->read_error = 0;
    443 	io->write_error = 0;
    444 	io->refcount = 1;
    445 
    446 	memset(data, 0, sizeof(struct unix_private_data));
    447 	data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
    448 	data->io_stats.num_fields = 2;
    449 
    450 	if ((retval = alloc_cache(io, data)))
    451 		goto cleanup;
    452 
    453 	open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
    454 	if (flags & IO_FLAG_EXCLUSIVE)
    455 		open_flags |= O_EXCL;
    456 #ifdef HAVE_OPEN64
    457 	data->dev = open64(io->name, open_flags);
    458 #else
    459 	data->dev = open(io->name, open_flags);
    460 #endif
    461 	if (data->dev < 0) {
    462 		retval = errno;
    463 		goto cleanup;
    464 	}
    465 
    466 #ifdef BLKROGET
    467 	if (flags & IO_FLAG_RW) {
    468 		int error;
    469 		int readonly = 0;
    470 
    471 		/* Is the block device actually writable? */
    472 		error = ioctl(data->dev, BLKROGET, &readonly);
    473 		if (!error && readonly) {
    474 			close(data->dev);
    475 			retval = EPERM;
    476 			goto cleanup;
    477 		}
    478 	}
    479 #endif
    480 
    481 #ifdef __linux__
    482 #undef RLIM_INFINITY
    483 #if (defined(__alpha__) || ((defined(__sparc__) || defined(__mips__)) && (SIZEOF_LONG == 4)))
    484 #define RLIM_INFINITY	((unsigned long)(~0UL>>1))
    485 #else
    486 #define RLIM_INFINITY  (~0UL)
    487 #endif
    488 	/*
    489 	 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
    490 	 * block devices are wrongly getting hit by the filesize
    491 	 * limit.  This workaround isn't perfect, since it won't work
    492 	 * if glibc wasn't built against 2.2 header files.  (Sigh.)
    493 	 *
    494 	 */
    495 	if ((flags & IO_FLAG_RW) &&
    496 	    (uname(&ut) == 0) &&
    497 	    ((ut.release[0] == '2') && (ut.release[1] == '.') &&
    498 	     (ut.release[2] == '4') && (ut.release[3] == '.') &&
    499 	     (ut.release[4] == '1') && (ut.release[5] >= '0') &&
    500 	     (ut.release[5] < '8')) &&
    501 	    (fstat(data->dev, &st) == 0) &&
    502 	    (S_ISBLK(st.st_mode))) {
    503 		struct rlimit	rlim;
    504 
    505 		rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
    506 		setrlimit(RLIMIT_FSIZE, &rlim);
    507 		getrlimit(RLIMIT_FSIZE, &rlim);
    508 		if (((unsigned long) rlim.rlim_cur) <
    509 		    ((unsigned long) rlim.rlim_max)) {
    510 			rlim.rlim_cur = rlim.rlim_max;
    511 			setrlimit(RLIMIT_FSIZE, &rlim);
    512 		}
    513 	}
    514 #endif
    515 	*channel = io;
    516 	return 0;
    517 
    518 cleanup:
    519 	if (data) {
    520 		free_cache(data);
    521 		ext2fs_free_mem(&data);
    522 	}
    523 	if (io)
    524 		ext2fs_free_mem(&io);
    525 	return retval;
    526 }
    527 
    528 static errcode_t unix_close(io_channel channel)
    529 {
    530 	struct unix_private_data *data;
    531 	errcode_t	retval = 0;
    532 
    533 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
    534 	data = (struct unix_private_data *) channel->private_data;
    535 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
    536 
    537 	if (--channel->refcount > 0)
    538 		return 0;
    539 
    540 #ifndef NO_IO_CACHE
    541 	retval = flush_cached_blocks(channel, data, 0);
    542 #endif
    543 
    544 	if (close(data->dev) < 0)
    545 		retval = errno;
    546 	free_cache(data);
    547 
    548 	ext2fs_free_mem(&channel->private_data);
    549 	if (channel->name)
    550 		ext2fs_free_mem(&channel->name);
    551 	ext2fs_free_mem(&channel);
    552 	return retval;
    553 }
    554 
    555 static errcode_t unix_set_blksize(io_channel channel, int blksize)
    556 {
    557 	struct unix_private_data *data;
    558 	errcode_t		retval;
    559 
    560 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
    561 	data = (struct unix_private_data *) channel->private_data;
    562 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
    563 
    564 	if (channel->block_size != blksize) {
    565 #ifndef NO_IO_CACHE
    566 		if ((retval = flush_cached_blocks(channel, data, 0)))
    567 			return retval;
    568 #endif
    569 
    570 		channel->block_size = blksize;
    571 		free_cache(data);
    572 		if ((retval = alloc_cache(channel, data)))
    573 			return retval;
    574 	}
    575 	return 0;
    576 }
    577 
    578 
    579 static errcode_t unix_read_blk64(io_channel channel, unsigned long long block,
    580 			       int count, void *buf)
    581 {
    582 	struct unix_private_data *data;
    583 	struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
    584 	errcode_t	retval;
    585 	char		*cp;
    586 	int		i, j;
    587 
    588 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
    589 	data = (struct unix_private_data *) channel->private_data;
    590 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
    591 
    592 #ifdef NO_IO_CACHE
    593 	return raw_read_blk(channel, data, block, count, buf);
    594 #else
    595 	/*
    596 	 * If we're doing an odd-sized read or a very large read,
    597 	 * flush out the cache and then do a direct read.
    598 	 */
    599 	if (count < 0 || count > WRITE_DIRECT_SIZE) {
    600 		if ((retval = flush_cached_blocks(channel, data, 0)))
    601 			return retval;
    602 		return raw_read_blk(channel, data, block, count, buf);
    603 	}
    604 
    605 	cp = buf;
    606 	while (count > 0) {
    607 		/* If it's in the cache, use it! */
    608 		if ((cache = find_cached_block(data, block, &reuse[0]))) {
    609 #ifdef DEBUG
    610 			printf("Using cached block %lu\n", block);
    611 #endif
    612 			memcpy(cp, cache->buf, channel->block_size);
    613 			count--;
    614 			block++;
    615 			cp += channel->block_size;
    616 			continue;
    617 		}
    618 		/*
    619 		 * Find the number of uncached blocks so we can do a
    620 		 * single read request
    621 		 */
    622 		for (i=1; i < count; i++)
    623 			if (find_cached_block(data, block+i, &reuse[i]))
    624 				break;
    625 #ifdef DEBUG
    626 		printf("Reading %d blocks starting at %lu\n", i, block);
    627 #endif
    628 		if ((retval = raw_read_blk(channel, data, block, i, cp)))
    629 			return retval;
    630 
    631 		/* Save the results in the cache */
    632 		for (j=0; j < i; j++) {
    633 			count--;
    634 			cache = reuse[j];
    635 			reuse_cache(channel, data, cache, block++);
    636 			memcpy(cache->buf, cp, channel->block_size);
    637 			cp += channel->block_size;
    638 		}
    639 	}
    640 	return 0;
    641 #endif /* NO_IO_CACHE */
    642 }
    643 
    644 static errcode_t unix_read_blk(io_channel channel, unsigned long block,
    645 			       int count, void *buf)
    646 {
    647 	return unix_read_blk64(channel, block, count, buf);
    648 }
    649 
    650 static errcode_t unix_write_blk64(io_channel channel, unsigned long long block,
    651 				int count, const void *buf)
    652 {
    653 	struct unix_private_data *data;
    654 	struct unix_cache *cache, *reuse;
    655 	errcode_t	retval = 0;
    656 	const char	*cp;
    657 	int		writethrough;
    658 
    659 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
    660 	data = (struct unix_private_data *) channel->private_data;
    661 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
    662 
    663 #ifdef NO_IO_CACHE
    664 	return raw_write_blk(channel, data, block, count, buf);
    665 #else
    666 	/*
    667 	 * If we're doing an odd-sized write or a very large write,
    668 	 * flush out the cache completely and then do a direct write.
    669 	 */
    670 	if (count < 0 || count > WRITE_DIRECT_SIZE) {
    671 		if ((retval = flush_cached_blocks(channel, data, 1)))
    672 			return retval;
    673 		return raw_write_blk(channel, data, block, count, buf);
    674 	}
    675 
    676 	/*
    677 	 * For a moderate-sized multi-block write, first force a write
    678 	 * if we're in write-through cache mode, and then fill the
    679 	 * cache with the blocks.
    680 	 */
    681 	writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
    682 	if (writethrough)
    683 		retval = raw_write_blk(channel, data, block, count, buf);
    684 
    685 	cp = buf;
    686 	while (count > 0) {
    687 		cache = find_cached_block(data, block, &reuse);
    688 		if (!cache) {
    689 			cache = reuse;
    690 			reuse_cache(channel, data, cache, block);
    691 		}
    692 		memcpy(cache->buf, cp, channel->block_size);
    693 		cache->dirty = !writethrough;
    694 		count--;
    695 		block++;
    696 		cp += channel->block_size;
    697 	}
    698 	return retval;
    699 #endif /* NO_IO_CACHE */
    700 }
    701 
    702 static errcode_t unix_write_blk(io_channel channel, unsigned long block,
    703 				int count, const void *buf)
    704 {
    705 	return unix_write_blk64(channel, block, count, buf);
    706 }
    707 
    708 static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
    709 				 int size, const void *buf)
    710 {
    711 	struct unix_private_data *data;
    712 	errcode_t	retval = 0;
    713 	ssize_t		actual;
    714 
    715 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
    716 	data = (struct unix_private_data *) channel->private_data;
    717 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
    718 
    719 #ifndef NO_IO_CACHE
    720 	/*
    721 	 * Flush out the cache completely
    722 	 */
    723 	if ((retval = flush_cached_blocks(channel, data, 1)))
    724 		return retval;
    725 #endif
    726 
    727 	if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
    728 		return errno;
    729 
    730 	actual = write(data->dev, buf, size);
    731 	if (actual != size)
    732 		return EXT2_ET_SHORT_WRITE;
    733 
    734 	return 0;
    735 }
    736 
    737 /*
    738  * Flush data buffers to disk.
    739  */
    740 static errcode_t unix_flush(io_channel channel)
    741 {
    742 	struct unix_private_data *data;
    743 	errcode_t retval = 0;
    744 
    745 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
    746 	data = (struct unix_private_data *) channel->private_data;
    747 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
    748 
    749 #ifndef NO_IO_CACHE
    750 	retval = flush_cached_blocks(channel, data, 0);
    751 #endif
    752 	fsync(data->dev);
    753 	return retval;
    754 }
    755 
    756 static errcode_t unix_set_option(io_channel channel, const char *option,
    757 				 const char *arg)
    758 {
    759 	struct unix_private_data *data;
    760 	unsigned long long tmp;
    761 	char *end;
    762 
    763 	EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
    764 	data = (struct unix_private_data *) channel->private_data;
    765 	EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
    766 
    767 	if (!strcmp(option, "offset")) {
    768 		if (!arg)
    769 			return EXT2_ET_INVALID_ARGUMENT;
    770 
    771 		tmp = strtoull(arg, &end, 0);
    772 		if (*end)
    773 			return EXT2_ET_INVALID_ARGUMENT;
    774 		data->offset = tmp;
    775 		if (data->offset < 0)
    776 			return EXT2_ET_INVALID_ARGUMENT;
    777 		return 0;
    778 	}
    779 	return EXT2_ET_INVALID_ARGUMENT;
    780 }
    781