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
jffs2_alloc_inode(struct super_block * sb)381da177e4SLinus Torvalds static struct inode *jffs2_alloc_inode(struct super_block *sb)
391da177e4SLinus Torvalds {
404e571abaSDavid Woodhouse struct jffs2_inode_info *f;
414e571abaSDavid Woodhouse
42fd60b288SMuchun Song f = alloc_inode_sb(sb, jffs2_inode_cachep, GFP_KERNEL);
434e571abaSDavid Woodhouse if (!f)
441da177e4SLinus Torvalds return NULL;
454e571abaSDavid Woodhouse return &f->vfs_inode;
461da177e4SLinus Torvalds }
471da177e4SLinus Torvalds
jffs2_free_inode(struct inode * inode)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
jffs2_i_init_once(void * foo)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);
61*d0bbbf31SWang Yong f->target = NULL;
624e571abaSDavid Woodhouse inode_init_once(&f->vfs_inode);
631da177e4SLinus Torvalds }
641da177e4SLinus Torvalds
jffs2_compr_name(unsigned int compr)6592abc475SAndres Salomon static const char *jffs2_compr_name(unsigned int compr)
6692abc475SAndres Salomon {
6792abc475SAndres Salomon switch (compr) {
6892abc475SAndres Salomon case JFFS2_COMPR_MODE_NONE:
6992abc475SAndres Salomon return "none";
70123005f3SAndres Salomon #ifdef CONFIG_JFFS2_LZO
71123005f3SAndres Salomon case JFFS2_COMPR_MODE_FORCELZO:
72123005f3SAndres Salomon return "lzo";
73123005f3SAndres Salomon #endif
74123005f3SAndres Salomon #ifdef CONFIG_JFFS2_ZLIB
75123005f3SAndres Salomon case JFFS2_COMPR_MODE_FORCEZLIB:
76123005f3SAndres Salomon return "zlib";
77123005f3SAndres Salomon #endif
7892abc475SAndres Salomon default:
7992abc475SAndres Salomon /* should never happen; programmer error */
8092abc475SAndres Salomon WARN_ON(1);
8192abc475SAndres Salomon return "";
8292abc475SAndres Salomon }
8392abc475SAndres Salomon }
8492abc475SAndres Salomon
jffs2_show_options(struct seq_file * s,struct dentry * root)8534c80b1dSAl Viro static int jffs2_show_options(struct seq_file *s, struct dentry *root)
8692abc475SAndres Salomon {
8734c80b1dSAl Viro struct jffs2_sb_info *c = JFFS2_SB_INFO(root->d_sb);
8892abc475SAndres Salomon struct jffs2_mount_opts *opts = &c->mount_opts;
8992abc475SAndres Salomon
9092abc475SAndres Salomon if (opts->override_compr)
9192abc475SAndres Salomon seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr));
92cd3ed3c7Slizhe if (opts->set_rp_size)
938da8ba2eSDaniel Drake seq_printf(s, ",rp_size=%u", opts->rp_size / 1024);
9492abc475SAndres Salomon
9592abc475SAndres Salomon return 0;
9692abc475SAndres Salomon }
9792abc475SAndres Salomon
jffs2_sync_fs(struct super_block * sb,int wait)981da177e4SLinus Torvalds static int jffs2_sync_fs(struct super_block *sb, int wait)
991da177e4SLinus Torvalds {
1001da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
1011da177e4SLinus Torvalds
102a445f784SArtem Bityutskiy #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
103a788c527SDaniel Santos if (jffs2_is_writebuffered(c))
104a445f784SArtem Bityutskiy cancel_delayed_work_sync(&c->wbuf_dwork);
105a445f784SArtem Bityutskiy #endif
106a445f784SArtem Bityutskiy
107ced22070SDavid Woodhouse mutex_lock(&c->alloc_sem);
1081da177e4SLinus Torvalds jffs2_flush_wbuf_pad(c);
109ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem);
1101da177e4SLinus Torvalds return 0;
1111da177e4SLinus Torvalds }
1121da177e4SLinus Torvalds
jffs2_nfs_get_inode(struct super_block * sb,uint64_t ino,uint32_t generation)1135f556aabSDavid Woodhouse static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
1145f556aabSDavid Woodhouse uint32_t generation)
1155f556aabSDavid Woodhouse {
1165f556aabSDavid Woodhouse /* We don't care about i_generation. We'll destroy the flash
1175f556aabSDavid Woodhouse before we start re-using inode numbers anyway. And even
1185f556aabSDavid Woodhouse if that wasn't true, we'd have other problems...*/
1195f556aabSDavid Woodhouse return jffs2_iget(sb, ino);
1205f556aabSDavid Woodhouse }
1215f556aabSDavid Woodhouse
jffs2_fh_to_dentry(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)1225f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
1235f556aabSDavid Woodhouse int fh_len, int fh_type)
1245f556aabSDavid Woodhouse {
1255f556aabSDavid Woodhouse return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
1265f556aabSDavid Woodhouse jffs2_nfs_get_inode);
1275f556aabSDavid Woodhouse }
1285f556aabSDavid Woodhouse
jffs2_fh_to_parent(struct super_block * sb,struct fid * fid,int fh_len,int fh_type)1295f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid,
1305f556aabSDavid Woodhouse int fh_len, int fh_type)
1315f556aabSDavid Woodhouse {
1325f556aabSDavid Woodhouse return generic_fh_to_parent(sb, fid, fh_len, fh_type,
1335f556aabSDavid Woodhouse jffs2_nfs_get_inode);
1345f556aabSDavid Woodhouse }
1355f556aabSDavid Woodhouse
jffs2_get_parent(struct dentry * child)1365f556aabSDavid Woodhouse static struct dentry *jffs2_get_parent(struct dentry *child)
1375f556aabSDavid Woodhouse {
1385f556aabSDavid Woodhouse struct jffs2_inode_info *f;
1395f556aabSDavid Woodhouse uint32_t pino;
1405f556aabSDavid Woodhouse
141e36cb0b8SDavid Howells BUG_ON(!d_is_dir(child));
1425f556aabSDavid Woodhouse
1432b0143b5SDavid Howells f = JFFS2_INODE_INFO(d_inode(child));
1445f556aabSDavid Woodhouse
1455f556aabSDavid Woodhouse pino = f->inocache->pino_nlink;
1465f556aabSDavid Woodhouse
1475f556aabSDavid Woodhouse JFFS2_DEBUG("Parent of directory ino #%u is #%u\n",
1485f556aabSDavid Woodhouse f->inocache->ino, pino);
1495f556aabSDavid Woodhouse
150fc64005cSAl Viro return d_obtain_alias(jffs2_iget(child->d_sb, pino));
1515f556aabSDavid Woodhouse }
1525f556aabSDavid Woodhouse
153ac4cfdd6SAlexey Dobriyan static const struct export_operations jffs2_export_ops = {
1545f556aabSDavid Woodhouse .get_parent = jffs2_get_parent,
1555f556aabSDavid Woodhouse .fh_to_dentry = jffs2_fh_to_dentry,
1565f556aabSDavid Woodhouse .fh_to_parent = jffs2_fh_to_parent,
1575f556aabSDavid Woodhouse };
1585f556aabSDavid Woodhouse
15992abc475SAndres Salomon /*
16092abc475SAndres Salomon * JFFS2 mount options.
16192abc475SAndres Salomon *
162ec10a24fSDavid Howells * Opt_source: The source device
16392abc475SAndres Salomon * Opt_override_compr: override default compressor
1648da8ba2eSDaniel Drake * Opt_rp_size: size of reserved pool in KiB
16592abc475SAndres Salomon */
16692abc475SAndres Salomon enum {
16792abc475SAndres Salomon Opt_override_compr,
1688da8ba2eSDaniel Drake Opt_rp_size,
16992abc475SAndres Salomon };
17092abc475SAndres Salomon
1715eede625SAl Viro static const struct constant_table jffs2_param_compr[] = {
1722710c957SAl Viro {"none", JFFS2_COMPR_MODE_NONE },
1732710c957SAl Viro #ifdef CONFIG_JFFS2_LZO
1742710c957SAl Viro {"lzo", JFFS2_COMPR_MODE_FORCELZO },
1752710c957SAl Viro #endif
1762710c957SAl Viro #ifdef CONFIG_JFFS2_ZLIB
1772710c957SAl Viro {"zlib", JFFS2_COMPR_MODE_FORCEZLIB },
1782710c957SAl Viro #endif
179ec10a24fSDavid Howells {}
18092abc475SAndres Salomon };
18192abc475SAndres Salomon
182d7167b14SAl Viro static const struct fs_parameter_spec jffs2_fs_parameters[] = {
1832710c957SAl Viro fsparam_enum ("compr", Opt_override_compr, jffs2_param_compr),
1842710c957SAl Viro fsparam_u32 ("rp_size", Opt_rp_size),
185ec10a24fSDavid Howells {}
186ec10a24fSDavid Howells };
187ec10a24fSDavid Howells
jffs2_parse_param(struct fs_context * fc,struct fs_parameter * param)188ec10a24fSDavid Howells static int jffs2_parse_param(struct fs_context *fc, struct fs_parameter *param)
189ec10a24fSDavid Howells {
190ec10a24fSDavid Howells struct fs_parse_result result;
191ec10a24fSDavid Howells struct jffs2_sb_info *c = fc->s_fs_info;
192ec10a24fSDavid Howells int opt;
193ec10a24fSDavid Howells
194d7167b14SAl Viro opt = fs_parse(fc, jffs2_fs_parameters, param, &result);
195ec10a24fSDavid Howells if (opt < 0)
196ec10a24fSDavid Howells return opt;
197ec10a24fSDavid Howells
198ec10a24fSDavid Howells switch (opt) {
199ec10a24fSDavid Howells case Opt_override_compr:
200ec10a24fSDavid Howells c->mount_opts.compr = result.uint_32;
201123005f3SAndres Salomon c->mount_opts.override_compr = true;
20292abc475SAndres Salomon break;
2038da8ba2eSDaniel Drake case Opt_rp_size:
204ec10a24fSDavid Howells if (result.uint_32 > UINT_MAX / 1024)
205ec10a24fSDavid Howells return invalf(fc, "jffs2: rp_size unrepresentable");
206a61df3c4SJamie Iles c->mount_opts.rp_size = result.uint_32 * 1024;
207cd3ed3c7Slizhe c->mount_opts.set_rp_size = true;
2088da8ba2eSDaniel Drake break;
20992abc475SAndres Salomon default:
21092abc475SAndres Salomon return -EINVAL;
21192abc475SAndres Salomon }
21292abc475SAndres Salomon
21392abc475SAndres Salomon return 0;
21492abc475SAndres Salomon }
21592abc475SAndres Salomon
jffs2_update_mount_opts(struct fs_context * fc)21608cd274fSlizhe static inline void jffs2_update_mount_opts(struct fs_context *fc)
21708cd274fSlizhe {
21808cd274fSlizhe struct jffs2_sb_info *new_c = fc->s_fs_info;
21908cd274fSlizhe struct jffs2_sb_info *c = JFFS2_SB_INFO(fc->root->d_sb);
22008cd274fSlizhe
22108cd274fSlizhe mutex_lock(&c->alloc_sem);
22208cd274fSlizhe if (new_c->mount_opts.override_compr) {
22308cd274fSlizhe c->mount_opts.override_compr = new_c->mount_opts.override_compr;
22408cd274fSlizhe c->mount_opts.compr = new_c->mount_opts.compr;
22508cd274fSlizhe }
226cd3ed3c7Slizhe if (new_c->mount_opts.set_rp_size) {
227cd3ed3c7Slizhe c->mount_opts.set_rp_size = new_c->mount_opts.set_rp_size;
22808cd274fSlizhe c->mount_opts.rp_size = new_c->mount_opts.rp_size;
229cd3ed3c7Slizhe }
23008cd274fSlizhe mutex_unlock(&c->alloc_sem);
23108cd274fSlizhe }
23208cd274fSlizhe
jffs2_reconfigure(struct fs_context * fc)233ec10a24fSDavid Howells static int jffs2_reconfigure(struct fs_context *fc)
23492abc475SAndres Salomon {
235ec10a24fSDavid Howells struct super_block *sb = fc->root->d_sb;
23692abc475SAndres Salomon
23702b9984dSTheodore Ts'o sync_filesystem(sb);
23808cd274fSlizhe jffs2_update_mount_opts(fc);
23908cd274fSlizhe
240ec10a24fSDavid Howells return jffs2_do_remount_fs(sb, fc);
24192abc475SAndres Salomon }
24292abc475SAndres Salomon
243ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jffs2_super_operations =
2441da177e4SLinus Torvalds {
2451da177e4SLinus Torvalds .alloc_inode = jffs2_alloc_inode,
246db0bd7b7SAl Viro .free_inode = jffs2_free_inode,
2471da177e4SLinus Torvalds .put_super = jffs2_put_super,
2481da177e4SLinus Torvalds .statfs = jffs2_statfs,
249b57922d9SAl Viro .evict_inode = jffs2_evict_inode,
2501da177e4SLinus Torvalds .dirty_inode = jffs2_dirty_inode,
25192abc475SAndres Salomon .show_options = jffs2_show_options,
2521da177e4SLinus Torvalds .sync_fs = jffs2_sync_fs,
2531da177e4SLinus Torvalds };
2541da177e4SLinus Torvalds
255acaebfd8SDavid Howells /*
256acaebfd8SDavid Howells * fill in the superblock
257acaebfd8SDavid Howells */
jffs2_fill_super(struct super_block * sb,struct fs_context * fc)258ec10a24fSDavid Howells static int jffs2_fill_super(struct super_block *sb, struct fs_context *fc)
2591da177e4SLinus Torvalds {
260ec10a24fSDavid Howells struct jffs2_sb_info *c = sb->s_fs_info;
261db719222SJan Blunck
2629c261b33SJoe Perches jffs2_dbg(1, "jffs2_get_sb_mtd():"
263acaebfd8SDavid Howells " New superblock for device %d (\"%s\")\n",
2649c261b33SJoe Perches sb->s_mtd->index, sb->s_mtd->name);
2651da177e4SLinus Torvalds
266acaebfd8SDavid Howells c->mtd = sb->s_mtd;
267acaebfd8SDavid Howells c->os_priv = sb;
26892abc475SAndres Salomon
269a61df3c4SJamie Iles if (c->mount_opts.rp_size > c->mtd->size)
270a61df3c4SJamie Iles return invalf(fc, "jffs2: Too large reserve pool specified, max is %llu KB",
271a61df3c4SJamie Iles c->mtd->size / 1024);
272a61df3c4SJamie Iles
273acaebfd8SDavid Howells /* Initialize JFFS2 superblock locks, the further initialization will
274acaebfd8SDavid Howells * be done later */
275ced22070SDavid Woodhouse mutex_init(&c->alloc_sem);
276ced22070SDavid Woodhouse mutex_init(&c->erase_free_sem);
277b6220598SArtem B. Bityuckiy init_waitqueue_head(&c->erase_wait);
278b6220598SArtem B. Bityuckiy init_waitqueue_head(&c->inocache_wq);
279b6220598SArtem B. Bityuckiy spin_lock_init(&c->erase_completion_lock);
280b6220598SArtem B. Bityuckiy spin_lock_init(&c->inocache_lock);
281b6220598SArtem B. Bityuckiy
2821da177e4SLinus Torvalds sb->s_op = &jffs2_super_operations;
2835f556aabSDavid Woodhouse sb->s_export_op = &jffs2_export_ops;
2841751e8a6SLinus Torvalds sb->s_flags = sb->s_flags | SB_NOATIME;
285aa98d7cfSKaiGai Kohei sb->s_xattr = jffs2_xattr_handlers;
286aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL
2871751e8a6SLinus Torvalds sb->s_flags |= SB_POSIXACL;
288aa98d7cfSKaiGai Kohei #endif
289ec10a24fSDavid Howells return jffs2_do_fill_super(sb, fc);
2901da177e4SLinus Torvalds }
2911da177e4SLinus Torvalds
jffs2_get_tree(struct fs_context * fc)292ec10a24fSDavid Howells static int jffs2_get_tree(struct fs_context *fc)
2931da177e4SLinus Torvalds {
294ec10a24fSDavid Howells return get_tree_mtd(fc, jffs2_fill_super);
295ec10a24fSDavid Howells }
296ec10a24fSDavid Howells
jffs2_free_fc(struct fs_context * fc)297ec10a24fSDavid Howells static void jffs2_free_fc(struct fs_context *fc)
298ec10a24fSDavid Howells {
299ec10a24fSDavid Howells kfree(fc->s_fs_info);
300ec10a24fSDavid Howells }
301ec10a24fSDavid Howells
302ec10a24fSDavid Howells static const struct fs_context_operations jffs2_context_ops = {
303ec10a24fSDavid Howells .free = jffs2_free_fc,
304ec10a24fSDavid Howells .parse_param = jffs2_parse_param,
305ec10a24fSDavid Howells .get_tree = jffs2_get_tree,
306ec10a24fSDavid Howells .reconfigure = jffs2_reconfigure,
307ec10a24fSDavid Howells };
308ec10a24fSDavid Howells
jffs2_init_fs_context(struct fs_context * fc)309ec10a24fSDavid Howells static int jffs2_init_fs_context(struct fs_context *fc)
310ec10a24fSDavid Howells {
311ec10a24fSDavid Howells struct jffs2_sb_info *ctx;
312ec10a24fSDavid Howells
313ec10a24fSDavid Howells ctx = kzalloc(sizeof(struct jffs2_sb_info), GFP_KERNEL);
314ec10a24fSDavid Howells if (!ctx)
315ec10a24fSDavid Howells return -ENOMEM;
316ec10a24fSDavid Howells
317ec10a24fSDavid Howells fc->s_fs_info = ctx;
318ec10a24fSDavid Howells fc->ops = &jffs2_context_ops;
319ec10a24fSDavid Howells return 0;
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds
jffs2_put_super(struct super_block * sb)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
jffs2_kill_sb(struct super_block * sb)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",
356ec10a24fSDavid Howells .init_fs_context = jffs2_init_fs_context,
357d7167b14SAl Viro .parameters = jffs2_fs_parameters,
3581da177e4SLinus Torvalds .kill_sb = jffs2_kill_sb,
3591da177e4SLinus Torvalds };
3607f78e035SEric W. Biederman MODULE_ALIAS_FS("jffs2");
3611da177e4SLinus Torvalds
init_jffs2_fs(void)3621da177e4SLinus Torvalds static int __init init_jffs2_fs(void)
3631da177e4SLinus Torvalds {
3641da177e4SLinus Torvalds int ret;
3651da177e4SLinus Torvalds
3663e68fbb5SDavid Woodhouse /* Paranoia checks for on-medium structures. If we ask GCC
3673e68fbb5SDavid Woodhouse to pack them with __attribute__((packed)) then it _also_
3683e68fbb5SDavid Woodhouse assumes that they're not aligned -- so it emits crappy
3693e68fbb5SDavid Woodhouse code on some architectures. Ideally we want an attribute
3703e68fbb5SDavid Woodhouse which means just 'no padding', without the alignment
3713e68fbb5SDavid Woodhouse thing. But GCC doesn't have that -- we have to just
3723e68fbb5SDavid Woodhouse hope the structs are the right sizes, instead. */
3732ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
3742ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
3752ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
3762ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
3773e68fbb5SDavid Woodhouse
3785a528957SJoe Perches pr_info("version 2.2."
3792f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
3801da177e4SLinus Torvalds " (NAND)"
3811da177e4SLinus Torvalds #endif
382e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY
383e631ddbaSFerenc Havasi " (SUMMARY) "
384e631ddbaSFerenc Havasi #endif
385c00c310eSDavid Woodhouse " © 2001-2006 Red Hat, Inc.\n");
3861da177e4SLinus Torvalds
3871da177e4SLinus Torvalds jffs2_inode_cachep = kmem_cache_create("jffs2_i",
3881da177e4SLinus Torvalds sizeof(struct jffs2_inode_info),
389fffb60f9SPaul Jackson 0, (SLAB_RECLAIM_ACCOUNT|
3905d097056SVladimir Davydov SLAB_MEM_SPREAD|SLAB_ACCOUNT),
39120c2df83SPaul Mundt jffs2_i_init_once);
3921da177e4SLinus Torvalds if (!jffs2_inode_cachep) {
3935a528957SJoe Perches pr_err("error: Failed to initialise inode cache\n");
3941da177e4SLinus Torvalds return -ENOMEM;
3951da177e4SLinus Torvalds }
3961da177e4SLinus Torvalds ret = jffs2_compressors_init();
3971da177e4SLinus Torvalds if (ret) {
3985a528957SJoe Perches pr_err("error: Failed to initialise compressors\n");
3991da177e4SLinus Torvalds goto out;
4001da177e4SLinus Torvalds }
4011da177e4SLinus Torvalds ret = jffs2_create_slab_caches();
4021da177e4SLinus Torvalds if (ret) {
4035a528957SJoe Perches pr_err("error: Failed to initialise slab caches\n");
4041da177e4SLinus Torvalds goto out_compressors;
4051da177e4SLinus Torvalds }
4061da177e4SLinus Torvalds ret = register_filesystem(&jffs2_fs_type);
4071da177e4SLinus Torvalds if (ret) {
4085a528957SJoe Perches pr_err("error: Failed to register filesystem\n");
4091da177e4SLinus Torvalds goto out_slab;
4101da177e4SLinus Torvalds }
4111da177e4SLinus Torvalds return 0;
4121da177e4SLinus Torvalds
4131da177e4SLinus Torvalds out_slab:
4141da177e4SLinus Torvalds jffs2_destroy_slab_caches();
4151da177e4SLinus Torvalds out_compressors:
4161da177e4SLinus Torvalds jffs2_compressors_exit();
4171da177e4SLinus Torvalds out:
4181da177e4SLinus Torvalds kmem_cache_destroy(jffs2_inode_cachep);
4191da177e4SLinus Torvalds return ret;
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds
exit_jffs2_fs(void)4221da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void)
4231da177e4SLinus Torvalds {
4241da177e4SLinus Torvalds unregister_filesystem(&jffs2_fs_type);
4251da177e4SLinus Torvalds jffs2_destroy_slab_caches();
4261da177e4SLinus Torvalds jffs2_compressors_exit();
4278c0a8537SKirill A. Shutemov
4288c0a8537SKirill A. Shutemov /*
4298c0a8537SKirill A. Shutemov * Make sure all delayed rcu free inodes are flushed before we
4308c0a8537SKirill A. Shutemov * destroy cache.
4318c0a8537SKirill A. Shutemov */
4328c0a8537SKirill A. Shutemov rcu_barrier();
4331da177e4SLinus Torvalds kmem_cache_destroy(jffs2_inode_cachep);
4341da177e4SLinus Torvalds }
4351da177e4SLinus Torvalds
4361da177e4SLinus Torvalds module_init(init_jffs2_fs);
4371da177e4SLinus Torvalds module_exit(exit_jffs2_fs);
4381da177e4SLinus Torvalds
4391da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journalling Flash File System, v2");
4401da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc.");
4411da177e4SLinus Torvalds MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
4421da177e4SLinus Torvalds // the sake of this tag. It's Free Software.
443