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