2 * fs_ext2.c - an implementation for the Ext2/Ext3 filesystem
4 * Copyright (C) 2001, 2002 Ethan Benson
6 * Copyright (C) 1999 Benjamin Herrenschmidt
8 * Adapted from quik/silo
10 * Copyright (C) 1996 Maurizio Plaza
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #include "partition.h"
41 #define MAX_READ_RANGE 256
45 #include "linux/ext2_fs.h"
46 #include "ext2fs/ext2fs.h"
48 static int ext2_open( struct boot_file_t* file,
49 struct partition_t* part,
50 struct boot_fspec_t* fspec);
51 static int ext2_read( struct boot_file_t* file,
54 static int ext2_seek( struct boot_file_t* file,
56 static int ext2_close( struct boot_file_t* file);
57 static unsigned int ext2_ino_size(struct boot_file_t *file);
59 struct fs_t ext2_filesystem =
69 /* IO manager structure for the ext2 library */
71 static errcode_t linux_open (const char *name, int flags, io_channel * channel);
72 static errcode_t linux_close (io_channel channel);
73 static errcode_t linux_set_blksize (io_channel channel, int blksize);
74 static errcode_t linux_read_blk (io_channel channel, unsigned long block, int count, void *data);
75 static errcode_t linux_write_blk (io_channel channel, unsigned long block, int count, const void *data);
76 static errcode_t linux_flush (io_channel channel);
78 static struct struct_io_manager struct_linux_manager =
80 EXT2_ET_MAGIC_IO_MANAGER,
90 static io_manager linux_io_manager = &struct_linux_manager;
92 /* Currently, we have a mess between what is in the file structure
93 * and what is stored globally here. I'll clean this up later
95 static int opened = 0; /* We can't open twice ! */
96 static unsigned int bs; /* Blocksize */
97 static unsigned long long doff; /* Byte offset where partition starts */
98 static unsigned long long dend; /* Byte offset where partition ends */
99 static ino_t root,cwd;
100 static ext2_filsys fs = 0;
101 static struct boot_file_t* cur_file;
102 static char *block_buffer = NULL;
105 static unsigned long read_range_start;
106 static unsigned long read_range_count;
107 static unsigned long read_last_logical;
108 static unsigned long read_total;
109 static unsigned long read_max;
110 static struct boot_file_t* read_cur_file;
111 static errcode_t read_result;
112 static char* read_buffer;
114 static int read_dump_range(void);
115 static int read_iterator(ext2_filsys fs, blk_t *blocknr, int lg_block, void *private);
116 #else /* FAST_VERSION */
117 static struct ext2_inode cur_inode;
118 #endif /* FAST_VERSION */
120 void com_err (const char *a, long i, const char *fmt,...)
122 prom_printf ((char *) fmt);
126 ext2_open( struct boot_file_t* file,
127 struct partition_t* part,
128 struct boot_fspec_t* fspec)
131 int error = FILE_ERR_NOTFOUND;
132 static char buffer[1024];
134 char *dev_name = fspec->dev;
135 char *file_name = fspec->file;
141 DEBUG_LEAVE(FILE_ERR_FSBUSY);
142 return FILE_ERR_FSBUSY;
144 if (file->device_kind != FILE_DEVICE_BLOCK
145 && file->device_kind != FILE_DEVICE_ISCSI) {
146 DEBUG_LEAVE(FILE_ERR_BADDEV);
147 return FILE_ERR_BADDEV;
152 /* We don't care too much about the device block size since we run
153 * thru the deblocker. We may have to change that is we plan to be
154 * compatible with older versions of OF
159 * On the other hand, we do care about the actual size of the
160 * partition, reads or seeks past the end may cause undefined
161 * behavior on some devices. A netapp that tries to seek and
162 * read past the end of the lun takes ~30 secs to recover per
167 doff = (unsigned long long)(part->part_start) * part->blocksize;
168 dend = doff + (unsigned long long)part->part_size * part->blocksize;
173 DEBUG_F("partition offset: %Lx, end: %Lx\n", doff, dend);
175 /* Open the OF device for the entire disk */
176 strncpy(buffer, dev_name, 1020);
177 if (_machine != _MACH_bplan)
178 strcat(buffer, ":0");
180 DEBUG_F("<%s>\n", buffer);
182 file->of_device = prom_open(buffer);
184 DEBUG_F("file->of_device = %p\n", file->of_device);
186 if (file->of_device == PROM_INVALID_HANDLE) {
188 DEBUG_F("Can't open device %p\n", file->of_device);
189 DEBUG_LEAVE(FILE_IOERR);
194 /* Open the ext2 filesystem */
195 result = ext2fs_open (buffer, EXT2_FLAG_RW, 0, 0, linux_io_manager, &fs);
198 if(result == EXT2_ET_BAD_MAGIC)
200 DEBUG_F( "ext2fs_open returned bad magic loading file %p\n",
205 DEBUG_F( "ext2fs_open error #%d while loading file %s\n",
208 error = FILE_ERR_BAD_FSYS;
212 /* Allocate the block buffer */
213 block_buffer = malloc(fs->blocksize * 2);
216 DEBUG_F("ext2fs: can't alloc block buffer (%d bytes)\n", fs->blocksize * 2);
221 /* Lookup file by pathname */
222 root = cwd = EXT2_ROOT_INO;
223 result = ext2fs_namei_follow(fs, root, cwd, file_name, &file->inode);
226 DEBUG_F("ext2fs_namei error #%d while loading file %s\n", result, file_name);
227 if (result == EXT2_ET_SYMLINK_LOOP)
228 error = FILE_ERR_SYMLINK_LOOP;
229 else if (result == EXT2_ET_FILE_NOT_FOUND)
230 error = FILE_ERR_NOTFOUND;
237 result = ext2fs_follow_link(fs, root, cwd, file->inode, &file->inode);
240 DEBUG_F("ext2fs_follow_link error #%d while loading file %s\n", result, file_name);
241 error = FILE_ERR_NOTFOUND;
247 result = ext2fs_read_inode(fs, file->inode, &cur_inode);
250 DEBUG_F("ext2fs_read_inode error #%d while loading file %s\n", result, file_name);
251 if (result == EXT2_ET_FILE_TOO_BIG)
252 error = FILE_ERR_LENGTH;
253 else if (result == EXT2_ET_LLSEEK_FAILED)
254 error = FILE_CANT_SEEK;
255 else if (result == EXT2_ET_FILE_NOT_FOUND)
256 error = FILE_ERR_NOTFOUND;
261 #endif /* FAST_VERSION */
271 prom_close(file->of_device);
277 DEBUG_LEAVE_F(error);
281 DEBUG_LEAVE(FILE_ERR_OK);
288 read_dump_range(void)
290 int count = read_range_count;
294 DEBUG_F(" dumping range: start: 0x%x count: 0x%x\n",
295 read_range_count, read_range_start);
297 /* Check if we need to handle a special case for the last block */
298 if ((count * bs) > read_max)
302 read_result = io_channel_read_blk(fs->io, read_range_start, count, read_buffer);
308 read_cur_file->pos += size;
309 read_range_count -= count;
310 read_range_start += count;
311 read_last_logical += count;
313 /* Handle remaining block */
314 if (read_max && read_range_count) {
315 read_result = io_channel_read_blk(fs->io, read_range_start, 1, block_buffer);
318 memcpy(read_buffer, block_buffer, read_max);
319 read_cur_file->pos += read_max;
320 read_total += read_max;
323 read_range_count = read_range_start = 0;
325 return (read_max == 0) ? BLOCK_ABORT : 0;
329 read_iterator(ext2_filsys fs, blk_t *blocknr, int lg_block, void *private)
332 DEBUG_F("read_it: p_bloc: 0x%x, l_bloc: 0x%x, f_pos: 0x%x, rng_pos: 0x%x ",
333 *blocknr, lg_block, read_cur_file->pos, read_last_logical);
337 DEBUG_F(" <skip lg>\n");
342 /* If we have not reached the start block yet, we skip */
343 if (lg_block < read_cur_file->pos / bs) {
345 DEBUG_F(" <skip pos>\n");
350 /* If block is contiguous to current range, just extend range,
351 * exit if we pass the remaining bytes count to read
353 if (read_range_start && read_range_count < MAX_READ_RANGE
354 && (*blocknr == read_range_start + read_range_count)
355 && (lg_block == read_last_logical + read_range_count)) {
357 DEBUG_F(" block in range\n");
360 return ((read_range_count * bs) >= read_max) ? BLOCK_ABORT : 0;
363 /* Range doesn't match. Dump existing range */
364 if (read_range_start) {
366 DEBUG_F(" calling dump range \n");
368 if (read_dump_range())
372 /* Here we handle holes in the file */
373 if (lg_block && lg_block != read_last_logical) {
376 DEBUG_F(" hole from lg_bloc 0x%x\n", read_last_logical);
378 if (read_cur_file->pos % bs) {
379 int offset = read_cur_file->pos % bs;
380 int size = bs - offset;
383 memset(read_buffer, 0, size);
387 read_cur_file->pos += size;
392 nzero = (lg_block - read_last_logical) * bs;
394 if (nzero > read_max)
396 memset(read_buffer, 0, nzero);
399 read_buffer += nzero;
400 read_cur_file->pos += nzero;
404 read_last_logical = lg_block;
407 /* If we are not aligned, handle that case */
408 if (read_cur_file->pos % bs) {
409 int offset = read_cur_file->pos % bs;
410 int size = bs - offset;
412 DEBUG_F(" handle unaligned start\n");
414 read_result = io_channel_read_blk(fs->io, *blocknr, 1, block_buffer);
419 memcpy(read_buffer, block_buffer + offset, size);
420 read_cur_file->pos += size;
424 read_last_logical = lg_block + 1;
425 return (read_max == 0) ? BLOCK_ABORT : 0;
428 /* If there is still a physical block to add, then create a new range */
431 DEBUG_F(" new range\n");
433 read_range_start = *blocknr;
434 read_range_count = 1;
435 return (bs >= read_max) ? BLOCK_ABORT : 0;
444 #endif /* FAST_VERSION */
447 ext2_read( struct boot_file_t* file,
458 DEBUG_F("ext_read() from pos 0x%Lx, size: 0x%ux\n", file->pos, size);
461 read_cur_file = file;
462 read_range_start = 0;
463 read_range_count = 0;
464 read_last_logical = file->pos / bs;
467 read_buffer = (unsigned char*)buffer;
470 retval = ext2fs_block_iterate(fs, file->inode, 0, 0, read_iterator, 0);
471 if (retval == BLOCK_ABORT)
472 retval = read_result;
473 if (!retval && read_range_start) {
475 DEBUG_F("on exit: range_start is 0x%x, calling dump...\n",
479 retval = read_result;
482 prom_printf ("ext2: i/o error %ld in read\n", (long) retval);
486 #else /* FAST_VERSION */
488 unsigned int read = 0;
494 DEBUG_F("ext_read() from pos 0x%x, size: 0x%x\n", file->pos, size);
498 blk_t fblock = file->pos / bs;
500 unsigned int blkorig, s, b;
503 status = ext2fs_bmap(fs, file->inode, &cur_inode,
504 block_buffer, 0, fblock, &pblock);
507 DEBUG_F("ext2fs_bmap(fblock:%d) return: %d\n", fblock, status);
510 blkorig = fblock * bs;
511 b = file->pos - blkorig;
512 s = ((bs - b) > size) ? size : (bs - b);
514 unsigned long long pos =
515 ((unsigned long long)pblock) * (unsigned long long)bs;
517 prom_lseek(file->of_device, pos);
518 status = prom_read(file->of_device, block_buffer, bs);
520 prom_printf("ext2: io error in read, ex: %d, got: %d\n",
525 memset(block_buffer, 0, bs);
527 memcpy(buffer, block_buffer + b, s);
534 #endif /* FAST_VERSION */
538 ext2_seek( struct boot_file_t* file,
542 return FILE_CANT_SEEK;
549 ext2_close( struct boot_file_t* file)
562 prom_close(file->of_device);
563 DEBUG_F("ext2_close called\n");
570 static unsigned int ext2_ino_size(struct boot_file_t *file)
572 struct ext2_inode ei;
574 if (ext2fs_read_inode(fs, file->inode, &ei))
580 static errcode_t linux_open (const char *name, int flags, io_channel * channel)
586 return EXT2_ET_BAD_DEVICE_NAME;
587 io = (io_channel) malloc (sizeof (struct struct_io_channel));
589 return EXT2_ET_BAD_DEVICE_NAME;
590 memset (io, 0, sizeof (struct struct_io_channel));
591 io->magic = EXT2_ET_MAGIC_IO_CHANNEL;
592 io->manager = linux_io_manager;
593 io->name = (char *) malloc (strlen (name) + 1);
594 strcpy (io->name, name);
603 static errcode_t linux_close (io_channel channel)
609 static errcode_t linux_set_blksize (io_channel channel, int blksize)
611 DEBUG_F("bs set to 0x%x\n", blksize);
612 channel->block_size = bs = blksize;
615 block_buffer = malloc(bs * 2);
620 static errcode_t linux_read_blk (io_channel channel, unsigned long block, int count, void *data)
623 unsigned long long tempb;
628 tempb = (((unsigned long long) block) *
629 ((unsigned long long)bs)) + (unsigned long long)doff;
631 * Only test tempb exceeding dend if dend is set to allow things
632 * like boot: hd:0,\xxxx
634 if (dend && tempb > dend) {
635 DEBUG_F("\nSeek error on block %lx, tempb=%Lx\n", block, tempb >> 9);
636 return EXT2_ET_LLSEEK_FAILED;
639 size = (count < 0) ? -count : count * bs;
640 prom_lseek(cur_file->of_device, tempb);
641 if (prom_read(cur_file->of_device, data, size) != size) {
642 DEBUG_F("\nRead error on block %ld\n", block);
643 return EXT2_ET_SHORT_READ;
648 static errcode_t linux_write_blk (io_channel channel, unsigned long block, int count, const void *data)
653 static errcode_t linux_flush (io_channel channel)
660 * c-file-style: "k&r"