Changes for kernel and Busybox
[tomato.git] / release / src / router / busybox / e2fsprogs / ext2fs / unix_io.c
blob8dde4c732258d14dc06f626107114461c9aef0c3
1 /* vi: set sw=4 ts=4: */
2 /*
3 * unix_io.c --- This is the Unix (well, really POSIX) implementation
4 * of the I/O manager.
6 * Implements a one-block write-through cache.
8 * Includes support for Windows NT support under Cygwin.
10 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
11 * 2002 by Theodore Ts'o.
13 * %Begin-Header%
14 * This file may be redistributed under the terms of the GNU Public
15 * License.
16 * %End-Header%
19 #include <stdio.h>
20 #include <string.h>
21 #if HAVE_UNISTD_H
22 #include <unistd.h>
23 #endif
24 #if HAVE_ERRNO_H
25 #include <errno.h>
26 #endif
27 #include <fcntl.h>
28 #include <time.h>
29 #ifdef __linux__
30 #include <sys/utsname.h>
31 #endif
32 #if HAVE_SYS_STAT_H
33 #include <sys/stat.h>
34 #endif
35 #if HAVE_SYS_TYPES_H
36 #include <sys/types.h>
37 #endif
38 #include <sys/resource.h>
40 #include "ext2_fs.h"
41 #include "ext2fs.h"
44 * For checking structure magic numbers...
47 #define EXT2_CHECK_MAGIC(struct, code) \
48 if ((struct)->magic != (code)) return (code)
50 struct unix_cache {
51 char *buf;
52 unsigned long block;
53 int access_time;
54 unsigned dirty:1;
55 unsigned in_use:1;
58 #define CACHE_SIZE 8
59 #define WRITE_DIRECT_SIZE 4 /* Must be smaller than CACHE_SIZE */
60 #define READ_DIRECT_SIZE 4 /* Should be smaller than CACHE_SIZE */
62 struct unix_private_data {
63 int magic;
64 int dev;
65 int flags;
66 int access_time;
67 ext2_loff_t offset;
68 struct unix_cache cache[CACHE_SIZE];
71 static errcode_t unix_open(const char *name, int flags, io_channel *channel);
72 static errcode_t unix_close(io_channel channel);
73 static errcode_t unix_set_blksize(io_channel channel, int blksize);
74 static errcode_t unix_read_blk(io_channel channel, unsigned long block,
75 int count, void *data);
76 static errcode_t unix_write_blk(io_channel channel, unsigned long block,
77 int count, const void *data);
78 static errcode_t unix_flush(io_channel channel);
79 static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
80 int size, const void *data);
81 static errcode_t unix_set_option(io_channel channel, const char *option,
82 const char *arg);
84 static void reuse_cache(io_channel channel, struct unix_private_data *data,
85 struct unix_cache *cache, unsigned long block);
87 /* __FreeBSD_kernel__ is defined by GNU/kFreeBSD - the FreeBSD kernel
88 * does not know buffered block devices - everything is raw. */
89 #if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
90 #define NEED_BOUNCE_BUFFER
91 #else
92 #undef NEED_BOUNCE_BUFFER
93 #endif
95 static struct struct_io_manager struct_unix_manager = {
96 EXT2_ET_MAGIC_IO_MANAGER,
97 "Unix I/O Manager",
98 unix_open,
99 unix_close,
100 unix_set_blksize,
101 unix_read_blk,
102 unix_write_blk,
103 unix_flush,
104 #ifdef NEED_BOUNCE_BUFFER
106 #else
107 unix_write_byte,
108 #endif
109 unix_set_option
112 io_manager unix_io_manager = &struct_unix_manager;
115 * Here are the raw I/O functions
117 #ifndef NEED_BOUNCE_BUFFER
118 static errcode_t raw_read_blk(io_channel channel,
119 struct unix_private_data *data,
120 unsigned long block,
121 int count, void *buf)
123 errcode_t retval;
124 ssize_t size;
125 ext2_loff_t location;
126 int actual = 0;
128 size = (count < 0) ? -count : count * channel->block_size;
129 location = ((ext2_loff_t) block * channel->block_size) + data->offset;
130 if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
131 retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
132 goto error_out;
134 actual = read(data->dev, buf, size);
135 if (actual != size) {
136 if (actual < 0)
137 actual = 0;
138 retval = EXT2_ET_SHORT_READ;
139 goto error_out;
141 return 0;
143 error_out:
144 memset((char *) buf+actual, 0, size-actual);
145 if (channel->read_error)
146 retval = (channel->read_error)(channel, block, count, buf,
147 size, actual, retval);
148 return retval;
150 #else /* NEED_BOUNCE_BUFFER */
152 * Windows and FreeBSD block devices only allow sector alignment IO in offset and size
154 static errcode_t raw_read_blk(io_channel channel,
155 struct unix_private_data *data,
156 unsigned long block,
157 int count, void *buf)
159 errcode_t retval;
160 size_t size, alignsize, fragment;
161 ext2_loff_t location;
162 int total = 0, actual;
163 #define BLOCKALIGN 512
164 char sector[BLOCKALIGN];
166 size = (count < 0) ? -count : count * channel->block_size;
167 location = ((ext2_loff_t) block * channel->block_size) + data->offset;
168 #ifdef DEBUG
169 printf("count=%d, size=%d, block=%d, blk_size=%d, location=%lx\n",
170 count, size, block, channel->block_size, location);
171 #endif
172 if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
173 retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
174 goto error_out;
176 fragment = size % BLOCKALIGN;
177 alignsize = size - fragment;
178 if (alignsize) {
179 actual = read(data->dev, buf, alignsize);
180 if (actual != alignsize)
181 goto short_read;
183 if (fragment) {
184 actual = read(data->dev, sector, BLOCKALIGN);
185 if (actual != BLOCKALIGN)
186 goto short_read;
187 memcpy(buf+alignsize, sector, fragment);
189 return 0;
191 short_read:
192 if (actual>0)
193 total += actual;
194 retval = EXT2_ET_SHORT_READ;
196 error_out:
197 memset((char *) buf+total, 0, size-actual);
198 if (channel->read_error)
199 retval = (channel->read_error)(channel, block, count, buf,
200 size, actual, retval);
201 return retval;
203 #endif
205 static errcode_t raw_write_blk(io_channel channel,
206 struct unix_private_data *data,
207 unsigned long block,
208 int count, const void *buf)
210 ssize_t size;
211 ext2_loff_t location;
212 int actual = 0;
213 errcode_t retval;
215 if (count == 1)
216 size = channel->block_size;
217 else {
218 if (count < 0)
219 size = -count;
220 else
221 size = count * channel->block_size;
224 location = ((ext2_loff_t) block * channel->block_size) + data->offset;
225 if (ext2fs_llseek(data->dev, location, SEEK_SET) != location) {
226 retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
227 goto error_out;
230 actual = write(data->dev, buf, size);
231 if (actual != size) {
232 retval = EXT2_ET_SHORT_WRITE;
233 goto error_out;
235 return 0;
237 error_out:
238 if (channel->write_error)
239 retval = (channel->write_error)(channel, block, count, buf,
240 size, actual, retval);
241 return retval;
246 * Here we implement the cache functions
249 /* Allocate the cache buffers */
250 static errcode_t alloc_cache(io_channel channel,
251 struct unix_private_data *data)
253 errcode_t retval;
254 struct unix_cache *cache;
255 int i;
257 data->access_time = 0;
258 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
259 cache->block = 0;
260 cache->access_time = 0;
261 cache->dirty = 0;
262 cache->in_use = 0;
263 if ((retval = ext2fs_get_mem(channel->block_size,
264 &cache->buf)))
265 return retval;
267 return 0;
270 /* Free the cache buffers */
271 static void free_cache(struct unix_private_data *data)
273 struct unix_cache *cache;
274 int i;
276 data->access_time = 0;
277 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
278 cache->block = 0;
279 cache->access_time = 0;
280 cache->dirty = 0;
281 cache->in_use = 0;
282 ext2fs_free_mem(&cache->buf);
283 cache->buf = 0;
287 #ifndef NO_IO_CACHE
289 * Try to find a block in the cache. If the block is not found, and
290 * eldest is a non-zero pointer, then fill in eldest with the cache
291 * entry to that should be reused.
293 static struct unix_cache *find_cached_block(struct unix_private_data *data,
294 unsigned long block,
295 struct unix_cache **eldest)
297 struct unix_cache *cache, *unused_cache, *oldest_cache;
298 int i;
300 unused_cache = oldest_cache = 0;
301 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
302 if (!cache->in_use) {
303 if (!unused_cache)
304 unused_cache = cache;
305 continue;
307 if (cache->block == block) {
308 cache->access_time = ++data->access_time;
309 return cache;
311 if (!oldest_cache ||
312 (cache->access_time < oldest_cache->access_time))
313 oldest_cache = cache;
315 if (eldest)
316 *eldest = (unused_cache) ? unused_cache : oldest_cache;
317 return 0;
321 * Reuse a particular cache entry for another block.
323 static void reuse_cache(io_channel channel, struct unix_private_data *data,
324 struct unix_cache *cache, unsigned long block)
326 if (cache->dirty && cache->in_use)
327 raw_write_blk(channel, data, cache->block, 1, cache->buf);
329 cache->in_use = 1;
330 cache->dirty = 0;
331 cache->block = block;
332 cache->access_time = ++data->access_time;
336 * Flush all of the blocks in the cache
338 static errcode_t flush_cached_blocks(io_channel channel,
339 struct unix_private_data *data,
340 int invalidate)
343 struct unix_cache *cache;
344 errcode_t retval, retval2;
345 int i;
347 retval2 = 0;
348 for (i=0, cache = data->cache; i < CACHE_SIZE; i++, cache++) {
349 if (!cache->in_use)
350 continue;
352 if (invalidate)
353 cache->in_use = 0;
355 if (!cache->dirty)
356 continue;
358 retval = raw_write_blk(channel, data,
359 cache->block, 1, cache->buf);
360 if (retval)
361 retval2 = retval;
362 else
363 cache->dirty = 0;
365 return retval2;
367 #endif /* NO_IO_CACHE */
369 static errcode_t unix_open(const char *name, int flags, io_channel *channel)
371 io_channel io = NULL;
372 struct unix_private_data *data = NULL;
373 errcode_t retval;
374 int open_flags;
375 struct stat st;
376 #ifdef __linux__
377 struct utsname ut;
378 #endif
380 if (name == 0)
381 return EXT2_ET_BAD_DEVICE_NAME;
382 retval = ext2fs_get_mem(sizeof(struct struct_io_channel), &io);
383 if (retval)
384 return retval;
385 memset(io, 0, sizeof(struct struct_io_channel));
386 io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
387 retval = ext2fs_get_mem(sizeof(struct unix_private_data), &data);
388 if (retval)
389 goto cleanup;
391 io->manager = unix_io_manager;
392 retval = ext2fs_get_mem(strlen(name)+1, &io->name);
393 if (retval)
394 goto cleanup;
396 strcpy(io->name, name);
397 io->private_data = data;
398 io->block_size = 1024;
399 io->read_error = 0;
400 io->write_error = 0;
401 io->refcount = 1;
403 memset(data, 0, sizeof(struct unix_private_data));
404 data->magic = EXT2_ET_MAGIC_UNIX_IO_CHANNEL;
406 if ((retval = alloc_cache(io, data)))
407 goto cleanup;
409 open_flags = (flags & IO_FLAG_RW) ? O_RDWR : O_RDONLY;
410 #ifdef CONFIG_LFS
411 data->dev = open64(io->name, open_flags);
412 #else
413 data->dev = open(io->name, open_flags);
414 #endif
415 if (data->dev < 0) {
416 retval = errno;
417 goto cleanup;
420 #ifdef __linux__
421 #undef RLIM_INFINITY
422 #if (defined(__alpha__) || (defined(__sparc__) && (__WORDSIZE == 32)) || (defined(__mips__) && (_MIPS_SZLONG == 32)))
423 #define RLIM_INFINITY ((unsigned long)(~0UL>>1))
424 #else
425 #define RLIM_INFINITY (~0UL)
426 #endif
428 * Work around a bug in 2.4.10-2.4.18 kernels where writes to
429 * block devices are wrongly getting hit by the filesize
430 * limit. This workaround isn't perfect, since it won't work
431 * if glibc wasn't built against 2.2 header files. (Sigh.)
434 if ((flags & IO_FLAG_RW) &&
435 (uname(&ut) == 0) &&
436 ((ut.release[0] == '2') && (ut.release[1] == '.') &&
437 (ut.release[2] == '4') && (ut.release[3] == '.') &&
438 (ut.release[4] == '1') && (ut.release[5] >= '0') &&
439 (ut.release[5] < '8')) &&
440 (fstat(data->dev, &st) == 0) &&
441 (S_ISBLK(st.st_mode))) {
442 struct rlimit rlim;
444 rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
445 setrlimit(RLIMIT_FSIZE, &rlim);
446 getrlimit(RLIMIT_FSIZE, &rlim);
447 if (((unsigned long) rlim.rlim_cur) <
448 ((unsigned long) rlim.rlim_max)) {
449 rlim.rlim_cur = rlim.rlim_max;
450 setrlimit(RLIMIT_FSIZE, &rlim);
453 #endif
454 *channel = io;
455 return 0;
457 cleanup:
458 if (data) {
459 free_cache(data);
460 ext2fs_free_mem(&data);
462 ext2fs_free_mem(&io);
463 return retval;
466 static errcode_t unix_close(io_channel channel)
468 struct unix_private_data *data;
469 errcode_t retval = 0;
471 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
472 data = (struct unix_private_data *) channel->private_data;
473 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
475 if (--channel->refcount > 0)
476 return 0;
478 #ifndef NO_IO_CACHE
479 retval = flush_cached_blocks(channel, data, 0);
480 #endif
482 if (close(data->dev) < 0)
483 retval = errno;
484 free_cache(data);
486 ext2fs_free_mem(&channel->private_data);
487 ext2fs_free_mem(&channel->name);
488 ext2fs_free_mem(&channel);
489 return retval;
492 static errcode_t unix_set_blksize(io_channel channel, int blksize)
494 struct unix_private_data *data;
495 errcode_t retval;
497 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
498 data = (struct unix_private_data *) channel->private_data;
499 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
501 if (channel->block_size != blksize) {
502 #ifndef NO_IO_CACHE
503 if ((retval = flush_cached_blocks(channel, data, 0)))
504 return retval;
505 #endif
507 channel->block_size = blksize;
508 free_cache(data);
509 if ((retval = alloc_cache(channel, data)))
510 return retval;
512 return 0;
516 static errcode_t unix_read_blk(io_channel channel, unsigned long block,
517 int count, void *buf)
519 struct unix_private_data *data;
520 struct unix_cache *cache, *reuse[READ_DIRECT_SIZE];
521 errcode_t retval;
522 char *cp;
523 int i, j;
525 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
526 data = (struct unix_private_data *) channel->private_data;
527 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
529 #ifdef NO_IO_CACHE
530 return raw_read_blk(channel, data, block, count, buf);
531 #else
533 * If we're doing an odd-sized read or a very large read,
534 * flush out the cache and then do a direct read.
536 if (count < 0 || count > WRITE_DIRECT_SIZE) {
537 if ((retval = flush_cached_blocks(channel, data, 0)))
538 return retval;
539 return raw_read_blk(channel, data, block, count, buf);
542 cp = buf;
543 while (count > 0) {
544 /* If it's in the cache, use it! */
545 if ((cache = find_cached_block(data, block, &reuse[0]))) {
546 #ifdef DEBUG
547 printf("Using cached block %d\n", block);
548 #endif
549 memcpy(cp, cache->buf, channel->block_size);
550 count--;
551 block++;
552 cp += channel->block_size;
553 continue;
556 * Find the number of uncached blocks so we can do a
557 * single read request
559 for (i=1; i < count; i++)
560 if (find_cached_block(data, block+i, &reuse[i]))
561 break;
562 #ifdef DEBUG
563 printf("Reading %d blocks starting at %d\n", i, block);
564 #endif
565 if ((retval = raw_read_blk(channel, data, block, i, cp)))
566 return retval;
568 /* Save the results in the cache */
569 for (j=0; j < i; j++) {
570 count--;
571 cache = reuse[j];
572 reuse_cache(channel, data, cache, block++);
573 memcpy(cache->buf, cp, channel->block_size);
574 cp += channel->block_size;
577 return 0;
578 #endif /* NO_IO_CACHE */
581 static errcode_t unix_write_blk(io_channel channel, unsigned long block,
582 int count, const void *buf)
584 struct unix_private_data *data;
585 struct unix_cache *cache, *reuse;
586 errcode_t retval = 0;
587 const char *cp;
588 int writethrough;
590 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
591 data = (struct unix_private_data *) channel->private_data;
592 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
594 #ifdef NO_IO_CACHE
595 return raw_write_blk(channel, data, block, count, buf);
596 #else
598 * If we're doing an odd-sized write or a very large write,
599 * flush out the cache completely and then do a direct write.
601 if (count < 0 || count > WRITE_DIRECT_SIZE) {
602 if ((retval = flush_cached_blocks(channel, data, 1)))
603 return retval;
604 return raw_write_blk(channel, data, block, count, buf);
608 * For a moderate-sized multi-block write, first force a write
609 * if we're in write-through cache mode, and then fill the
610 * cache with the blocks.
612 writethrough = channel->flags & CHANNEL_FLAGS_WRITETHROUGH;
613 if (writethrough)
614 retval = raw_write_blk(channel, data, block, count, buf);
616 cp = buf;
617 while (count > 0) {
618 cache = find_cached_block(data, block, &reuse);
619 if (!cache) {
620 cache = reuse;
621 reuse_cache(channel, data, cache, block);
623 memcpy(cache->buf, cp, channel->block_size);
624 cache->dirty = !writethrough;
625 count--;
626 block++;
627 cp += channel->block_size;
629 return retval;
630 #endif /* NO_IO_CACHE */
633 static errcode_t unix_write_byte(io_channel channel, unsigned long offset,
634 int size, const void *buf)
636 struct unix_private_data *data;
637 errcode_t retval = 0;
638 ssize_t actual;
640 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
641 data = (struct unix_private_data *) channel->private_data;
642 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
644 #ifndef NO_IO_CACHE
646 * Flush out the cache completely
648 if ((retval = flush_cached_blocks(channel, data, 1)))
649 return retval;
650 #endif
652 if (lseek(data->dev, offset + data->offset, SEEK_SET) < 0)
653 return errno;
655 actual = write(data->dev, buf, size);
656 if (actual != size)
657 return EXT2_ET_SHORT_WRITE;
659 return 0;
663 * Flush data buffers to disk.
665 static errcode_t unix_flush(io_channel channel)
667 struct unix_private_data *data;
668 errcode_t retval = 0;
670 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
671 data = (struct unix_private_data *) channel->private_data;
672 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
674 #ifndef NO_IO_CACHE
675 retval = flush_cached_blocks(channel, data, 0);
676 #endif
677 fsync(data->dev);
678 return retval;
681 static errcode_t unix_set_option(io_channel channel, const char *option,
682 const char *arg)
684 struct unix_private_data *data;
685 unsigned long tmp;
686 char *end;
688 EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
689 data = (struct unix_private_data *) channel->private_data;
690 EXT2_CHECK_MAGIC(data, EXT2_ET_MAGIC_UNIX_IO_CHANNEL);
692 if (!strcmp(option, "offset")) {
693 if (!arg)
694 return EXT2_ET_INVALID_ARGUMENT;
696 tmp = strtoul(arg, &end, 0);
697 if (*end)
698 return EXT2_ET_INVALID_ARGUMENT;
699 data->offset = tmp;
700 return 0;
702 return EXT2_ET_INVALID_ARGUMENT;