X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fjffs2%2Fsuper.c;h=08a0e6c49e61d77b4d51b03714108df0b0840462;hb=refs%2Fheads%2Fvserver;hp=b657c55d5f51fac0660da622ca5adf104139c984;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index b657c55d5..08a0e6c49 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -3,37 +3,38 @@ * * Copyright (C) 2001-2003 Red Hat, Inc. * - * Created by David Woodhouse + * Created by David Woodhouse * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: super.c,v 1.90 2003/10/11 11:47:23 dwmw2 Exp $ + * $Id: super.c,v 1.110 2005/11/07 11:14:42 gleixner Exp $ * */ -#include #include #include #include #include #include #include +#include #include #include #include #include #include #include +#include "compr.h" #include "nodelist.h" static void jffs2_put_super(struct super_block *); -static kmem_cache_t *jffs2_inode_cachep; +static struct kmem_cache *jffs2_inode_cachep; static struct inode *jffs2_alloc_inode(struct super_block *sb) { struct jffs2_inode_info *ei; - ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, SLAB_KERNEL); + ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL); if (!ei) return NULL; return &ei->vfs_inode; @@ -44,17 +45,27 @@ static void jffs2_destroy_inode(struct inode *inode) kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode)); } -static void jffs2_i_init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) +static void jffs2_i_init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) { struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo; if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { - init_MUTEX_LOCKED(&ei->sem); + init_MUTEX(&ei->sem); inode_init_once(&ei->vfs_inode); } } +static int jffs2_sync_fs(struct super_block *sb, int wait) +{ + struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); + + down(&c->alloc_sem); + jffs2_flush_wbuf_pad(c); + up(&c->alloc_sem); + return 0; +} + static struct super_operations jffs2_super_operations = { .alloc_inode = jffs2_alloc_inode, @@ -66,6 +77,7 @@ static struct super_operations jffs2_super_operations = .remount_fs = jffs2_remount_fs, .clear_inode = jffs2_clear_inode, .dirty_inode = jffs2_dirty_inode, + .sync_fs = jffs2_sync_fs, }; static int jffs2_sb_compare(struct super_block *sb, void *data) @@ -99,88 +111,104 @@ static int jffs2_sb_set(struct super_block *sb, void *data) return 0; } -static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data, struct mtd_info *mtd) +static int jffs2_get_sb_mtd(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct mtd_info *mtd, + struct vfsmount *mnt) { struct super_block *sb; struct jffs2_sb_info *c; int ret; - c = kmalloc(sizeof(*c), GFP_KERNEL); + c = kzalloc(sizeof(*c), GFP_KERNEL); if (!c) - return ERR_PTR(-ENOMEM); - memset(c, 0, sizeof(*c)); + return -ENOMEM; c->mtd = mtd; sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, c); if (IS_ERR(sb)) - goto out_put; + goto out_error; if (sb->s_root) { /* New mountpoint for JFFS2 which is already mounted */ D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): Device %d (\"%s\") is already mounted\n", mtd->index, mtd->name)); + ret = simple_set_mnt(mnt, sb); goto out_put; } D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): New superblock for device %d (\"%s\")\n", mtd->index, mtd->name)); - sb->s_op = &jffs2_super_operations; - sb->s_flags |= MS_NOATIME; + /* Initialize JFFS2 superblock locks, the further initialization will be + * done later */ + init_MUTEX(&c->alloc_sem); + init_MUTEX(&c->erase_free_sem); + init_waitqueue_head(&c->erase_wait); + init_waitqueue_head(&c->inocache_wq); + spin_lock_init(&c->erase_completion_lock); + spin_lock_init(&c->inocache_lock); - ret = jffs2_do_fill_super(sb, data, (flags&MS_VERBOSE)?1:0); + sb->s_op = &jffs2_super_operations; + sb->s_flags = flags | MS_NOATIME; + sb->s_xattr = jffs2_xattr_handlers; +#ifdef CONFIG_JFFS2_FS_POSIX_ACL + sb->s_flags |= MS_POSIXACL; +#endif + ret = jffs2_do_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); if (ret) { /* Failure case... */ up_write(&sb->s_umount); deactivate_super(sb); - return ERR_PTR(ret); + return ret; } sb->s_flags |= MS_ACTIVE; - return sb; + return simple_set_mnt(mnt, sb); +out_error: + ret = PTR_ERR(sb); out_put: kfree(c); put_mtd_device(mtd); - return sb; + return ret; } -static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data, int mtdnr) +static int jffs2_get_sb_mtdnr(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, int mtdnr, + struct vfsmount *mnt) { struct mtd_info *mtd; mtd = get_mtd_device(NULL, mtdnr); - if (!mtd) { + if (IS_ERR(mtd)) { D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr)); - return ERR_PTR(-EINVAL); + return PTR_ERR(mtd); } - return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd); + return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt); } -static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) +static int jffs2_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) { int err; struct nameidata nd; int mtdnr; if (!dev_name) - return ERR_PTR(-EINVAL); + return -EINVAL; D1(printk(KERN_DEBUG "jffs2_get_sb(): dev_name \"%s\"\n", dev_name)); /* The preferred way of mounting in future; especially when CONFIG_BLK_DEV is implemented - we specify the underlying - MTD device by number or by name, so that we don't require + MTD device by number or by name, so that we don't require block device support to be present in the kernel. */ /* FIXME: How to do the root fs this way? */ @@ -194,9 +222,9 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd:%%s, name \"%s\"\n", dev_name+4)); for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) { mtd = get_mtd_device(NULL, mtdnr); - if (mtd) { + if (!IS_ERR(mtd)) { if (!strcmp(mtd->name, dev_name+4)) - return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd); + return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt); put_mtd_device(mtd); } } @@ -204,17 +232,17 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, } else if (isdigit(dev_name[3])) { /* Mount by MTD device number name */ char *endptr; - + mtdnr = simple_strtoul(dev_name+3, &endptr, 0); if (!*endptr) { /* It was a valid number */ D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd%%d, mtdnr %d\n", mtdnr)); - return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr); + return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt); } } } - /* Try the old way - the hack where we allowed users to mount + /* Try the old way - the hack where we allowed users to mount /dev/mtdblock$(n) but didn't actually _use_ the blkdev */ err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); @@ -223,7 +251,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, err, nd.dentry->d_inode)); if (err) - return ERR_PTR(err); + return err; err = -EINVAL; @@ -236,7 +264,7 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, } if (imajor(nd.dentry->d_inode) != MTD_BLOCK_MAJOR) { - if (!(flags & MS_VERBOSE)) /* Yes I mean this. Strangely */ + if (!(flags & MS_SILENT)) printk(KERN_NOTICE "Attempt to mount non-MTD device \"%s\" as JFFS2\n", dev_name); goto out; @@ -245,11 +273,11 @@ static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, mtdnr = iminor(nd.dentry->d_inode); path_release(&nd); - return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr); + return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt); out: path_release(&nd); - return ERR_PTR(err); + return err; } static void jffs2_put_super (struct super_block *sb) @@ -258,16 +286,21 @@ static void jffs2_put_super (struct super_block *sb) D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); - if (!(sb->s_flags & MS_RDONLY)) - jffs2_stop_garbage_collect_thread(c); down(&c->alloc_sem); jffs2_flush_wbuf_pad(c); up(&c->alloc_sem); + + jffs2_sum_exit(c); + jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); - kfree(c->blocks); - jffs2_nand_flash_cleanup(c); + if (jffs2_blocks_use_vmalloc(c)) + vfree(c->blocks); + else + kfree(c->blocks); + jffs2_flash_cleanup(c); kfree(c->inocache_list); + jffs2_clear_xattr_subsystem(c); if (c->mtd->sync) c->mtd->sync(c->mtd); @@ -277,6 +310,8 @@ static void jffs2_put_super (struct super_block *sb) static void jffs2_kill_sb(struct super_block *sb) { struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); + if (!(sb->s_flags & MS_RDONLY)) + jffs2_stop_garbage_collect_thread(c); generic_shutdown_super(sb); put_mtd_device(c->mtd); kfree(c); @@ -293,29 +328,45 @@ static int __init init_jffs2_fs(void) { int ret; + /* Paranoia checks for on-medium structures. If we ask GCC + to pack them with __attribute__((packed)) then it _also_ + assumes that they're not aligned -- so it emits crappy + code on some architectures. Ideally we want an attribute + which means just 'no padding', without the alignment + thing. But GCC doesn't have that -- we have to just + hope the structs are the right sizes, instead. */ + BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12); + BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40); + BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); + BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); + printk(KERN_INFO "JFFS2 version 2.2." -#ifdef CONFIG_FS_JFFS2_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER " (NAND)" #endif - " (C) 2001-2003 Red Hat, Inc.\n"); +#ifdef CONFIG_JFFS2_SUMMARY + " (SUMMARY) " +#endif + " (C) 2001-2006 Red Hat, Inc.\n"); jffs2_inode_cachep = kmem_cache_create("jffs2_i", sizeof(struct jffs2_inode_info), - 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, + 0, (SLAB_RECLAIM_ACCOUNT| + SLAB_MEM_SPREAD), jffs2_i_init_once, NULL); if (!jffs2_inode_cachep) { printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n"); return -ENOMEM; } - ret = jffs2_zlib_init(); + ret = jffs2_compressors_init(); if (ret) { - printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n"); + printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n"); goto out; } ret = jffs2_create_slab_caches(); if (ret) { printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n"); - goto out_zlib; + goto out_compressors; } ret = register_filesystem(&jffs2_fs_type); if (ret) { @@ -326,9 +377,10 @@ static int __init init_jffs2_fs(void) out_slab: jffs2_destroy_slab_caches(); - out_zlib: - jffs2_zlib_exit(); + out_compressors: + jffs2_compressors_exit(); out: + kmem_cache_destroy(jffs2_inode_cachep); return ret; } @@ -336,7 +388,7 @@ static void __exit exit_jffs2_fs(void) { unregister_filesystem(&jffs2_fs_type); jffs2_destroy_slab_caches(); - jffs2_zlib_exit(); + jffs2_compressors_exit(); kmem_cache_destroy(jffs2_inode_cachep); } @@ -345,5 +397,5 @@ module_exit(exit_jffs2_fs); MODULE_DESCRIPTION("The Journalling Flash File System, v2"); MODULE_AUTHOR("Red Hat, Inc."); -MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for +MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for // the sake of this tag. It's Free Software.