11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * JFFS2 -- Journalling Flash File System, Version 2. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001-2003 Red Hat, Inc. 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Created by David Woodhouse <dwmw2@infradead.org> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * For licensing information, see the file 'LICENCE' in this directory. 91da177e4SLinus Torvalds * 10182ec4eeSThomas Gleixner * $Id: super.c,v 1.110 2005/11/07 11:14:42 gleixner Exp $ 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include <linux/kernel.h> 151da177e4SLinus Torvalds #include <linux/module.h> 161da177e4SLinus Torvalds #include <linux/slab.h> 171da177e4SLinus Torvalds #include <linux/init.h> 181da177e4SLinus Torvalds #include <linux/list.h> 191da177e4SLinus Torvalds #include <linux/fs.h> 201da177e4SLinus Torvalds #include <linux/mount.h> 211da177e4SLinus Torvalds #include <linux/jffs2.h> 221da177e4SLinus Torvalds #include <linux/pagemap.h> 231da177e4SLinus Torvalds #include <linux/mtd/mtd.h> 241da177e4SLinus Torvalds #include <linux/ctype.h> 251da177e4SLinus Torvalds #include <linux/namei.h> 261da177e4SLinus Torvalds #include "compr.h" 271da177e4SLinus Torvalds #include "nodelist.h" 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds static void jffs2_put_super(struct super_block *); 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds static kmem_cache_t *jffs2_inode_cachep; 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds static struct inode *jffs2_alloc_inode(struct super_block *sb) 341da177e4SLinus Torvalds { 351da177e4SLinus Torvalds struct jffs2_inode_info *ei; 361da177e4SLinus Torvalds ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, SLAB_KERNEL); 371da177e4SLinus Torvalds if (!ei) 381da177e4SLinus Torvalds return NULL; 391da177e4SLinus Torvalds return &ei->vfs_inode; 401da177e4SLinus Torvalds } 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds static void jffs2_destroy_inode(struct inode *inode) 431da177e4SLinus Torvalds { 441da177e4SLinus Torvalds kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode)); 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds static void jffs2_i_init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) 481da177e4SLinus Torvalds { 491da177e4SLinus Torvalds struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo; 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == 521da177e4SLinus Torvalds SLAB_CTOR_CONSTRUCTOR) { 5321eeb7aaSThomas Gleixner init_MUTEX(&ei->sem); 541da177e4SLinus Torvalds inode_init_once(&ei->vfs_inode); 551da177e4SLinus Torvalds } 561da177e4SLinus Torvalds } 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds static int jffs2_sync_fs(struct super_block *sb, int wait) 591da177e4SLinus Torvalds { 601da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds down(&c->alloc_sem); 631da177e4SLinus Torvalds jffs2_flush_wbuf_pad(c); 641da177e4SLinus Torvalds up(&c->alloc_sem); 651da177e4SLinus Torvalds return 0; 661da177e4SLinus Torvalds } 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds static struct super_operations jffs2_super_operations = 691da177e4SLinus Torvalds { 701da177e4SLinus Torvalds .alloc_inode = jffs2_alloc_inode, 711da177e4SLinus Torvalds .destroy_inode =jffs2_destroy_inode, 721da177e4SLinus Torvalds .read_inode = jffs2_read_inode, 731da177e4SLinus Torvalds .put_super = jffs2_put_super, 741da177e4SLinus Torvalds .write_super = jffs2_write_super, 751da177e4SLinus Torvalds .statfs = jffs2_statfs, 761da177e4SLinus Torvalds .remount_fs = jffs2_remount_fs, 771da177e4SLinus Torvalds .clear_inode = jffs2_clear_inode, 781da177e4SLinus Torvalds .dirty_inode = jffs2_dirty_inode, 791da177e4SLinus Torvalds .sync_fs = jffs2_sync_fs, 801da177e4SLinus Torvalds }; 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds static int jffs2_sb_compare(struct super_block *sb, void *data) 831da177e4SLinus Torvalds { 841da177e4SLinus Torvalds struct jffs2_sb_info *p = data; 851da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds /* The superblocks are considered to be equivalent if the underlying MTD 881da177e4SLinus Torvalds device is the same one */ 891da177e4SLinus Torvalds if (c->mtd == p->mtd) { 901da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_sb_compare: match on device %d (\"%s\")\n", p->mtd->index, p->mtd->name)); 911da177e4SLinus Torvalds return 1; 921da177e4SLinus Torvalds } else { 931da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_sb_compare: No match, device %d (\"%s\"), device %d (\"%s\")\n", 941da177e4SLinus Torvalds c->mtd->index, c->mtd->name, p->mtd->index, p->mtd->name)); 951da177e4SLinus Torvalds return 0; 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds } 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds static int jffs2_sb_set(struct super_block *sb, void *data) 1001da177e4SLinus Torvalds { 1011da177e4SLinus Torvalds struct jffs2_sb_info *p = data; 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds /* For persistence of NFS exports etc. we use the same s_dev 1041da177e4SLinus Torvalds each time we mount the device, don't just use an anonymous 1051da177e4SLinus Torvalds device */ 1061da177e4SLinus Torvalds sb->s_fs_info = p; 1071da177e4SLinus Torvalds p->os_priv = sb; 1081da177e4SLinus Torvalds sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, p->mtd->index); 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds return 0; 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds 113454e2398SDavid Howells static int jffs2_get_sb_mtd(struct file_system_type *fs_type, 1141da177e4SLinus Torvalds int flags, const char *dev_name, 115454e2398SDavid Howells void *data, struct mtd_info *mtd, 116454e2398SDavid Howells struct vfsmount *mnt) 1171da177e4SLinus Torvalds { 1181da177e4SLinus Torvalds struct super_block *sb; 1191da177e4SLinus Torvalds struct jffs2_sb_info *c; 1201da177e4SLinus Torvalds int ret; 1211da177e4SLinus Torvalds 122f8314dc6SPanagiotis Issaris c = kzalloc(sizeof(*c), GFP_KERNEL); 1231da177e4SLinus Torvalds if (!c) 124454e2398SDavid Howells return -ENOMEM; 1251da177e4SLinus Torvalds c->mtd = mtd; 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, c); 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds if (IS_ERR(sb)) 130454e2398SDavid Howells goto out_error; 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds if (sb->s_root) { 1331da177e4SLinus Torvalds /* New mountpoint for JFFS2 which is already mounted */ 1341da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): Device %d (\"%s\") is already mounted\n", 1351da177e4SLinus Torvalds mtd->index, mtd->name)); 136454e2398SDavid Howells ret = simple_set_mnt(mnt, sb); 1371da177e4SLinus Torvalds goto out_put; 1381da177e4SLinus Torvalds } 1391da177e4SLinus Torvalds 1401da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): New superblock for device %d (\"%s\")\n", 1411da177e4SLinus Torvalds mtd->index, mtd->name)); 1421da177e4SLinus Torvalds 143b6220598SArtem B. Bityuckiy /* Initialize JFFS2 superblock locks, the further initialization will be 144b6220598SArtem B. Bityuckiy * done later */ 145b6220598SArtem B. Bityuckiy init_MUTEX(&c->alloc_sem); 146b6220598SArtem B. Bityuckiy init_MUTEX(&c->erase_free_sem); 147b6220598SArtem B. Bityuckiy init_waitqueue_head(&c->erase_wait); 148b6220598SArtem B. Bityuckiy init_waitqueue_head(&c->inocache_wq); 149b6220598SArtem B. Bityuckiy spin_lock_init(&c->erase_completion_lock); 150b6220598SArtem B. Bityuckiy spin_lock_init(&c->inocache_lock); 151b6220598SArtem B. Bityuckiy 1521da177e4SLinus Torvalds sb->s_op = &jffs2_super_operations; 1531da177e4SLinus Torvalds sb->s_flags = flags | MS_NOATIME; 154aa98d7cfSKaiGai Kohei sb->s_xattr = jffs2_xattr_handlers; 155aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL 156aa98d7cfSKaiGai Kohei sb->s_flags |= MS_POSIXACL; 157aa98d7cfSKaiGai Kohei #endif 1589b04c997STheodore Ts'o ret = jffs2_do_fill_super(sb, data, flags & MS_SILENT ? 1 : 0); 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds if (ret) { 1611da177e4SLinus Torvalds /* Failure case... */ 1621da177e4SLinus Torvalds up_write(&sb->s_umount); 1631da177e4SLinus Torvalds deactivate_super(sb); 164454e2398SDavid Howells return ret; 1651da177e4SLinus Torvalds } 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds sb->s_flags |= MS_ACTIVE; 168454e2398SDavid Howells return simple_set_mnt(mnt, sb); 1691da177e4SLinus Torvalds 170454e2398SDavid Howells out_error: 171454e2398SDavid Howells ret = PTR_ERR(sb); 1721da177e4SLinus Torvalds out_put: 1731da177e4SLinus Torvalds kfree(c); 1741da177e4SLinus Torvalds put_mtd_device(mtd); 1751da177e4SLinus Torvalds 176454e2398SDavid Howells return ret; 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds 179454e2398SDavid Howells static int jffs2_get_sb_mtdnr(struct file_system_type *fs_type, 1801da177e4SLinus Torvalds int flags, const char *dev_name, 181454e2398SDavid Howells void *data, int mtdnr, 182454e2398SDavid Howells struct vfsmount *mnt) 1831da177e4SLinus Torvalds { 1841da177e4SLinus Torvalds struct mtd_info *mtd; 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds mtd = get_mtd_device(NULL, mtdnr); 1871da177e4SLinus Torvalds if (!mtd) { 1881da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr)); 189454e2398SDavid Howells return -EINVAL; 1901da177e4SLinus Torvalds } 1911da177e4SLinus Torvalds 192454e2398SDavid Howells return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt); 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds 195454e2398SDavid Howells static int jffs2_get_sb(struct file_system_type *fs_type, 1961da177e4SLinus Torvalds int flags, const char *dev_name, 197454e2398SDavid Howells void *data, struct vfsmount *mnt) 1981da177e4SLinus Torvalds { 1991da177e4SLinus Torvalds int err; 2001da177e4SLinus Torvalds struct nameidata nd; 2011da177e4SLinus Torvalds int mtdnr; 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds if (!dev_name) 204454e2398SDavid Howells return -EINVAL; 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_get_sb(): dev_name \"%s\"\n", dev_name)); 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds /* The preferred way of mounting in future; especially when 2091da177e4SLinus Torvalds CONFIG_BLK_DEV is implemented - we specify the underlying 2101da177e4SLinus Torvalds MTD device by number or by name, so that we don't require 2111da177e4SLinus Torvalds block device support to be present in the kernel. */ 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds /* FIXME: How to do the root fs this way? */ 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') { 2161da177e4SLinus Torvalds /* Probably mounting without the blkdev crap */ 2171da177e4SLinus Torvalds if (dev_name[3] == ':') { 2181da177e4SLinus Torvalds struct mtd_info *mtd; 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds /* Mount by MTD device name */ 2211da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd:%%s, name \"%s\"\n", dev_name+4)); 2221da177e4SLinus Torvalds for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) { 2231da177e4SLinus Torvalds mtd = get_mtd_device(NULL, mtdnr); 2241da177e4SLinus Torvalds if (mtd) { 2251da177e4SLinus Torvalds if (!strcmp(mtd->name, dev_name+4)) 226454e2398SDavid Howells return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt); 2271da177e4SLinus Torvalds put_mtd_device(mtd); 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds printk(KERN_NOTICE "jffs2_get_sb(): MTD device with name \"%s\" not found.\n", dev_name+4); 2311da177e4SLinus Torvalds } else if (isdigit(dev_name[3])) { 2321da177e4SLinus Torvalds /* Mount by MTD device number name */ 2331da177e4SLinus Torvalds char *endptr; 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds mtdnr = simple_strtoul(dev_name+3, &endptr, 0); 2361da177e4SLinus Torvalds if (!*endptr) { 2371da177e4SLinus Torvalds /* It was a valid number */ 2381da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd%%d, mtdnr %d\n", mtdnr)); 239454e2398SDavid Howells return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt); 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds /* Try the old way - the hack where we allowed users to mount 2451da177e4SLinus Torvalds /dev/mtdblock$(n) but didn't actually _use_ the blkdev */ 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_get_sb(): path_lookup() returned %d, inode %p\n", 2501da177e4SLinus Torvalds err, nd.dentry->d_inode)); 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds if (err) 253454e2398SDavid Howells return err; 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds err = -EINVAL; 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds if (!S_ISBLK(nd.dentry->d_inode->i_mode)) 2581da177e4SLinus Torvalds goto out; 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds if (nd.mnt->mnt_flags & MNT_NODEV) { 2611da177e4SLinus Torvalds err = -EACCES; 2621da177e4SLinus Torvalds goto out; 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds if (imajor(nd.dentry->d_inode) != MTD_BLOCK_MAJOR) { 2669b04c997STheodore Ts'o if (!(flags & MS_SILENT)) 2671da177e4SLinus Torvalds printk(KERN_NOTICE "Attempt to mount non-MTD device \"%s\" as JFFS2\n", 2681da177e4SLinus Torvalds dev_name); 2691da177e4SLinus Torvalds goto out; 2701da177e4SLinus Torvalds } 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds mtdnr = iminor(nd.dentry->d_inode); 2731da177e4SLinus Torvalds path_release(&nd); 2741da177e4SLinus Torvalds 275454e2398SDavid Howells return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt); 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds out: 2781da177e4SLinus Torvalds path_release(&nd); 279454e2398SDavid Howells return err; 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds static void jffs2_put_super (struct super_block *sb) 2831da177e4SLinus Torvalds { 2841da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds down(&c->alloc_sem); 2891da177e4SLinus Torvalds jffs2_flush_wbuf_pad(c); 2901da177e4SLinus Torvalds up(&c->alloc_sem); 291e631ddbaSFerenc Havasi 292e631ddbaSFerenc Havasi jffs2_sum_exit(c); 293e631ddbaSFerenc Havasi 2941da177e4SLinus Torvalds jffs2_free_ino_caches(c); 2951da177e4SLinus Torvalds jffs2_free_raw_node_refs(c); 2964ce1f562SFerenc Havasi if (jffs2_blocks_use_vmalloc(c)) 2971da177e4SLinus Torvalds vfree(c->blocks); 2981da177e4SLinus Torvalds else 2991da177e4SLinus Torvalds kfree(c->blocks); 3001da177e4SLinus Torvalds jffs2_flash_cleanup(c); 3011da177e4SLinus Torvalds kfree(c->inocache_list); 302aa98d7cfSKaiGai Kohei jffs2_clear_xattr_subsystem(c); 3031da177e4SLinus Torvalds if (c->mtd->sync) 3041da177e4SLinus Torvalds c->mtd->sync(c->mtd); 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_put_super returning\n")); 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds static void jffs2_kill_sb(struct super_block *sb) 3101da177e4SLinus Torvalds { 3111da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 312a69dde91SArtem B. Bityuckiy if (!(sb->s_flags & MS_RDONLY)) 313a69dde91SArtem B. Bityuckiy jffs2_stop_garbage_collect_thread(c); 3141da177e4SLinus Torvalds generic_shutdown_super(sb); 3151da177e4SLinus Torvalds put_mtd_device(c->mtd); 3161da177e4SLinus Torvalds kfree(c); 3171da177e4SLinus Torvalds } 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds static struct file_system_type jffs2_fs_type = { 3201da177e4SLinus Torvalds .owner = THIS_MODULE, 3211da177e4SLinus Torvalds .name = "jffs2", 3221da177e4SLinus Torvalds .get_sb = jffs2_get_sb, 3231da177e4SLinus Torvalds .kill_sb = jffs2_kill_sb, 3241da177e4SLinus Torvalds }; 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds static int __init init_jffs2_fs(void) 3271da177e4SLinus Torvalds { 3281da177e4SLinus Torvalds int ret; 3291da177e4SLinus Torvalds 3303e68fbb5SDavid Woodhouse /* Paranoia checks for on-medium structures. If we ask GCC 3313e68fbb5SDavid Woodhouse to pack them with __attribute__((packed)) then it _also_ 3323e68fbb5SDavid Woodhouse assumes that they're not aligned -- so it emits crappy 3333e68fbb5SDavid Woodhouse code on some architectures. Ideally we want an attribute 3343e68fbb5SDavid Woodhouse which means just 'no padding', without the alignment 3353e68fbb5SDavid Woodhouse thing. But GCC doesn't have that -- we have to just 3363e68fbb5SDavid Woodhouse hope the structs are the right sizes, instead. */ 3372ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12); 3382ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40); 3392ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); 3402ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); 3413e68fbb5SDavid Woodhouse 3421da177e4SLinus Torvalds printk(KERN_INFO "JFFS2 version 2.2." 3432f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER 3441da177e4SLinus Torvalds " (NAND)" 3451da177e4SLinus Torvalds #endif 346e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY 347e631ddbaSFerenc Havasi " (SUMMARY) " 348e631ddbaSFerenc Havasi #endif 3493e68fbb5SDavid Woodhouse " (C) 2001-2006 Red Hat, Inc.\n"); 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds jffs2_inode_cachep = kmem_cache_create("jffs2_i", 3521da177e4SLinus Torvalds sizeof(struct jffs2_inode_info), 353fffb60f9SPaul Jackson 0, (SLAB_RECLAIM_ACCOUNT| 354fffb60f9SPaul Jackson SLAB_MEM_SPREAD), 3551da177e4SLinus Torvalds jffs2_i_init_once, NULL); 3561da177e4SLinus Torvalds if (!jffs2_inode_cachep) { 3571da177e4SLinus Torvalds printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n"); 3581da177e4SLinus Torvalds return -ENOMEM; 3591da177e4SLinus Torvalds } 3601da177e4SLinus Torvalds ret = jffs2_compressors_init(); 3611da177e4SLinus Torvalds if (ret) { 3621da177e4SLinus Torvalds printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n"); 3631da177e4SLinus Torvalds goto out; 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds ret = jffs2_create_slab_caches(); 3661da177e4SLinus Torvalds if (ret) { 3671da177e4SLinus Torvalds printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n"); 3681da177e4SLinus Torvalds goto out_compressors; 3691da177e4SLinus Torvalds } 3701da177e4SLinus Torvalds ret = register_filesystem(&jffs2_fs_type); 3711da177e4SLinus Torvalds if (ret) { 3721da177e4SLinus Torvalds printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n"); 3731da177e4SLinus Torvalds goto out_slab; 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds return 0; 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds out_slab: 3781da177e4SLinus Torvalds jffs2_destroy_slab_caches(); 3791da177e4SLinus Torvalds out_compressors: 3801da177e4SLinus Torvalds jffs2_compressors_exit(); 3811da177e4SLinus Torvalds out: 3821da177e4SLinus Torvalds kmem_cache_destroy(jffs2_inode_cachep); 3831da177e4SLinus Torvalds return ret; 3841da177e4SLinus Torvalds } 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void) 3871da177e4SLinus Torvalds { 3881da177e4SLinus Torvalds unregister_filesystem(&jffs2_fs_type); 3891da177e4SLinus Torvalds jffs2_destroy_slab_caches(); 3901da177e4SLinus Torvalds jffs2_compressors_exit(); 3911da177e4SLinus Torvalds kmem_cache_destroy(jffs2_inode_cachep); 3921da177e4SLinus Torvalds } 3931da177e4SLinus Torvalds 3941da177e4SLinus Torvalds module_init(init_jffs2_fs); 3951da177e4SLinus Torvalds module_exit(exit_jffs2_fs); 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journalling Flash File System, v2"); 3981da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc."); 3991da177e4SLinus Torvalds MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for 4001da177e4SLinus Torvalds // the sake of this tag. It's Free Software. 401