diff -urN B9-pages/fs/cramfs/inode.c B9-cramfs2/fs/cramfs/inode.c --- B9-pages/fs/cramfs/inode.c Wed Nov 5 18:23:04 2003 +++ B9-cramfs2/fs/cramfs/inode.c Wed Nov 5 18:29:13 2003 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -113,7 +114,8 @@ */ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned int len) { - struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; + struct cramfs_sb_info *sbi = sb->s_fs_info; + struct address_space *mapping = sbi->mapping; struct page *pages[BLKS_PER_BUF]; unsigned i, blocknr, buffer, unread; unsigned long devsize; @@ -149,7 +151,7 @@ if (blocknr + i < devsize) { page = read_cache_page(mapping, blocknr + i, (filler_t *)mapping->a_ops->readpage, - NULL); + sbi->file); /* synchronous error? */ if (IS_ERR(page)) page = NULL; @@ -188,24 +190,15 @@ return read_buffers[buffer] + offset; } -static void cramfs_put_super(struct super_block *sb) -{ - kfree(sb->s_fs_info); - sb->s_fs_info = NULL; -} - -static int cramfs_fill_super(struct super_block *sb, void *data, int silent) +static int cramfs_set_super(struct super_block *sb, void *data, int silent) { int i; struct cramfs_super super; unsigned long root_offset; - struct cramfs_sb_info *sbi; + struct cramfs_sb_info *sbi = sb->s_fs_info; - sbi = kmalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL); - if (!sbi) - return -ENOMEM; - sb->s_fs_info = sbi; - memset(sbi, 0, sizeof(struct cramfs_sb_info)); + if (!sbi->mapping->a_ops->readpage) + return -EINVAL; down(&read_mutex); /* Invalidate the read buffers on mount: think disk change.. */ @@ -225,20 +218,20 @@ if (super.magic != CRAMFS_MAGIC) { if (!silent) printk(KERN_ERR "cramfs: wrong magic\n"); - goto out; + return -EINVAL; } } /* get feature flags first */ if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) { printk(KERN_ERR "cramfs: unsupported filesystem features\n"); - goto out; + return -EINVAL; } /* Check that the root inode is in a sane state */ if (!S_ISDIR(super.root.mode)) { printk(KERN_ERR "cramfs: root is not a directory\n"); - goto out; + return -EINVAL; } root_offset = super.root.offset << 2; if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) { @@ -259,17 +252,27 @@ (root_offset != 512 + sizeof(struct cramfs_super)))) { printk(KERN_ERR "cramfs: bad root offset %lu\n", root_offset); - goto out; + return -EINVAL; } /* Set it all up.. */ sb->s_op = &cramfs_ops; sb->s_root = d_alloc_root(get_cramfs_inode(sb, &super.root)); return 0; -out: - kfree(sbi); - sb->s_fs_info = NULL; - return -EINVAL; +} + +static int cramfs_fill_super(struct super_block *sb, void *data, int silent) +{ + struct cramfs_sb_info *sbi; + + sbi = kmalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL); + if (!sbi) + return -ENOMEM; + memset(sbi, 0, sizeof(struct cramfs_sb_info)); + sbi->mapping = sb->s_bdev->bd_inode->i_mapping; + sb->s_fs_info = sbi; + + return cramfs_set_super(sb, data, silent); } static int cramfs_statfs(struct super_block *sb, struct kstatfs *buf) @@ -465,34 +468,117 @@ }; static struct super_operations cramfs_ops = { - .put_super = cramfs_put_super, .statfs = cramfs_statfs, }; static struct super_block *cramfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { + if (!(flags & MS_RDONLY)) + return ERR_PTR(-EROFS); return get_sb_bdev(fs_type, flags, dev_name, data, cramfs_fill_super); } +static void cramfs_kill_sb(struct super_block *sb) +{ + void *private = sb->s_fs_info; + sb->s_fs_info = NULL; + kill_block_super(sb); + kfree(private); +} + +static struct super_block *cramfs2_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + struct cramfs_sb_info *sbi; + struct file *file; + struct super_block *s; + int error = 0; + + if (!(flags & MS_RDONLY)) + return ERR_PTR(-EROFS); + + sbi = kmalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL); + if (!sbi) + return ERR_PTR(-ENOMEM); + + file = filp_open(dev_name, O_RDONLY, 0); + if (IS_ERR(file)) { + s = (struct super_block *)file; + goto out; + } + + s = sget(fs_type, NULL, set_anon_super, NULL); + if (IS_ERR(s)) + goto out1; + + s->s_flags = flags; + + memset(sbi, 0, sizeof(struct cramfs_sb_info)); + sbi->mapping = file->f_dentry->d_inode->i_mapping; + sbi->file = file; + + s->s_fs_info = sbi; + + error = cramfs_set_super(s, data, flags & MS_VERBOSE ? 1 : 0); + if (error) { + up_write(&s->s_umount); + deactivate_super(s); + return ERR_PTR(error); + } + s->s_flags |= MS_ACTIVE; + return s; +out1: + fput(file); +out: + kfree(sbi); + return s; +} + +static void cramfs2_kill_sb(struct super_block *sb) +{ + struct cramfs_sb_info *sbi = sb->s_fs_info; + sb->s_fs_info = NULL; + kill_anon_super(sb); + fput(sbi->file); + kfree(sbi); +} + static struct file_system_type cramfs_fs_type = { .owner = THIS_MODULE, .name = "cramfs", .get_sb = cramfs_get_sb, - .kill_sb = kill_block_super, + .kill_sb = cramfs_kill_sb, .fs_flags = FS_REQUIRES_DEV, }; +static struct file_system_type cramfs2_fs_type = { + .owner = THIS_MODULE, + .name = "cramfs2", + .get_sb = cramfs2_get_sb, + .kill_sb = cramfs2_kill_sb, +}; + static int __init init_cramfs_fs(void) { + int err; cramfs_uncompress_init(); - return register_filesystem(&cramfs_fs_type); + err = register_filesystem(&cramfs_fs_type); + if (!err) { + err = register_filesystem(&cramfs2_fs_type); + if (!err) + return 0; + unregister_filesystem(&cramfs_fs_type); + } + cramfs_uncompress_exit(); + return err; } static void __exit exit_cramfs_fs(void) { cramfs_uncompress_exit(); unregister_filesystem(&cramfs_fs_type); + unregister_filesystem(&cramfs2_fs_type); } module_init(init_cramfs_fs) diff -urN B9-pages/include/linux/cramfs_fs_sb.h B9-cramfs2/include/linux/cramfs_fs_sb.h --- B9-pages/include/linux/cramfs_fs_sb.h Sat Oct 12 00:55:25 2002 +++ B9-cramfs2/include/linux/cramfs_fs_sb.h Wed Nov 5 18:27:57 2003 @@ -5,11 +5,13 @@ * cramfs super-block data in memory */ struct cramfs_sb_info { - unsigned long magic; - unsigned long size; - unsigned long blocks; - unsigned long files; - unsigned long flags; + struct address_space *mapping; + struct file *file; + unsigned long magic; + unsigned long size; + unsigned long blocks; + unsigned long files; + unsigned long flags; }; static inline struct cramfs_sb_info *CRAMFS_SB(struct super_block *sb)