11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * JFFS2 -- Journalling Flash File System, Version 2. 31da177e4SLinus Torvalds * 4c00c310eSDavid Woodhouse * Copyright © 2001-2007 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 * 101da177e4SLinus Torvalds */ 111da177e4SLinus Torvalds 125a528957SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 135a528957SJoe Perches 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> 209c74034fSArtem Bityutskiy #include <linux/err.h> 211da177e4SLinus Torvalds #include <linux/mount.h> 2292abc475SAndres Salomon #include <linux/parser.h> 231da177e4SLinus Torvalds #include <linux/jffs2.h> 241da177e4SLinus Torvalds #include <linux/pagemap.h> 25acaebfd8SDavid Howells #include <linux/mtd/super.h> 261da177e4SLinus Torvalds #include <linux/ctype.h> 271da177e4SLinus Torvalds #include <linux/namei.h> 2892abc475SAndres Salomon #include <linux/seq_file.h> 295f556aabSDavid Woodhouse #include <linux/exportfs.h> 301da177e4SLinus Torvalds #include "compr.h" 311da177e4SLinus Torvalds #include "nodelist.h" 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds static void jffs2_put_super(struct super_block *); 341da177e4SLinus Torvalds 35e18b890bSChristoph Lameter static struct kmem_cache *jffs2_inode_cachep; 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds static struct inode *jffs2_alloc_inode(struct super_block *sb) 381da177e4SLinus Torvalds { 394e571abaSDavid Woodhouse struct jffs2_inode_info *f; 404e571abaSDavid Woodhouse 414e571abaSDavid Woodhouse f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL); 424e571abaSDavid Woodhouse if (!f) 431da177e4SLinus Torvalds return NULL; 444e571abaSDavid Woodhouse return &f->vfs_inode; 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds 47fa0d7e3dSNick Piggin static void jffs2_i_callback(struct rcu_head *head) 48fa0d7e3dSNick Piggin { 49fa0d7e3dSNick Piggin struct inode *inode = container_of(head, struct inode, i_rcu); 504fdcfab5SAl Viro struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); 514fdcfab5SAl Viro 524fdcfab5SAl Viro kfree(f->target); 534fdcfab5SAl Viro kmem_cache_free(jffs2_inode_cachep, f); 54fa0d7e3dSNick Piggin } 55fa0d7e3dSNick Piggin 561da177e4SLinus Torvalds static void jffs2_destroy_inode(struct inode *inode) 571da177e4SLinus Torvalds { 58fa0d7e3dSNick Piggin call_rcu(&inode->i_rcu, jffs2_i_callback); 591da177e4SLinus Torvalds } 601da177e4SLinus Torvalds 6151cc5068SAlexey Dobriyan static void jffs2_i_init_once(void *foo) 621da177e4SLinus Torvalds { 634e571abaSDavid Woodhouse struct jffs2_inode_info *f = foo; 641da177e4SLinus Torvalds 654e571abaSDavid Woodhouse mutex_init(&f->sem); 664e571abaSDavid Woodhouse inode_init_once(&f->vfs_inode); 671da177e4SLinus Torvalds } 681da177e4SLinus Torvalds 6992abc475SAndres Salomon static const char *jffs2_compr_name(unsigned int compr) 7092abc475SAndres Salomon { 7192abc475SAndres Salomon switch (compr) { 7292abc475SAndres Salomon case JFFS2_COMPR_MODE_NONE: 7392abc475SAndres Salomon return "none"; 74123005f3SAndres Salomon #ifdef CONFIG_JFFS2_LZO 75123005f3SAndres Salomon case JFFS2_COMPR_MODE_FORCELZO: 76123005f3SAndres Salomon return "lzo"; 77123005f3SAndres Salomon #endif 78123005f3SAndres Salomon #ifdef CONFIG_JFFS2_ZLIB 79123005f3SAndres Salomon case JFFS2_COMPR_MODE_FORCEZLIB: 80123005f3SAndres Salomon return "zlib"; 81123005f3SAndres Salomon #endif 8292abc475SAndres Salomon default: 8392abc475SAndres Salomon /* should never happen; programmer error */ 8492abc475SAndres Salomon WARN_ON(1); 8592abc475SAndres Salomon return ""; 8692abc475SAndres Salomon } 8792abc475SAndres Salomon } 8892abc475SAndres Salomon 8934c80b1dSAl Viro static int jffs2_show_options(struct seq_file *s, struct dentry *root) 9092abc475SAndres Salomon { 9134c80b1dSAl Viro struct jffs2_sb_info *c = JFFS2_SB_INFO(root->d_sb); 9292abc475SAndres Salomon struct jffs2_mount_opts *opts = &c->mount_opts; 9392abc475SAndres Salomon 9492abc475SAndres Salomon if (opts->override_compr) 9592abc475SAndres Salomon seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr)); 968da8ba2eSDaniel Drake if (opts->rp_size) 978da8ba2eSDaniel Drake seq_printf(s, ",rp_size=%u", opts->rp_size / 1024); 9892abc475SAndres Salomon 9992abc475SAndres Salomon return 0; 10092abc475SAndres Salomon } 10192abc475SAndres Salomon 1021da177e4SLinus Torvalds static int jffs2_sync_fs(struct super_block *sb, int wait) 1031da177e4SLinus Torvalds { 1041da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 1051da177e4SLinus Torvalds 106a445f784SArtem Bityutskiy #ifdef CONFIG_JFFS2_FS_WRITEBUFFER 107a788c527SDaniel Santos if (jffs2_is_writebuffered(c)) 108a445f784SArtem Bityutskiy cancel_delayed_work_sync(&c->wbuf_dwork); 109a445f784SArtem Bityutskiy #endif 110a445f784SArtem Bityutskiy 111ced22070SDavid Woodhouse mutex_lock(&c->alloc_sem); 1121da177e4SLinus Torvalds jffs2_flush_wbuf_pad(c); 113ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 1141da177e4SLinus Torvalds return 0; 1151da177e4SLinus Torvalds } 1161da177e4SLinus Torvalds 1175f556aabSDavid Woodhouse static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, 1185f556aabSDavid Woodhouse uint32_t generation) 1195f556aabSDavid Woodhouse { 1205f556aabSDavid Woodhouse /* We don't care about i_generation. We'll destroy the flash 1215f556aabSDavid Woodhouse before we start re-using inode numbers anyway. And even 1225f556aabSDavid Woodhouse if that wasn't true, we'd have other problems...*/ 1235f556aabSDavid Woodhouse return jffs2_iget(sb, ino); 1245f556aabSDavid Woodhouse } 1255f556aabSDavid Woodhouse 1265f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, 1275f556aabSDavid Woodhouse int fh_len, int fh_type) 1285f556aabSDavid Woodhouse { 1295f556aabSDavid Woodhouse return generic_fh_to_dentry(sb, fid, fh_len, fh_type, 1305f556aabSDavid Woodhouse jffs2_nfs_get_inode); 1315f556aabSDavid Woodhouse } 1325f556aabSDavid Woodhouse 1335f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid, 1345f556aabSDavid Woodhouse int fh_len, int fh_type) 1355f556aabSDavid Woodhouse { 1365f556aabSDavid Woodhouse return generic_fh_to_parent(sb, fid, fh_len, fh_type, 1375f556aabSDavid Woodhouse jffs2_nfs_get_inode); 1385f556aabSDavid Woodhouse } 1395f556aabSDavid Woodhouse 1405f556aabSDavid Woodhouse static struct dentry *jffs2_get_parent(struct dentry *child) 1415f556aabSDavid Woodhouse { 1425f556aabSDavid Woodhouse struct jffs2_inode_info *f; 1435f556aabSDavid Woodhouse uint32_t pino; 1445f556aabSDavid Woodhouse 145e36cb0b8SDavid Howells BUG_ON(!d_is_dir(child)); 1465f556aabSDavid Woodhouse 1472b0143b5SDavid Howells f = JFFS2_INODE_INFO(d_inode(child)); 1485f556aabSDavid Woodhouse 1495f556aabSDavid Woodhouse pino = f->inocache->pino_nlink; 1505f556aabSDavid Woodhouse 1515f556aabSDavid Woodhouse JFFS2_DEBUG("Parent of directory ino #%u is #%u\n", 1525f556aabSDavid Woodhouse f->inocache->ino, pino); 1535f556aabSDavid Woodhouse 154fc64005cSAl Viro return d_obtain_alias(jffs2_iget(child->d_sb, pino)); 1555f556aabSDavid Woodhouse } 1565f556aabSDavid Woodhouse 157ac4cfdd6SAlexey Dobriyan static const struct export_operations jffs2_export_ops = { 1585f556aabSDavid Woodhouse .get_parent = jffs2_get_parent, 1595f556aabSDavid Woodhouse .fh_to_dentry = jffs2_fh_to_dentry, 1605f556aabSDavid Woodhouse .fh_to_parent = jffs2_fh_to_parent, 1615f556aabSDavid Woodhouse }; 1625f556aabSDavid Woodhouse 16392abc475SAndres Salomon /* 16492abc475SAndres Salomon * JFFS2 mount options. 16592abc475SAndres Salomon * 16692abc475SAndres Salomon * Opt_override_compr: override default compressor 1678da8ba2eSDaniel Drake * Opt_rp_size: size of reserved pool in KiB 16892abc475SAndres Salomon * Opt_err: just end of array marker 16992abc475SAndres Salomon */ 17092abc475SAndres Salomon enum { 17192abc475SAndres Salomon Opt_override_compr, 1728da8ba2eSDaniel Drake Opt_rp_size, 17392abc475SAndres Salomon Opt_err, 17492abc475SAndres Salomon }; 17592abc475SAndres Salomon 17692abc475SAndres Salomon static const match_table_t tokens = { 17792abc475SAndres Salomon {Opt_override_compr, "compr=%s"}, 1788da8ba2eSDaniel Drake {Opt_rp_size, "rp_size=%u"}, 17992abc475SAndres Salomon {Opt_err, NULL}, 18092abc475SAndres Salomon }; 18192abc475SAndres Salomon 18292abc475SAndres Salomon static int jffs2_parse_options(struct jffs2_sb_info *c, char *data) 18392abc475SAndres Salomon { 18492abc475SAndres Salomon substring_t args[MAX_OPT_ARGS]; 18592abc475SAndres Salomon char *p, *name; 1868da8ba2eSDaniel Drake unsigned int opt; 18792abc475SAndres Salomon 18892abc475SAndres Salomon if (!data) 18992abc475SAndres Salomon return 0; 19092abc475SAndres Salomon 19192abc475SAndres Salomon while ((p = strsep(&data, ","))) { 19292abc475SAndres Salomon int token; 19392abc475SAndres Salomon 19492abc475SAndres Salomon if (!*p) 19592abc475SAndres Salomon continue; 19692abc475SAndres Salomon 19792abc475SAndres Salomon token = match_token(p, tokens, args); 19892abc475SAndres Salomon switch (token) { 19992abc475SAndres Salomon case Opt_override_compr: 20092abc475SAndres Salomon name = match_strdup(&args[0]); 20192abc475SAndres Salomon 20292abc475SAndres Salomon if (!name) 20392abc475SAndres Salomon return -ENOMEM; 204123005f3SAndres Salomon if (!strcmp(name, "none")) 20592abc475SAndres Salomon c->mount_opts.compr = JFFS2_COMPR_MODE_NONE; 206123005f3SAndres Salomon #ifdef CONFIG_JFFS2_LZO 207123005f3SAndres Salomon else if (!strcmp(name, "lzo")) 208123005f3SAndres Salomon c->mount_opts.compr = JFFS2_COMPR_MODE_FORCELZO; 209123005f3SAndres Salomon #endif 210123005f3SAndres Salomon #ifdef CONFIG_JFFS2_ZLIB 211123005f3SAndres Salomon else if (!strcmp(name, "zlib")) 212123005f3SAndres Salomon c->mount_opts.compr = 213123005f3SAndres Salomon JFFS2_COMPR_MODE_FORCEZLIB; 214123005f3SAndres Salomon #endif 215123005f3SAndres Salomon else { 2165a528957SJoe Perches pr_err("Error: unknown compressor \"%s\"\n", 217123005f3SAndres Salomon name); 218123005f3SAndres Salomon kfree(name); 219123005f3SAndres Salomon return -EINVAL; 22092abc475SAndres Salomon } 22192abc475SAndres Salomon kfree(name); 222123005f3SAndres Salomon c->mount_opts.override_compr = true; 22392abc475SAndres Salomon break; 2248da8ba2eSDaniel Drake case Opt_rp_size: 2258da8ba2eSDaniel Drake if (match_int(&args[0], &opt)) 2268da8ba2eSDaniel Drake return -EINVAL; 2278da8ba2eSDaniel Drake opt *= 1024; 2288da8ba2eSDaniel Drake if (opt > c->mtd->size) { 2298da8ba2eSDaniel Drake pr_warn("Too large reserve pool specified, max " 2308da8ba2eSDaniel Drake "is %llu KB\n", c->mtd->size / 1024); 2318da8ba2eSDaniel Drake return -EINVAL; 2328da8ba2eSDaniel Drake } 2338da8ba2eSDaniel Drake c->mount_opts.rp_size = opt; 2348da8ba2eSDaniel Drake break; 23592abc475SAndres Salomon default: 2365a528957SJoe Perches pr_err("Error: unrecognized mount option '%s' or missing value\n", 23792abc475SAndres Salomon p); 23892abc475SAndres Salomon return -EINVAL; 23992abc475SAndres Salomon } 24092abc475SAndres Salomon } 24192abc475SAndres Salomon 24292abc475SAndres Salomon return 0; 24392abc475SAndres Salomon } 24492abc475SAndres Salomon 24592abc475SAndres Salomon static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data) 24692abc475SAndres Salomon { 24792abc475SAndres Salomon struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 24892abc475SAndres Salomon int err; 24992abc475SAndres Salomon 25002b9984dSTheodore Ts'o sync_filesystem(sb); 25192abc475SAndres Salomon err = jffs2_parse_options(c, data); 25292abc475SAndres Salomon if (err) 25392abc475SAndres Salomon return -EINVAL; 25492abc475SAndres Salomon 25592abc475SAndres Salomon return jffs2_do_remount_fs(sb, flags, data); 25692abc475SAndres Salomon } 25792abc475SAndres Salomon 258ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jffs2_super_operations = 2591da177e4SLinus Torvalds { 2601da177e4SLinus Torvalds .alloc_inode = jffs2_alloc_inode, 2611da177e4SLinus Torvalds .destroy_inode =jffs2_destroy_inode, 2621da177e4SLinus Torvalds .put_super = jffs2_put_super, 2631da177e4SLinus Torvalds .statfs = jffs2_statfs, 2641da177e4SLinus Torvalds .remount_fs = jffs2_remount_fs, 265b57922d9SAl Viro .evict_inode = jffs2_evict_inode, 2661da177e4SLinus Torvalds .dirty_inode = jffs2_dirty_inode, 26792abc475SAndres Salomon .show_options = jffs2_show_options, 2681da177e4SLinus Torvalds .sync_fs = jffs2_sync_fs, 2691da177e4SLinus Torvalds }; 2701da177e4SLinus Torvalds 271acaebfd8SDavid Howells /* 272acaebfd8SDavid Howells * fill in the superblock 273acaebfd8SDavid Howells */ 274acaebfd8SDavid Howells static int jffs2_fill_super(struct super_block *sb, void *data, int silent) 2751da177e4SLinus Torvalds { 2761da177e4SLinus Torvalds struct jffs2_sb_info *c; 277db719222SJan Blunck int ret; 278db719222SJan Blunck 2799c261b33SJoe Perches jffs2_dbg(1, "jffs2_get_sb_mtd():" 280acaebfd8SDavid Howells " New superblock for device %d (\"%s\")\n", 2819c261b33SJoe Perches sb->s_mtd->index, sb->s_mtd->name); 2821da177e4SLinus Torvalds 283f8314dc6SPanagiotis Issaris c = kzalloc(sizeof(*c), GFP_KERNEL); 2841a028dd2SArnd Bergmann if (!c) 285454e2398SDavid Howells return -ENOMEM; 2861da177e4SLinus Torvalds 287acaebfd8SDavid Howells c->mtd = sb->s_mtd; 288acaebfd8SDavid Howells c->os_priv = sb; 289acaebfd8SDavid Howells sb->s_fs_info = c; 2901da177e4SLinus Torvalds 29192abc475SAndres Salomon ret = jffs2_parse_options(c, data); 29292e2921fSHou Tao if (ret) 29392abc475SAndres Salomon return -EINVAL; 29492abc475SAndres Salomon 295acaebfd8SDavid Howells /* Initialize JFFS2 superblock locks, the further initialization will 296acaebfd8SDavid Howells * be done later */ 297ced22070SDavid Woodhouse mutex_init(&c->alloc_sem); 298ced22070SDavid Woodhouse mutex_init(&c->erase_free_sem); 299b6220598SArtem B. Bityuckiy init_waitqueue_head(&c->erase_wait); 300b6220598SArtem B. Bityuckiy init_waitqueue_head(&c->inocache_wq); 301b6220598SArtem B. Bityuckiy spin_lock_init(&c->erase_completion_lock); 302b6220598SArtem B. Bityuckiy spin_lock_init(&c->inocache_lock); 303b6220598SArtem B. Bityuckiy 3041da177e4SLinus Torvalds sb->s_op = &jffs2_super_operations; 3055f556aabSDavid Woodhouse sb->s_export_op = &jffs2_export_ops; 3061751e8a6SLinus Torvalds sb->s_flags = sb->s_flags | SB_NOATIME; 307aa98d7cfSKaiGai Kohei sb->s_xattr = jffs2_xattr_handlers; 308aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL 3091751e8a6SLinus Torvalds sb->s_flags |= SB_POSIXACL; 310aa98d7cfSKaiGai Kohei #endif 311db719222SJan Blunck ret = jffs2_do_fill_super(sb, data, silent); 312db719222SJan Blunck return ret; 3131da177e4SLinus Torvalds } 3141da177e4SLinus Torvalds 315848b83a5SAl Viro static struct dentry *jffs2_mount(struct file_system_type *fs_type, 3161da177e4SLinus Torvalds int flags, const char *dev_name, 317848b83a5SAl Viro void *data) 3181da177e4SLinus Torvalds { 319848b83a5SAl Viro return mount_mtd(fs_type, flags, dev_name, data, jffs2_fill_super); 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds static void jffs2_put_super (struct super_block *sb) 3231da177e4SLinus Torvalds { 3241da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 3251da177e4SLinus Torvalds 3269c261b33SJoe Perches jffs2_dbg(2, "%s()\n", __func__); 3271da177e4SLinus Torvalds 328ced22070SDavid Woodhouse mutex_lock(&c->alloc_sem); 3291da177e4SLinus Torvalds jffs2_flush_wbuf_pad(c); 330ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 331e631ddbaSFerenc Havasi 332e631ddbaSFerenc Havasi jffs2_sum_exit(c); 333e631ddbaSFerenc Havasi 3341da177e4SLinus Torvalds jffs2_free_ino_caches(c); 3351da177e4SLinus Torvalds jffs2_free_raw_node_refs(c); 3361d5cfdb0STetsuo Handa kvfree(c->blocks); 3371da177e4SLinus Torvalds jffs2_flash_cleanup(c); 3381da177e4SLinus Torvalds kfree(c->inocache_list); 339aa98d7cfSKaiGai Kohei jffs2_clear_xattr_subsystem(c); 34085f2f2a8SArtem Bityutskiy mtd_sync(c->mtd); 3419c261b33SJoe Perches jffs2_dbg(1, "%s(): returning\n", __func__); 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds static void jffs2_kill_sb(struct super_block *sb) 3451da177e4SLinus Torvalds { 3461da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 347c66b23c2SAl Viro if (c && !sb_rdonly(sb)) 348a69dde91SArtem B. Bityuckiy jffs2_stop_garbage_collect_thread(c); 349acaebfd8SDavid Howells kill_mtd_super(sb); 3501da177e4SLinus Torvalds kfree(c); 3511da177e4SLinus Torvalds } 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds static struct file_system_type jffs2_fs_type = { 3541da177e4SLinus Torvalds .owner = THIS_MODULE, 3551da177e4SLinus Torvalds .name = "jffs2", 356848b83a5SAl Viro .mount = jffs2_mount, 3571da177e4SLinus Torvalds .kill_sb = jffs2_kill_sb, 3581da177e4SLinus Torvalds }; 3597f78e035SEric W. Biederman MODULE_ALIAS_FS("jffs2"); 3601da177e4SLinus Torvalds 3611da177e4SLinus Torvalds static int __init init_jffs2_fs(void) 3621da177e4SLinus Torvalds { 3631da177e4SLinus Torvalds int ret; 3641da177e4SLinus Torvalds 3653e68fbb5SDavid Woodhouse /* Paranoia checks for on-medium structures. If we ask GCC 3663e68fbb5SDavid Woodhouse to pack them with __attribute__((packed)) then it _also_ 3673e68fbb5SDavid Woodhouse assumes that they're not aligned -- so it emits crappy 3683e68fbb5SDavid Woodhouse code on some architectures. Ideally we want an attribute 3693e68fbb5SDavid Woodhouse which means just 'no padding', without the alignment 3703e68fbb5SDavid Woodhouse thing. But GCC doesn't have that -- we have to just 3713e68fbb5SDavid Woodhouse hope the structs are the right sizes, instead. */ 3722ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12); 3732ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40); 3742ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); 3752ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); 3763e68fbb5SDavid Woodhouse 3775a528957SJoe Perches pr_info("version 2.2." 3782f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER 3791da177e4SLinus Torvalds " (NAND)" 3801da177e4SLinus Torvalds #endif 381e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY 382e631ddbaSFerenc Havasi " (SUMMARY) " 383e631ddbaSFerenc Havasi #endif 384c00c310eSDavid Woodhouse " © 2001-2006 Red Hat, Inc.\n"); 3851da177e4SLinus Torvalds 3861da177e4SLinus Torvalds jffs2_inode_cachep = kmem_cache_create("jffs2_i", 3871da177e4SLinus Torvalds sizeof(struct jffs2_inode_info), 388fffb60f9SPaul Jackson 0, (SLAB_RECLAIM_ACCOUNT| 3895d097056SVladimir Davydov SLAB_MEM_SPREAD|SLAB_ACCOUNT), 39020c2df83SPaul Mundt jffs2_i_init_once); 3911da177e4SLinus Torvalds if (!jffs2_inode_cachep) { 3925a528957SJoe Perches pr_err("error: Failed to initialise inode cache\n"); 3931da177e4SLinus Torvalds return -ENOMEM; 3941da177e4SLinus Torvalds } 3951da177e4SLinus Torvalds ret = jffs2_compressors_init(); 3961da177e4SLinus Torvalds if (ret) { 3975a528957SJoe Perches pr_err("error: Failed to initialise compressors\n"); 3981da177e4SLinus Torvalds goto out; 3991da177e4SLinus Torvalds } 4001da177e4SLinus Torvalds ret = jffs2_create_slab_caches(); 4011da177e4SLinus Torvalds if (ret) { 4025a528957SJoe Perches pr_err("error: Failed to initialise slab caches\n"); 4031da177e4SLinus Torvalds goto out_compressors; 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds ret = register_filesystem(&jffs2_fs_type); 4061da177e4SLinus Torvalds if (ret) { 4075a528957SJoe Perches pr_err("error: Failed to register filesystem\n"); 4081da177e4SLinus Torvalds goto out_slab; 4091da177e4SLinus Torvalds } 4101da177e4SLinus Torvalds return 0; 4111da177e4SLinus Torvalds 4121da177e4SLinus Torvalds out_slab: 4131da177e4SLinus Torvalds jffs2_destroy_slab_caches(); 4141da177e4SLinus Torvalds out_compressors: 4151da177e4SLinus Torvalds jffs2_compressors_exit(); 4161da177e4SLinus Torvalds out: 4171da177e4SLinus Torvalds kmem_cache_destroy(jffs2_inode_cachep); 4181da177e4SLinus Torvalds return ret; 4191da177e4SLinus Torvalds } 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void) 4221da177e4SLinus Torvalds { 4231da177e4SLinus Torvalds unregister_filesystem(&jffs2_fs_type); 4241da177e4SLinus Torvalds jffs2_destroy_slab_caches(); 4251da177e4SLinus Torvalds jffs2_compressors_exit(); 4268c0a8537SKirill A. Shutemov 4278c0a8537SKirill A. Shutemov /* 4288c0a8537SKirill A. Shutemov * Make sure all delayed rcu free inodes are flushed before we 4298c0a8537SKirill A. Shutemov * destroy cache. 4308c0a8537SKirill A. Shutemov */ 4318c0a8537SKirill A. Shutemov rcu_barrier(); 4321da177e4SLinus Torvalds kmem_cache_destroy(jffs2_inode_cachep); 4331da177e4SLinus Torvalds } 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds module_init(init_jffs2_fs); 4361da177e4SLinus Torvalds module_exit(exit_jffs2_fs); 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journalling Flash File System, v2"); 4391da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc."); 4401da177e4SLinus Torvalds MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for 4411da177e4SLinus Torvalds // the sake of this tag. It's Free Software. 442