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