X-Git-Url: http://git.ozlabs.org/?p=yaboot.git;a=blobdiff_plain;f=second%2Ffs_ext2.c;h=67571f28fadda668e967cde6e263a2ce37dda0a8;hp=b2ef127fa8abd95086c4a4410db887136efa0d3e;hb=fa877515ee56ce034ee8ae0d37994d9c6957e5ad;hpb=da7857367944c983abf98f956241dcc614b2f453 diff --git a/second/fs_ext2.c b/second/fs_ext2.c index b2ef127..67571f2 100644 --- a/second/fs_ext2.c +++ b/second/fs_ext2.c @@ -1,29 +1,29 @@ -/* ext2 filesystem - - Copyright (C) 1999 Benjamin Herrenschmidt - - Adapted from quik/silo - - Copyright (C) 1996 Maurizio Plaza - 1996 Jakub Jelinek - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - Note: This version is way too slow due to the way we use bmap. This - should be replaced by an iterator. -*/ +/* + * fs_ext2.c - an implementation for the Ext2/Ext3 filesystem + * + * Copyright (C) 2001, 2002 Ethan Benson + * + * Copyright (C) 1999 Benjamin Herrenschmidt + * + * Adapted from quik/silo + * + * Copyright (C) 1996 Maurizio Plaza + * 1996 Jakub Jelinek + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ #include "ctype.h" #include "types.h" @@ -35,6 +35,7 @@ #include "fs.h" #include "errors.h" #include "debug.h" +#include "bootinfo.h" #define FAST_VERSION #define MAX_READ_RANGE 256 @@ -65,7 +66,7 @@ struct fs_t ext2_filesystem = }; /* IO manager structure for the ext2 library */ - + static errcode_t linux_open (const char *name, int flags, io_channel * channel); static errcode_t linux_close (io_channel channel); static errcode_t linux_set_blksize (io_channel channel, int blksize); @@ -93,6 +94,7 @@ static io_manager linux_io_manager = &struct_linux_manager; static int opened = 0; /* We can't open twice ! */ static unsigned int bs; /* Blocksize */ static unsigned long long doff; /* Byte offset where partition starts */ +static unsigned long long dend; /* Byte offset where partition ends */ static ino_t root,cwd; static ext2_filsys fs = 0; static struct boot_file_t* cur_file; @@ -129,39 +131,48 @@ ext2_open( struct boot_file_t* file, int error = FILE_ERR_NOTFOUND; static char buffer[1024]; int ofopened = 0; - + DEBUG_ENTER; DEBUG_OPEN; if (opened) { - prom_printf("ext2_open() : fs busy\n"); DEBUG_LEAVE(FILE_ERR_FSBUSY); return FILE_ERR_FSBUSY; } if (file->device_kind != FILE_DEVICE_BLOCK) { - prom_printf("Can't open ext2 filesystem on non-block device\n"); DEBUG_LEAVE(FILE_ERR_BADDEV); return FILE_ERR_BADDEV; } fs = NULL; - + /* We don't care too much about the device block size since we run * thru the deblocker. We may have to change that is we plan to be * compatible with older versions of OF */ bs = 1024; - doff = 0; - if (part) + + /* + * On the other hand, we do care about the actual size of the + * partition, reads or seeks past the end may cause undefined + * behavior on some devices. A netapp that tries to seek and + * read past the end of the lun takes ~30 secs to recover per + * attempt. + */ + doff = dend = 0; + if (part) { doff = (unsigned long long)(part->part_start) * part->blocksize; + dend = doff + (unsigned long long)part->part_size * part->blocksize; + } cur_file = file; - DEBUG_F("partition offset: %Lu\n", doff); + DEBUG_F("partition offset: %Lx, end: %Lx\n", doff, dend); /* Open the OF device for the entire disk */ strncpy(buffer, dev_name, 1020); - strcat(buffer, ":0"); + if (_machine != _MACH_bplan) + strcat(buffer, ":0"); DEBUG_F("<%s>\n", buffer); @@ -176,7 +187,7 @@ ext2_open( struct boot_file_t* file, return FILE_IOERR; } ofopened = 1; - + /* Open the ext2 filesystem */ result = ext2fs_open (buffer, EXT2_FLAG_RW, 0, 0, linux_io_manager, &fs); if (result) { @@ -203,7 +214,7 @@ ext2_open( struct boot_file_t* file, error = FILE_IOERR; goto bail; } - + /* Lookup file by pathname */ root = cwd = EXT2_ROOT_INO; result = ext2fs_namei_follow(fs, root, cwd, file_name, &file->inode); @@ -227,7 +238,7 @@ ext2_open( struct boot_file_t* file, error = FILE_ERR_NOTFOUND; goto bail; } -#endif +#endif #ifndef FAST_VERSION result = ext2fs_read_inode(fs, file->inode, &cur_inode); @@ -246,7 +257,7 @@ ext2_open( struct boot_file_t* file, } #endif /* FAST_VERSION */ file->pos = 0; - + opened = 1; bail: if (!opened) { @@ -259,7 +270,7 @@ bail: free(block_buffer); block_buffer = NULL; cur_file = NULL; - + DEBUG_LEAVE_F(error); return error; } @@ -284,7 +295,7 @@ read_dump_range(void) if ((count * bs) > read_max) count--; if (count) { - size = count * bs; + size = count * bs; read_result = io_channel_read_blk(fs->io, read_range_start, count, read_buffer); if (read_result) return BLOCK_ABORT; @@ -295,7 +306,7 @@ read_dump_range(void) read_range_count -= count; read_range_start += count; read_last_logical += count; - } + } /* Handle remaining block */ if (read_max && read_range_count) { read_result = io_channel_read_blk(fs->io, read_range_start, 1, block_buffer); @@ -345,7 +356,7 @@ read_iterator(ext2_filsys fs, blk_t *blocknr, int lg_block, void *private) ++read_range_count; return ((read_range_count * bs) >= read_max) ? BLOCK_ABORT : 0; } - + /* Range doesn't match. Dump existing range */ if (read_range_start) { #ifdef VERBOSE_DEBUG @@ -420,7 +431,7 @@ read_iterator(ext2_filsys fs, blk_t *blocknr, int lg_block, void *private) read_range_count = 1; return (bs >= read_max) ? BLOCK_ABORT : 0; } - + #ifdef VERBOSE_DEBUG DEBUG_F("\n"); #endif @@ -452,7 +463,7 @@ ext2_read( struct boot_file_t* file, read_max = size; read_buffer = (unsigned char*)buffer; read_result = 0; - + retval = ext2fs_block_iterate(fs, file->inode, 0, 0, read_iterator, 0); if (retval == BLOCK_ABORT) retval = read_result; @@ -466,13 +477,13 @@ ext2_read( struct boot_file_t* file, } if (retval) prom_printf ("ext2: i/o error %ld in read\n", (long) retval); - + return read_total; #else /* FAST_VERSION */ int status; unsigned int read = 0; - + if (!opened) return FILE_IOERR; @@ -480,11 +491,11 @@ ext2_read( struct boot_file_t* file, DEBUG_F("ext_read() from pos 0x%x, size: 0x%x\n", file->pos, size); - while(size) { + while(size) { blk_t fblock = file->pos / bs; blk_t pblock; unsigned int blkorig, s, b; - + pblock = 0; status = ext2fs_bmap(fs, file->inode, &cur_inode, block_buffer, 0, fblock, &pblock); @@ -517,7 +528,7 @@ ext2_read( struct boot_file_t* file, file->pos += s; } return read; -#endif /* FAST_VERSION */ +#endif /* FAST_VERSION */ } static int @@ -544,12 +555,12 @@ ext2_close( struct boot_file_t* file) if (fs) ext2fs_close(fs); fs = NULL; - + prom_close(file->of_device); DEBUG_F("ext2_close called\n"); opened = 0; - + return 0; } @@ -584,11 +595,12 @@ static errcode_t linux_close (io_channel channel) static errcode_t linux_set_blksize (io_channel channel, int blksize) { + DEBUG_F("bs set to 0x%x\n", blksize); channel->block_size = bs = blksize; if (block_buffer) { free(block_buffer); block_buffer = malloc(bs * 2); - } + } return 0; } @@ -599,9 +611,18 @@ static errcode_t linux_read_blk (io_channel channel, unsigned long block, int co if (count == 0) return 0; - + tempb = (((unsigned long long) block) * ((unsigned long long)bs)) + (unsigned long long)doff; + /* + * Only test tempb exceeding dend if dend is set to allow things + * like boot: hd:0,\xxxx + */ + if (dend && tempb > dend) { + DEBUG_F("\nSeek error on block %lx, tempb=%Lx\n", block, tempb >> 9); + return EXT2_ET_LLSEEK_FAILED; + } + size = (count < 0) ? -count : count * bs; prom_lseek(cur_file->of_device, tempb); if (prom_read(cur_file->of_device, data, size) != size) { @@ -621,7 +642,7 @@ static errcode_t linux_flush (io_channel channel) return 0; } -/* +/* * Local variables: * c-file-style: "k&r" * c-basic-offset: 5