diff options
Diffstat (limited to 'fs/ext2/super.c')
-rw-r--r-- | fs/ext2/super.c | 69 |
1 files changed, 53 insertions, 16 deletions
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 6bcdb5e20..26e18852e 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -32,6 +32,8 @@ #include <linux/stat.h> #include <linux/string.h> #include <linux/locks.h> +#include <linux/blkdev.h> +#include <linux/init.h> static char error_buf[1024]; @@ -129,7 +131,7 @@ void ext2_put_super (struct super_block * sb) return; } -static struct super_operations ext2_sops = { +static struct super_operations ext2_sops = { ext2_read_inode, NULL, ext2_write_inode, @@ -377,10 +379,26 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, unsigned short resuid = EXT2_DEF_RESUID; unsigned short resgid = EXT2_DEF_RESGID; unsigned long logic_sb_block = 1; + unsigned long offset = 0; kdev_t dev = sb->s_dev; + int blocksize = BLOCK_SIZE; + int hblock; int db_count; int i, j; + /* + * See what the current blocksize for the device is, and + * use that as the blocksize. Otherwise (or if the blocksize + * is smaller than the default) use the default. + * This is important for devices that have a hardware + * sectorsize that is larger than the default. + */ + blocksize = get_hardblocksize(dev); + if( blocksize == 0 || blocksize < BLOCK_SIZE ) + { + blocksize = BLOCK_SIZE; + } + sb->u.ext2_sb.s_mount_opt = 0; set_opt (sb->u.ext2_sb.s_mount_opt, CHECK_NORMAL); if (!parse_options ((char *) data, &sb_block, &resuid, &resgid, @@ -391,8 +409,19 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, MOD_INC_USE_COUNT; lock_super (sb); - set_blocksize (dev, BLOCK_SIZE); - if (!(bh = bread (dev, sb_block, BLOCK_SIZE))) { + set_blocksize (dev, blocksize); + + /* + * If the superblock doesn't start on a sector boundary, + * calculate the offset. FIXME(eric) this doesn't make sense + * that we would have to do this. + */ + if (blocksize != BLOCK_SIZE) { + logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize; + offset = (sb_block*BLOCK_SIZE) % blocksize; + } + + if (!(bh = bread (dev, logic_sb_block, blocksize))) { sb->s_dev = 0; unlock_super (sb); printk ("EXT2-fs: unable to read superblock\n"); @@ -403,7 +432,7 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, * Note: s_es must be initialized s_es as soon as possible because * some ext2 macro-instructions depend on its value */ - es = (struct ext2_super_block *) bh->b_data; + es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); sb->u.ext2_sb.s_es = es; sb->s_magic = le16_to_cpu(es->s_magic); if (sb->s_magic != EXT2_SUPER_MAGIC) { @@ -421,24 +450,34 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, if (le32_to_cpu(es->s_rev_level) > EXT2_GOOD_OLD_REV) { if (le32_to_cpu(es->s_feature_incompat) & ~EXT2_FEATURE_INCOMPAT_SUPP) { printk("EXT2-fs: %s: couldn't mount because of " - "unsupported optional features.\n", + "unsupported optional features.\n", kdevname(dev)); goto failed_mount; } if (!(sb->s_flags & MS_RDONLY) && (le32_to_cpu(es->s_feature_ro_compat) & ~EXT2_FEATURE_RO_COMPAT_SUPP)) { printk("EXT2-fs: %s: couldn't mount RDWR because of " - "unsupported optional features.\n", + "unsupported optional features.\n", kdevname(dev)); goto failed_mount; } } sb->s_blocksize_bits = le32_to_cpu(sb->u.ext2_sb.s_es->s_log_block_size) + 10; sb->s_blocksize = 1 << sb->s_blocksize_bits; - if (sb->s_blocksize != BLOCK_SIZE && - (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 || + if (sb->s_blocksize != BLOCK_SIZE && + (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 || sb->s_blocksize == 4096)) { - unsigned long offset; + /* + * Make sure the blocksize for the filesystem is larger + * than the hardware sectorsize for the machine. + */ + hblock = get_hardblocksize(dev); + if( (hblock != 0) + && (sb->s_blocksize < hblock) ) + { + printk("EXT2-fs: blocksize too small for device.\n"); + goto failed_mount; + } brelse (bh); set_blocksize (dev, sb->s_blocksize); @@ -675,7 +714,7 @@ int ext2_remount (struct super_block * sb, int * flags, char * data) else { /* * Mounting a RDONLY partition read-write, so reread and - * store the current valid flag. (It may have been changed + * store the current valid flag. (It may have been changed * by e2fsck since we originally mounted the partition.) */ sb->u.ext2_sb.s_mount_state = le16_to_cpu(es->s_state); @@ -689,19 +728,17 @@ static struct file_system_type ext2_fs_type = { ext2_read_super, "ext2", 1, NULL }; -int init_ext2_fs(void) +__initfunc(int init_ext2_fs(void)) { return register_filesystem(&ext2_fs_type); } #ifdef MODULE +EXPORT_NO_SYMBOLS; + int init_module(void) { - int status; - - if ((status = init_ext2_fs()) == 0) - register_symtab(0); - return status; + return init_ext2_fs(); } void cleanup_module(void) |