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> 22ec10a24fSDavid Howells #include <linux/fs_context.h> 23ec10a24fSDavid Howells #include <linux/fs_parser.h> 241da177e4SLinus Torvalds #include <linux/jffs2.h> 251da177e4SLinus Torvalds #include <linux/pagemap.h> 26acaebfd8SDavid Howells #include <linux/mtd/super.h> 271da177e4SLinus Torvalds #include <linux/ctype.h> 281da177e4SLinus Torvalds #include <linux/namei.h> 2992abc475SAndres Salomon #include <linux/seq_file.h> 305f556aabSDavid Woodhouse #include <linux/exportfs.h> 311da177e4SLinus Torvalds #include "compr.h" 321da177e4SLinus Torvalds #include "nodelist.h" 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds static void jffs2_put_super(struct super_block *); 351da177e4SLinus Torvalds 36e18b890bSChristoph Lameter static struct kmem_cache *jffs2_inode_cachep; 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds static struct inode *jffs2_alloc_inode(struct super_block *sb) 391da177e4SLinus Torvalds { 404e571abaSDavid Woodhouse struct jffs2_inode_info *f; 414e571abaSDavid Woodhouse 424e571abaSDavid Woodhouse f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL); 434e571abaSDavid Woodhouse if (!f) 441da177e4SLinus Torvalds return NULL; 454e571abaSDavid Woodhouse return &f->vfs_inode; 461da177e4SLinus Torvalds } 471da177e4SLinus Torvalds 48db0bd7b7SAl Viro static void jffs2_free_inode(struct inode *inode) 49fa0d7e3dSNick Piggin { 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 5651cc5068SAlexey Dobriyan static void jffs2_i_init_once(void *foo) 571da177e4SLinus Torvalds { 584e571abaSDavid Woodhouse struct jffs2_inode_info *f = foo; 591da177e4SLinus Torvalds 604e571abaSDavid Woodhouse mutex_init(&f->sem); 614e571abaSDavid Woodhouse inode_init_once(&f->vfs_inode); 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds 6492abc475SAndres Salomon static const char *jffs2_compr_name(unsigned int compr) 6592abc475SAndres Salomon { 6692abc475SAndres Salomon switch (compr) { 6792abc475SAndres Salomon case JFFS2_COMPR_MODE_NONE: 6892abc475SAndres Salomon return "none"; 69123005f3SAndres Salomon #ifdef CONFIG_JFFS2_LZO 70123005f3SAndres Salomon case JFFS2_COMPR_MODE_FORCELZO: 71123005f3SAndres Salomon return "lzo"; 72123005f3SAndres Salomon #endif 73123005f3SAndres Salomon #ifdef CONFIG_JFFS2_ZLIB 74123005f3SAndres Salomon case JFFS2_COMPR_MODE_FORCEZLIB: 75123005f3SAndres Salomon return "zlib"; 76123005f3SAndres Salomon #endif 7792abc475SAndres Salomon default: 7892abc475SAndres Salomon /* should never happen; programmer error */ 7992abc475SAndres Salomon WARN_ON(1); 8092abc475SAndres Salomon return ""; 8192abc475SAndres Salomon } 8292abc475SAndres Salomon } 8392abc475SAndres Salomon 8434c80b1dSAl Viro static int jffs2_show_options(struct seq_file *s, struct dentry *root) 8592abc475SAndres Salomon { 8634c80b1dSAl Viro struct jffs2_sb_info *c = JFFS2_SB_INFO(root->d_sb); 8792abc475SAndres Salomon struct jffs2_mount_opts *opts = &c->mount_opts; 8892abc475SAndres Salomon 8992abc475SAndres Salomon if (opts->override_compr) 9092abc475SAndres Salomon seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr)); 918da8ba2eSDaniel Drake if (opts->rp_size) 928da8ba2eSDaniel Drake seq_printf(s, ",rp_size=%u", opts->rp_size / 1024); 9392abc475SAndres Salomon 9492abc475SAndres Salomon return 0; 9592abc475SAndres Salomon } 9692abc475SAndres Salomon 971da177e4SLinus Torvalds static int jffs2_sync_fs(struct super_block *sb, int wait) 981da177e4SLinus Torvalds { 991da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 1001da177e4SLinus Torvalds 101a445f784SArtem Bityutskiy #ifdef CONFIG_JFFS2_FS_WRITEBUFFER 102a788c527SDaniel Santos if (jffs2_is_writebuffered(c)) 103a445f784SArtem Bityutskiy cancel_delayed_work_sync(&c->wbuf_dwork); 104a445f784SArtem Bityutskiy #endif 105a445f784SArtem Bityutskiy 106ced22070SDavid Woodhouse mutex_lock(&c->alloc_sem); 1071da177e4SLinus Torvalds jffs2_flush_wbuf_pad(c); 108ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 1091da177e4SLinus Torvalds return 0; 1101da177e4SLinus Torvalds } 1111da177e4SLinus Torvalds 1125f556aabSDavid Woodhouse static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, 1135f556aabSDavid Woodhouse uint32_t generation) 1145f556aabSDavid Woodhouse { 1155f556aabSDavid Woodhouse /* We don't care about i_generation. We'll destroy the flash 1165f556aabSDavid Woodhouse before we start re-using inode numbers anyway. And even 1175f556aabSDavid Woodhouse if that wasn't true, we'd have other problems...*/ 1185f556aabSDavid Woodhouse return jffs2_iget(sb, ino); 1195f556aabSDavid Woodhouse } 1205f556aabSDavid Woodhouse 1215f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, 1225f556aabSDavid Woodhouse int fh_len, int fh_type) 1235f556aabSDavid Woodhouse { 1245f556aabSDavid Woodhouse return generic_fh_to_dentry(sb, fid, fh_len, fh_type, 1255f556aabSDavid Woodhouse jffs2_nfs_get_inode); 1265f556aabSDavid Woodhouse } 1275f556aabSDavid Woodhouse 1285f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid, 1295f556aabSDavid Woodhouse int fh_len, int fh_type) 1305f556aabSDavid Woodhouse { 1315f556aabSDavid Woodhouse return generic_fh_to_parent(sb, fid, fh_len, fh_type, 1325f556aabSDavid Woodhouse jffs2_nfs_get_inode); 1335f556aabSDavid Woodhouse } 1345f556aabSDavid Woodhouse 1355f556aabSDavid Woodhouse static struct dentry *jffs2_get_parent(struct dentry *child) 1365f556aabSDavid Woodhouse { 1375f556aabSDavid Woodhouse struct jffs2_inode_info *f; 1385f556aabSDavid Woodhouse uint32_t pino; 1395f556aabSDavid Woodhouse 140e36cb0b8SDavid Howells BUG_ON(!d_is_dir(child)); 1415f556aabSDavid Woodhouse 1422b0143b5SDavid Howells f = JFFS2_INODE_INFO(d_inode(child)); 1435f556aabSDavid Woodhouse 1445f556aabSDavid Woodhouse pino = f->inocache->pino_nlink; 1455f556aabSDavid Woodhouse 1465f556aabSDavid Woodhouse JFFS2_DEBUG("Parent of directory ino #%u is #%u\n", 1475f556aabSDavid Woodhouse f->inocache->ino, pino); 1485f556aabSDavid Woodhouse 149fc64005cSAl Viro return d_obtain_alias(jffs2_iget(child->d_sb, pino)); 1505f556aabSDavid Woodhouse } 1515f556aabSDavid Woodhouse 152ac4cfdd6SAlexey Dobriyan static const struct export_operations jffs2_export_ops = { 1535f556aabSDavid Woodhouse .get_parent = jffs2_get_parent, 1545f556aabSDavid Woodhouse .fh_to_dentry = jffs2_fh_to_dentry, 1555f556aabSDavid Woodhouse .fh_to_parent = jffs2_fh_to_parent, 1565f556aabSDavid Woodhouse }; 1575f556aabSDavid Woodhouse 15892abc475SAndres Salomon /* 15992abc475SAndres Salomon * JFFS2 mount options. 16092abc475SAndres Salomon * 161ec10a24fSDavid Howells * Opt_source: The source device 16292abc475SAndres Salomon * Opt_override_compr: override default compressor 1638da8ba2eSDaniel Drake * Opt_rp_size: size of reserved pool in KiB 16492abc475SAndres Salomon */ 16592abc475SAndres Salomon enum { 16692abc475SAndres Salomon Opt_override_compr, 1678da8ba2eSDaniel Drake Opt_rp_size, 16892abc475SAndres Salomon }; 16992abc475SAndres Salomon 1705eede625SAl Viro static const struct constant_table jffs2_param_compr[] = { 1712710c957SAl Viro {"none", JFFS2_COMPR_MODE_NONE }, 1722710c957SAl Viro #ifdef CONFIG_JFFS2_LZO 1732710c957SAl Viro {"lzo", JFFS2_COMPR_MODE_FORCELZO }, 1742710c957SAl Viro #endif 1752710c957SAl Viro #ifdef CONFIG_JFFS2_ZLIB 1762710c957SAl Viro {"zlib", JFFS2_COMPR_MODE_FORCEZLIB }, 1772710c957SAl Viro #endif 178ec10a24fSDavid Howells {} 17992abc475SAndres Salomon }; 18092abc475SAndres Salomon 1812710c957SAl Viro static const struct fs_parameter_spec jffs2_param_specs[] = { 1822710c957SAl Viro fsparam_enum ("compr", Opt_override_compr, jffs2_param_compr), 1832710c957SAl Viro fsparam_u32 ("rp_size", Opt_rp_size), 184ec10a24fSDavid Howells {} 185ec10a24fSDavid Howells }; 186ec10a24fSDavid Howells 187ec10a24fSDavid Howells const struct fs_parameter_description jffs2_fs_parameters = { 188ec10a24fSDavid Howells .name = "jffs2", 189ec10a24fSDavid Howells .specs = jffs2_param_specs, 190ec10a24fSDavid Howells }; 191ec10a24fSDavid Howells 192ec10a24fSDavid Howells static int jffs2_parse_param(struct fs_context *fc, struct fs_parameter *param) 193ec10a24fSDavid Howells { 194ec10a24fSDavid Howells struct fs_parse_result result; 195ec10a24fSDavid Howells struct jffs2_sb_info *c = fc->s_fs_info; 196ec10a24fSDavid Howells int opt; 197ec10a24fSDavid Howells 198ec10a24fSDavid Howells opt = fs_parse(fc, &jffs2_fs_parameters, param, &result); 199ec10a24fSDavid Howells if (opt < 0) 200ec10a24fSDavid Howells return opt; 201ec10a24fSDavid Howells 202ec10a24fSDavid Howells switch (opt) { 203ec10a24fSDavid Howells case Opt_override_compr: 204ec10a24fSDavid Howells c->mount_opts.compr = result.uint_32; 205123005f3SAndres Salomon c->mount_opts.override_compr = true; 20692abc475SAndres Salomon break; 2078da8ba2eSDaniel Drake case Opt_rp_size: 208ec10a24fSDavid Howells if (result.uint_32 > UINT_MAX / 1024) 209ec10a24fSDavid Howells return invalf(fc, "jffs2: rp_size unrepresentable"); 210ec10a24fSDavid Howells opt = result.uint_32 * 1024; 211ec10a24fSDavid Howells if (opt > c->mtd->size) 212ec10a24fSDavid Howells return invalf(fc, "jffs2: Too large reserve pool specified, max is %llu KB", 213ec10a24fSDavid Howells c->mtd->size / 1024); 2148da8ba2eSDaniel Drake c->mount_opts.rp_size = opt; 2158da8ba2eSDaniel Drake break; 21692abc475SAndres Salomon default: 21792abc475SAndres Salomon return -EINVAL; 21892abc475SAndres Salomon } 21992abc475SAndres Salomon 22092abc475SAndres Salomon return 0; 22192abc475SAndres Salomon } 22292abc475SAndres Salomon 223ec10a24fSDavid Howells static int jffs2_reconfigure(struct fs_context *fc) 22492abc475SAndres Salomon { 225ec10a24fSDavid Howells struct super_block *sb = fc->root->d_sb; 22692abc475SAndres Salomon 22702b9984dSTheodore Ts'o sync_filesystem(sb); 228ec10a24fSDavid Howells return jffs2_do_remount_fs(sb, fc); 22992abc475SAndres Salomon } 23092abc475SAndres Salomon 231ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jffs2_super_operations = 2321da177e4SLinus Torvalds { 2331da177e4SLinus Torvalds .alloc_inode = jffs2_alloc_inode, 234db0bd7b7SAl Viro .free_inode = jffs2_free_inode, 2351da177e4SLinus Torvalds .put_super = jffs2_put_super, 2361da177e4SLinus Torvalds .statfs = jffs2_statfs, 237b57922d9SAl Viro .evict_inode = jffs2_evict_inode, 2381da177e4SLinus Torvalds .dirty_inode = jffs2_dirty_inode, 23992abc475SAndres Salomon .show_options = jffs2_show_options, 2401da177e4SLinus Torvalds .sync_fs = jffs2_sync_fs, 2411da177e4SLinus Torvalds }; 2421da177e4SLinus Torvalds 243acaebfd8SDavid Howells /* 244acaebfd8SDavid Howells * fill in the superblock 245acaebfd8SDavid Howells */ 246ec10a24fSDavid Howells static int jffs2_fill_super(struct super_block *sb, struct fs_context *fc) 2471da177e4SLinus Torvalds { 248ec10a24fSDavid Howells struct jffs2_sb_info *c = sb->s_fs_info; 249db719222SJan Blunck 2509c261b33SJoe Perches jffs2_dbg(1, "jffs2_get_sb_mtd():" 251acaebfd8SDavid Howells " New superblock for device %d (\"%s\")\n", 2529c261b33SJoe Perches sb->s_mtd->index, sb->s_mtd->name); 2531da177e4SLinus Torvalds 254acaebfd8SDavid Howells c->mtd = sb->s_mtd; 255acaebfd8SDavid Howells c->os_priv = sb; 25692abc475SAndres Salomon 257acaebfd8SDavid Howells /* Initialize JFFS2 superblock locks, the further initialization will 258acaebfd8SDavid Howells * be done later */ 259ced22070SDavid Woodhouse mutex_init(&c->alloc_sem); 260ced22070SDavid Woodhouse mutex_init(&c->erase_free_sem); 261b6220598SArtem B. Bityuckiy init_waitqueue_head(&c->erase_wait); 262b6220598SArtem B. Bityuckiy init_waitqueue_head(&c->inocache_wq); 263b6220598SArtem B. Bityuckiy spin_lock_init(&c->erase_completion_lock); 264b6220598SArtem B. Bityuckiy spin_lock_init(&c->inocache_lock); 265b6220598SArtem B. Bityuckiy 2661da177e4SLinus Torvalds sb->s_op = &jffs2_super_operations; 2675f556aabSDavid Woodhouse sb->s_export_op = &jffs2_export_ops; 2681751e8a6SLinus Torvalds sb->s_flags = sb->s_flags | SB_NOATIME; 269aa98d7cfSKaiGai Kohei sb->s_xattr = jffs2_xattr_handlers; 270aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL 2711751e8a6SLinus Torvalds sb->s_flags |= SB_POSIXACL; 272aa98d7cfSKaiGai Kohei #endif 273ec10a24fSDavid Howells return jffs2_do_fill_super(sb, fc); 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 276ec10a24fSDavid Howells static int jffs2_get_tree(struct fs_context *fc) 2771da177e4SLinus Torvalds { 278ec10a24fSDavid Howells return get_tree_mtd(fc, jffs2_fill_super); 279ec10a24fSDavid Howells } 280ec10a24fSDavid Howells 281ec10a24fSDavid Howells static void jffs2_free_fc(struct fs_context *fc) 282ec10a24fSDavid Howells { 283ec10a24fSDavid Howells kfree(fc->s_fs_info); 284ec10a24fSDavid Howells } 285ec10a24fSDavid Howells 286ec10a24fSDavid Howells static const struct fs_context_operations jffs2_context_ops = { 287ec10a24fSDavid Howells .free = jffs2_free_fc, 288ec10a24fSDavid Howells .parse_param = jffs2_parse_param, 289ec10a24fSDavid Howells .get_tree = jffs2_get_tree, 290ec10a24fSDavid Howells .reconfigure = jffs2_reconfigure, 291ec10a24fSDavid Howells }; 292ec10a24fSDavid Howells 293ec10a24fSDavid Howells static int jffs2_init_fs_context(struct fs_context *fc) 294ec10a24fSDavid Howells { 295ec10a24fSDavid Howells struct jffs2_sb_info *ctx; 296ec10a24fSDavid Howells 297ec10a24fSDavid Howells ctx = kzalloc(sizeof(struct jffs2_sb_info), GFP_KERNEL); 298ec10a24fSDavid Howells if (!ctx) 299ec10a24fSDavid Howells return -ENOMEM; 300ec10a24fSDavid Howells 301ec10a24fSDavid Howells fc->s_fs_info = ctx; 302ec10a24fSDavid Howells fc->ops = &jffs2_context_ops; 303ec10a24fSDavid Howells return 0; 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds static void jffs2_put_super (struct super_block *sb) 3071da177e4SLinus Torvalds { 3081da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 3091da177e4SLinus Torvalds 3109c261b33SJoe Perches jffs2_dbg(2, "%s()\n", __func__); 3111da177e4SLinus Torvalds 312ced22070SDavid Woodhouse mutex_lock(&c->alloc_sem); 3131da177e4SLinus Torvalds jffs2_flush_wbuf_pad(c); 314ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 315e631ddbaSFerenc Havasi 316e631ddbaSFerenc Havasi jffs2_sum_exit(c); 317e631ddbaSFerenc Havasi 3181da177e4SLinus Torvalds jffs2_free_ino_caches(c); 3191da177e4SLinus Torvalds jffs2_free_raw_node_refs(c); 3201d5cfdb0STetsuo Handa kvfree(c->blocks); 3211da177e4SLinus Torvalds jffs2_flash_cleanup(c); 3221da177e4SLinus Torvalds kfree(c->inocache_list); 323aa98d7cfSKaiGai Kohei jffs2_clear_xattr_subsystem(c); 32485f2f2a8SArtem Bityutskiy mtd_sync(c->mtd); 3259c261b33SJoe Perches jffs2_dbg(1, "%s(): returning\n", __func__); 3261da177e4SLinus Torvalds } 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds static void jffs2_kill_sb(struct super_block *sb) 3291da177e4SLinus Torvalds { 3301da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 331c66b23c2SAl Viro if (c && !sb_rdonly(sb)) 332a69dde91SArtem B. Bityuckiy jffs2_stop_garbage_collect_thread(c); 333acaebfd8SDavid Howells kill_mtd_super(sb); 3341da177e4SLinus Torvalds kfree(c); 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds static struct file_system_type jffs2_fs_type = { 3381da177e4SLinus Torvalds .owner = THIS_MODULE, 3391da177e4SLinus Torvalds .name = "jffs2", 340ec10a24fSDavid Howells .init_fs_context = jffs2_init_fs_context, 341ec10a24fSDavid Howells .parameters = &jffs2_fs_parameters, 3421da177e4SLinus Torvalds .kill_sb = jffs2_kill_sb, 3431da177e4SLinus Torvalds }; 3447f78e035SEric W. Biederman MODULE_ALIAS_FS("jffs2"); 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds static int __init init_jffs2_fs(void) 3471da177e4SLinus Torvalds { 3481da177e4SLinus Torvalds int ret; 3491da177e4SLinus Torvalds 3503e68fbb5SDavid Woodhouse /* Paranoia checks for on-medium structures. If we ask GCC 3513e68fbb5SDavid Woodhouse to pack them with __attribute__((packed)) then it _also_ 3523e68fbb5SDavid Woodhouse assumes that they're not aligned -- so it emits crappy 3533e68fbb5SDavid Woodhouse code on some architectures. Ideally we want an attribute 3543e68fbb5SDavid Woodhouse which means just 'no padding', without the alignment 3553e68fbb5SDavid Woodhouse thing. But GCC doesn't have that -- we have to just 3563e68fbb5SDavid Woodhouse hope the structs are the right sizes, instead. */ 3572ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12); 3582ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40); 3592ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); 3602ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); 3613e68fbb5SDavid Woodhouse 3625a528957SJoe Perches pr_info("version 2.2." 3632f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER 3641da177e4SLinus Torvalds " (NAND)" 3651da177e4SLinus Torvalds #endif 366e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY 367e631ddbaSFerenc Havasi " (SUMMARY) " 368e631ddbaSFerenc Havasi #endif 369c00c310eSDavid Woodhouse " © 2001-2006 Red Hat, Inc.\n"); 3701da177e4SLinus Torvalds 3711da177e4SLinus Torvalds jffs2_inode_cachep = kmem_cache_create("jffs2_i", 3721da177e4SLinus Torvalds sizeof(struct jffs2_inode_info), 373fffb60f9SPaul Jackson 0, (SLAB_RECLAIM_ACCOUNT| 3745d097056SVladimir Davydov SLAB_MEM_SPREAD|SLAB_ACCOUNT), 37520c2df83SPaul Mundt jffs2_i_init_once); 3761da177e4SLinus Torvalds if (!jffs2_inode_cachep) { 3775a528957SJoe Perches pr_err("error: Failed to initialise inode cache\n"); 3781da177e4SLinus Torvalds return -ENOMEM; 3791da177e4SLinus Torvalds } 3801da177e4SLinus Torvalds ret = jffs2_compressors_init(); 3811da177e4SLinus Torvalds if (ret) { 3825a528957SJoe Perches pr_err("error: Failed to initialise compressors\n"); 3831da177e4SLinus Torvalds goto out; 3841da177e4SLinus Torvalds } 3851da177e4SLinus Torvalds ret = jffs2_create_slab_caches(); 3861da177e4SLinus Torvalds if (ret) { 3875a528957SJoe Perches pr_err("error: Failed to initialise slab caches\n"); 3881da177e4SLinus Torvalds goto out_compressors; 3891da177e4SLinus Torvalds } 3901da177e4SLinus Torvalds ret = register_filesystem(&jffs2_fs_type); 3911da177e4SLinus Torvalds if (ret) { 3925a528957SJoe Perches pr_err("error: Failed to register filesystem\n"); 3931da177e4SLinus Torvalds goto out_slab; 3941da177e4SLinus Torvalds } 3951da177e4SLinus Torvalds return 0; 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds out_slab: 3981da177e4SLinus Torvalds jffs2_destroy_slab_caches(); 3991da177e4SLinus Torvalds out_compressors: 4001da177e4SLinus Torvalds jffs2_compressors_exit(); 4011da177e4SLinus Torvalds out: 4021da177e4SLinus Torvalds kmem_cache_destroy(jffs2_inode_cachep); 4031da177e4SLinus Torvalds return ret; 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void) 4071da177e4SLinus Torvalds { 4081da177e4SLinus Torvalds unregister_filesystem(&jffs2_fs_type); 4091da177e4SLinus Torvalds jffs2_destroy_slab_caches(); 4101da177e4SLinus Torvalds jffs2_compressors_exit(); 4118c0a8537SKirill A. Shutemov 4128c0a8537SKirill A. Shutemov /* 4138c0a8537SKirill A. Shutemov * Make sure all delayed rcu free inodes are flushed before we 4148c0a8537SKirill A. Shutemov * destroy cache. 4158c0a8537SKirill A. Shutemov */ 4168c0a8537SKirill A. Shutemov rcu_barrier(); 4171da177e4SLinus Torvalds kmem_cache_destroy(jffs2_inode_cachep); 4181da177e4SLinus Torvalds } 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds module_init(init_jffs2_fs); 4211da177e4SLinus Torvalds module_exit(exit_jffs2_fs); 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journalling Flash File System, v2"); 4241da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc."); 4251da177e4SLinus Torvalds MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for 4261da177e4SLinus Torvalds // the sake of this tag. It's Free Software. 427