xref: /openbmc/linux/fs/jffs2/super.c (revision db0bd7b7)
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 
47db0bd7b7SAl Viro static void jffs2_free_inode(struct inode *inode)
48fa0d7e3dSNick Piggin {
494fdcfab5SAl Viro 	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
504fdcfab5SAl Viro 
514fdcfab5SAl Viro 	kfree(f->target);
524fdcfab5SAl Viro 	kmem_cache_free(jffs2_inode_cachep, f);
53fa0d7e3dSNick Piggin }
54fa0d7e3dSNick Piggin 
5551cc5068SAlexey Dobriyan static void jffs2_i_init_once(void *foo)
561da177e4SLinus Torvalds {
574e571abaSDavid Woodhouse 	struct jffs2_inode_info *f = foo;
581da177e4SLinus Torvalds 
594e571abaSDavid Woodhouse 	mutex_init(&f->sem);
604e571abaSDavid Woodhouse 	inode_init_once(&f->vfs_inode);
611da177e4SLinus Torvalds }
621da177e4SLinus Torvalds 
6392abc475SAndres Salomon static const char *jffs2_compr_name(unsigned int compr)
6492abc475SAndres Salomon {
6592abc475SAndres Salomon 	switch (compr) {
6692abc475SAndres Salomon 	case JFFS2_COMPR_MODE_NONE:
6792abc475SAndres Salomon 		return "none";
68123005f3SAndres Salomon #ifdef CONFIG_JFFS2_LZO
69123005f3SAndres Salomon 	case JFFS2_COMPR_MODE_FORCELZO:
70123005f3SAndres Salomon 		return "lzo";
71123005f3SAndres Salomon #endif
72123005f3SAndres Salomon #ifdef CONFIG_JFFS2_ZLIB
73123005f3SAndres Salomon 	case JFFS2_COMPR_MODE_FORCEZLIB:
74123005f3SAndres Salomon 		return "zlib";
75123005f3SAndres Salomon #endif
7692abc475SAndres Salomon 	default:
7792abc475SAndres Salomon 		/* should never happen; programmer error */
7892abc475SAndres Salomon 		WARN_ON(1);
7992abc475SAndres Salomon 		return "";
8092abc475SAndres Salomon 	}
8192abc475SAndres Salomon }
8292abc475SAndres Salomon 
8334c80b1dSAl Viro static int jffs2_show_options(struct seq_file *s, struct dentry *root)
8492abc475SAndres Salomon {
8534c80b1dSAl Viro 	struct jffs2_sb_info *c = JFFS2_SB_INFO(root->d_sb);
8692abc475SAndres Salomon 	struct jffs2_mount_opts *opts = &c->mount_opts;
8792abc475SAndres Salomon 
8892abc475SAndres Salomon 	if (opts->override_compr)
8992abc475SAndres Salomon 		seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr));
908da8ba2eSDaniel Drake 	if (opts->rp_size)
918da8ba2eSDaniel Drake 		seq_printf(s, ",rp_size=%u", opts->rp_size / 1024);
9292abc475SAndres Salomon 
9392abc475SAndres Salomon 	return 0;
9492abc475SAndres Salomon }
9592abc475SAndres Salomon 
961da177e4SLinus Torvalds static int jffs2_sync_fs(struct super_block *sb, int wait)
971da177e4SLinus Torvalds {
981da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
991da177e4SLinus Torvalds 
100a445f784SArtem Bityutskiy #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
101a788c527SDaniel Santos 	if (jffs2_is_writebuffered(c))
102a445f784SArtem Bityutskiy 		cancel_delayed_work_sync(&c->wbuf_dwork);
103a445f784SArtem Bityutskiy #endif
104a445f784SArtem Bityutskiy 
105ced22070SDavid Woodhouse 	mutex_lock(&c->alloc_sem);
1061da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
107ced22070SDavid Woodhouse 	mutex_unlock(&c->alloc_sem);
1081da177e4SLinus Torvalds 	return 0;
1091da177e4SLinus Torvalds }
1101da177e4SLinus Torvalds 
1115f556aabSDavid Woodhouse static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
1125f556aabSDavid Woodhouse 					 uint32_t generation)
1135f556aabSDavid Woodhouse {
1145f556aabSDavid Woodhouse 	/* We don't care about i_generation. We'll destroy the flash
1155f556aabSDavid Woodhouse 	   before we start re-using inode numbers anyway. And even
1165f556aabSDavid Woodhouse 	   if that wasn't true, we'd have other problems...*/
1175f556aabSDavid Woodhouse 	return jffs2_iget(sb, ino);
1185f556aabSDavid Woodhouse }
1195f556aabSDavid Woodhouse 
1205f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
1215f556aabSDavid Woodhouse 					 int fh_len, int fh_type)
1225f556aabSDavid Woodhouse {
1235f556aabSDavid Woodhouse         return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
1245f556aabSDavid Woodhouse                                     jffs2_nfs_get_inode);
1255f556aabSDavid Woodhouse }
1265f556aabSDavid Woodhouse 
1275f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid,
1285f556aabSDavid Woodhouse 					 int fh_len, int fh_type)
1295f556aabSDavid Woodhouse {
1305f556aabSDavid Woodhouse         return generic_fh_to_parent(sb, fid, fh_len, fh_type,
1315f556aabSDavid Woodhouse                                     jffs2_nfs_get_inode);
1325f556aabSDavid Woodhouse }
1335f556aabSDavid Woodhouse 
1345f556aabSDavid Woodhouse static struct dentry *jffs2_get_parent(struct dentry *child)
1355f556aabSDavid Woodhouse {
1365f556aabSDavid Woodhouse 	struct jffs2_inode_info *f;
1375f556aabSDavid Woodhouse 	uint32_t pino;
1385f556aabSDavid Woodhouse 
139e36cb0b8SDavid Howells 	BUG_ON(!d_is_dir(child));
1405f556aabSDavid Woodhouse 
1412b0143b5SDavid Howells 	f = JFFS2_INODE_INFO(d_inode(child));
1425f556aabSDavid Woodhouse 
1435f556aabSDavid Woodhouse 	pino = f->inocache->pino_nlink;
1445f556aabSDavid Woodhouse 
1455f556aabSDavid Woodhouse 	JFFS2_DEBUG("Parent of directory ino #%u is #%u\n",
1465f556aabSDavid Woodhouse 		    f->inocache->ino, pino);
1475f556aabSDavid Woodhouse 
148fc64005cSAl Viro 	return d_obtain_alias(jffs2_iget(child->d_sb, pino));
1495f556aabSDavid Woodhouse }
1505f556aabSDavid Woodhouse 
151ac4cfdd6SAlexey Dobriyan static const struct export_operations jffs2_export_ops = {
1525f556aabSDavid Woodhouse 	.get_parent = jffs2_get_parent,
1535f556aabSDavid Woodhouse 	.fh_to_dentry = jffs2_fh_to_dentry,
1545f556aabSDavid Woodhouse 	.fh_to_parent = jffs2_fh_to_parent,
1555f556aabSDavid Woodhouse };
1565f556aabSDavid Woodhouse 
15792abc475SAndres Salomon /*
15892abc475SAndres Salomon  * JFFS2 mount options.
15992abc475SAndres Salomon  *
16092abc475SAndres Salomon  * Opt_override_compr: override default compressor
1618da8ba2eSDaniel Drake  * Opt_rp_size: size of reserved pool in KiB
16292abc475SAndres Salomon  * Opt_err: just end of array marker
16392abc475SAndres Salomon  */
16492abc475SAndres Salomon enum {
16592abc475SAndres Salomon 	Opt_override_compr,
1668da8ba2eSDaniel Drake 	Opt_rp_size,
16792abc475SAndres Salomon 	Opt_err,
16892abc475SAndres Salomon };
16992abc475SAndres Salomon 
17092abc475SAndres Salomon static const match_table_t tokens = {
17192abc475SAndres Salomon 	{Opt_override_compr, "compr=%s"},
1728da8ba2eSDaniel Drake 	{Opt_rp_size, "rp_size=%u"},
17392abc475SAndres Salomon 	{Opt_err, NULL},
17492abc475SAndres Salomon };
17592abc475SAndres Salomon 
17692abc475SAndres Salomon static int jffs2_parse_options(struct jffs2_sb_info *c, char *data)
17792abc475SAndres Salomon {
17892abc475SAndres Salomon 	substring_t args[MAX_OPT_ARGS];
17992abc475SAndres Salomon 	char *p, *name;
1808da8ba2eSDaniel Drake 	unsigned int opt;
18192abc475SAndres Salomon 
18292abc475SAndres Salomon 	if (!data)
18392abc475SAndres Salomon 		return 0;
18492abc475SAndres Salomon 
18592abc475SAndres Salomon 	while ((p = strsep(&data, ","))) {
18692abc475SAndres Salomon 		int token;
18792abc475SAndres Salomon 
18892abc475SAndres Salomon 		if (!*p)
18992abc475SAndres Salomon 			continue;
19092abc475SAndres Salomon 
19192abc475SAndres Salomon 		token = match_token(p, tokens, args);
19292abc475SAndres Salomon 		switch (token) {
19392abc475SAndres Salomon 		case Opt_override_compr:
19492abc475SAndres Salomon 			name = match_strdup(&args[0]);
19592abc475SAndres Salomon 
19692abc475SAndres Salomon 			if (!name)
19792abc475SAndres Salomon 				return -ENOMEM;
198123005f3SAndres Salomon 			if (!strcmp(name, "none"))
19992abc475SAndres Salomon 				c->mount_opts.compr = JFFS2_COMPR_MODE_NONE;
200123005f3SAndres Salomon #ifdef CONFIG_JFFS2_LZO
201123005f3SAndres Salomon 			else if (!strcmp(name, "lzo"))
202123005f3SAndres Salomon 				c->mount_opts.compr = JFFS2_COMPR_MODE_FORCELZO;
203123005f3SAndres Salomon #endif
204123005f3SAndres Salomon #ifdef CONFIG_JFFS2_ZLIB
205123005f3SAndres Salomon 			else if (!strcmp(name, "zlib"))
206123005f3SAndres Salomon 				c->mount_opts.compr =
207123005f3SAndres Salomon 						JFFS2_COMPR_MODE_FORCEZLIB;
208123005f3SAndres Salomon #endif
209123005f3SAndres Salomon 			else {
2105a528957SJoe Perches 				pr_err("Error: unknown compressor \"%s\"\n",
211123005f3SAndres Salomon 				       name);
212123005f3SAndres Salomon 				kfree(name);
213123005f3SAndres Salomon 				return -EINVAL;
21492abc475SAndres Salomon 			}
21592abc475SAndres Salomon 			kfree(name);
216123005f3SAndres Salomon 			c->mount_opts.override_compr = true;
21792abc475SAndres Salomon 			break;
2188da8ba2eSDaniel Drake 		case Opt_rp_size:
2198da8ba2eSDaniel Drake 			if (match_int(&args[0], &opt))
2208da8ba2eSDaniel Drake 				return -EINVAL;
2218da8ba2eSDaniel Drake 			opt *= 1024;
2228da8ba2eSDaniel Drake 			if (opt > c->mtd->size) {
2238da8ba2eSDaniel Drake 				pr_warn("Too large reserve pool specified, max "
2248da8ba2eSDaniel Drake 					"is %llu KB\n", c->mtd->size / 1024);
2258da8ba2eSDaniel Drake 				return -EINVAL;
2268da8ba2eSDaniel Drake 			}
2278da8ba2eSDaniel Drake 			c->mount_opts.rp_size = opt;
2288da8ba2eSDaniel Drake 			break;
22992abc475SAndres Salomon 		default:
2305a528957SJoe Perches 			pr_err("Error: unrecognized mount option '%s' or missing value\n",
23192abc475SAndres Salomon 			       p);
23292abc475SAndres Salomon 			return -EINVAL;
23392abc475SAndres Salomon 		}
23492abc475SAndres Salomon 	}
23592abc475SAndres Salomon 
23692abc475SAndres Salomon 	return 0;
23792abc475SAndres Salomon }
23892abc475SAndres Salomon 
23992abc475SAndres Salomon static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data)
24092abc475SAndres Salomon {
24192abc475SAndres Salomon 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
24292abc475SAndres Salomon 	int err;
24392abc475SAndres Salomon 
24402b9984dSTheodore Ts'o 	sync_filesystem(sb);
24592abc475SAndres Salomon 	err = jffs2_parse_options(c, data);
24692abc475SAndres Salomon 	if (err)
24792abc475SAndres Salomon 		return -EINVAL;
24892abc475SAndres Salomon 
24992abc475SAndres Salomon 	return jffs2_do_remount_fs(sb, flags, data);
25092abc475SAndres Salomon }
25192abc475SAndres Salomon 
252ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jffs2_super_operations =
2531da177e4SLinus Torvalds {
2541da177e4SLinus Torvalds 	.alloc_inode =	jffs2_alloc_inode,
255db0bd7b7SAl Viro 	.free_inode =	jffs2_free_inode,
2561da177e4SLinus Torvalds 	.put_super =	jffs2_put_super,
2571da177e4SLinus Torvalds 	.statfs =	jffs2_statfs,
2581da177e4SLinus Torvalds 	.remount_fs =	jffs2_remount_fs,
259b57922d9SAl Viro 	.evict_inode =	jffs2_evict_inode,
2601da177e4SLinus Torvalds 	.dirty_inode =	jffs2_dirty_inode,
26192abc475SAndres Salomon 	.show_options =	jffs2_show_options,
2621da177e4SLinus Torvalds 	.sync_fs =	jffs2_sync_fs,
2631da177e4SLinus Torvalds };
2641da177e4SLinus Torvalds 
265acaebfd8SDavid Howells /*
266acaebfd8SDavid Howells  * fill in the superblock
267acaebfd8SDavid Howells  */
268acaebfd8SDavid Howells static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
2691da177e4SLinus Torvalds {
2701da177e4SLinus Torvalds 	struct jffs2_sb_info *c;
271db719222SJan Blunck 	int ret;
272db719222SJan Blunck 
2739c261b33SJoe Perches 	jffs2_dbg(1, "jffs2_get_sb_mtd():"
274acaebfd8SDavid Howells 		  " New superblock for device %d (\"%s\")\n",
2759c261b33SJoe Perches 		  sb->s_mtd->index, sb->s_mtd->name);
2761da177e4SLinus Torvalds 
277f8314dc6SPanagiotis Issaris 	c = kzalloc(sizeof(*c), GFP_KERNEL);
2781a028dd2SArnd Bergmann 	if (!c)
279454e2398SDavid Howells 		return -ENOMEM;
2801da177e4SLinus Torvalds 
281acaebfd8SDavid Howells 	c->mtd = sb->s_mtd;
282acaebfd8SDavid Howells 	c->os_priv = sb;
283acaebfd8SDavid Howells 	sb->s_fs_info = c;
2841da177e4SLinus Torvalds 
28592abc475SAndres Salomon 	ret = jffs2_parse_options(c, data);
28692e2921fSHou Tao 	if (ret)
28792abc475SAndres Salomon 		return -EINVAL;
28892abc475SAndres Salomon 
289acaebfd8SDavid Howells 	/* Initialize JFFS2 superblock locks, the further initialization will
290acaebfd8SDavid Howells 	 * be done later */
291ced22070SDavid Woodhouse 	mutex_init(&c->alloc_sem);
292ced22070SDavid Woodhouse 	mutex_init(&c->erase_free_sem);
293b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->erase_wait);
294b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->inocache_wq);
295b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->erase_completion_lock);
296b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->inocache_lock);
297b6220598SArtem B. Bityuckiy 
2981da177e4SLinus Torvalds 	sb->s_op = &jffs2_super_operations;
2995f556aabSDavid Woodhouse 	sb->s_export_op = &jffs2_export_ops;
3001751e8a6SLinus Torvalds 	sb->s_flags = sb->s_flags | SB_NOATIME;
301aa98d7cfSKaiGai Kohei 	sb->s_xattr = jffs2_xattr_handlers;
302aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL
3031751e8a6SLinus Torvalds 	sb->s_flags |= SB_POSIXACL;
304aa98d7cfSKaiGai Kohei #endif
305db719222SJan Blunck 	ret = jffs2_do_fill_super(sb, data, silent);
306db719222SJan Blunck 	return ret;
3071da177e4SLinus Torvalds }
3081da177e4SLinus Torvalds 
309848b83a5SAl Viro static struct dentry *jffs2_mount(struct file_system_type *fs_type,
3101da177e4SLinus Torvalds 			int flags, const char *dev_name,
311848b83a5SAl Viro 			void *data)
3121da177e4SLinus Torvalds {
313848b83a5SAl Viro 	return mount_mtd(fs_type, flags, dev_name, data, jffs2_fill_super);
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds 
3161da177e4SLinus Torvalds static void jffs2_put_super (struct super_block *sb)
3171da177e4SLinus Torvalds {
3181da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
3191da177e4SLinus Torvalds 
3209c261b33SJoe Perches 	jffs2_dbg(2, "%s()\n", __func__);
3211da177e4SLinus Torvalds 
322ced22070SDavid Woodhouse 	mutex_lock(&c->alloc_sem);
3231da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
324ced22070SDavid Woodhouse 	mutex_unlock(&c->alloc_sem);
325e631ddbaSFerenc Havasi 
326e631ddbaSFerenc Havasi 	jffs2_sum_exit(c);
327e631ddbaSFerenc Havasi 
3281da177e4SLinus Torvalds 	jffs2_free_ino_caches(c);
3291da177e4SLinus Torvalds 	jffs2_free_raw_node_refs(c);
3301d5cfdb0STetsuo Handa 	kvfree(c->blocks);
3311da177e4SLinus Torvalds 	jffs2_flash_cleanup(c);
3321da177e4SLinus Torvalds 	kfree(c->inocache_list);
333aa98d7cfSKaiGai Kohei 	jffs2_clear_xattr_subsystem(c);
33485f2f2a8SArtem Bityutskiy 	mtd_sync(c->mtd);
3359c261b33SJoe Perches 	jffs2_dbg(1, "%s(): returning\n", __func__);
3361da177e4SLinus Torvalds }
3371da177e4SLinus Torvalds 
3381da177e4SLinus Torvalds static void jffs2_kill_sb(struct super_block *sb)
3391da177e4SLinus Torvalds {
3401da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
341c66b23c2SAl Viro 	if (c && !sb_rdonly(sb))
342a69dde91SArtem B. Bityuckiy 		jffs2_stop_garbage_collect_thread(c);
343acaebfd8SDavid Howells 	kill_mtd_super(sb);
3441da177e4SLinus Torvalds 	kfree(c);
3451da177e4SLinus Torvalds }
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds static struct file_system_type jffs2_fs_type = {
3481da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
3491da177e4SLinus Torvalds 	.name =		"jffs2",
350848b83a5SAl Viro 	.mount =	jffs2_mount,
3511da177e4SLinus Torvalds 	.kill_sb =	jffs2_kill_sb,
3521da177e4SLinus Torvalds };
3537f78e035SEric W. Biederman MODULE_ALIAS_FS("jffs2");
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds static int __init init_jffs2_fs(void)
3561da177e4SLinus Torvalds {
3571da177e4SLinus Torvalds 	int ret;
3581da177e4SLinus Torvalds 
3593e68fbb5SDavid Woodhouse 	/* Paranoia checks for on-medium structures. If we ask GCC
3603e68fbb5SDavid Woodhouse 	   to pack them with __attribute__((packed)) then it _also_
3613e68fbb5SDavid Woodhouse 	   assumes that they're not aligned -- so it emits crappy
3623e68fbb5SDavid Woodhouse 	   code on some architectures. Ideally we want an attribute
3633e68fbb5SDavid Woodhouse 	   which means just 'no padding', without the alignment
3643e68fbb5SDavid Woodhouse 	   thing. But GCC doesn't have that -- we have to just
3653e68fbb5SDavid Woodhouse 	   hope the structs are the right sizes, instead. */
3662ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
3672ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
3682ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
3692ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
3703e68fbb5SDavid Woodhouse 
3715a528957SJoe Perches 	pr_info("version 2.2."
3722f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
3731da177e4SLinus Torvalds 	       " (NAND)"
3741da177e4SLinus Torvalds #endif
375e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY
376e631ddbaSFerenc Havasi 	       " (SUMMARY) "
377e631ddbaSFerenc Havasi #endif
378c00c310eSDavid Woodhouse 	       " © 2001-2006 Red Hat, Inc.\n");
3791da177e4SLinus Torvalds 
3801da177e4SLinus Torvalds 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
3811da177e4SLinus Torvalds 					     sizeof(struct jffs2_inode_info),
382fffb60f9SPaul Jackson 					     0, (SLAB_RECLAIM_ACCOUNT|
3835d097056SVladimir Davydov 						SLAB_MEM_SPREAD|SLAB_ACCOUNT),
38420c2df83SPaul Mundt 					     jffs2_i_init_once);
3851da177e4SLinus Torvalds 	if (!jffs2_inode_cachep) {
3865a528957SJoe Perches 		pr_err("error: Failed to initialise inode cache\n");
3871da177e4SLinus Torvalds 		return -ENOMEM;
3881da177e4SLinus Torvalds 	}
3891da177e4SLinus Torvalds 	ret = jffs2_compressors_init();
3901da177e4SLinus Torvalds 	if (ret) {
3915a528957SJoe Perches 		pr_err("error: Failed to initialise compressors\n");
3921da177e4SLinus Torvalds 		goto out;
3931da177e4SLinus Torvalds 	}
3941da177e4SLinus Torvalds 	ret = jffs2_create_slab_caches();
3951da177e4SLinus Torvalds 	if (ret) {
3965a528957SJoe Perches 		pr_err("error: Failed to initialise slab caches\n");
3971da177e4SLinus Torvalds 		goto out_compressors;
3981da177e4SLinus Torvalds 	}
3991da177e4SLinus Torvalds 	ret = register_filesystem(&jffs2_fs_type);
4001da177e4SLinus Torvalds 	if (ret) {
4015a528957SJoe Perches 		pr_err("error: Failed to register filesystem\n");
4021da177e4SLinus Torvalds 		goto out_slab;
4031da177e4SLinus Torvalds 	}
4041da177e4SLinus Torvalds 	return 0;
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds  out_slab:
4071da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
4081da177e4SLinus Torvalds  out_compressors:
4091da177e4SLinus Torvalds 	jffs2_compressors_exit();
4101da177e4SLinus Torvalds  out:
4111da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
4121da177e4SLinus Torvalds 	return ret;
4131da177e4SLinus Torvalds }
4141da177e4SLinus Torvalds 
4151da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void)
4161da177e4SLinus Torvalds {
4171da177e4SLinus Torvalds 	unregister_filesystem(&jffs2_fs_type);
4181da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
4191da177e4SLinus Torvalds 	jffs2_compressors_exit();
4208c0a8537SKirill A. Shutemov 
4218c0a8537SKirill A. Shutemov 	/*
4228c0a8537SKirill A. Shutemov 	 * Make sure all delayed rcu free inodes are flushed before we
4238c0a8537SKirill A. Shutemov 	 * destroy cache.
4248c0a8537SKirill A. Shutemov 	 */
4258c0a8537SKirill A. Shutemov 	rcu_barrier();
4261da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
4271da177e4SLinus Torvalds }
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds module_init(init_jffs2_fs);
4301da177e4SLinus Torvalds module_exit(exit_jffs2_fs);
4311da177e4SLinus Torvalds 
4321da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journalling Flash File System, v2");
4331da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc.");
4341da177e4SLinus Torvalds MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
4351da177e4SLinus Torvalds 		       // the sake of this tag. It's Free Software.
436