xref: /openbmc/linux/fs/jffs2/super.c (revision ec10a24f)
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 {
166ec10a24fSDavid Howells 	Opt_source,
16792abc475SAndres Salomon 	Opt_override_compr,
1688da8ba2eSDaniel Drake 	Opt_rp_size,
16992abc475SAndres Salomon };
17092abc475SAndres Salomon 
171ec10a24fSDavid Howells static const struct fs_parameter_spec jffs2_param_specs[] = {
172ec10a24fSDavid Howells 	fsparam_string	("source",	Opt_source),
173ec10a24fSDavid Howells 	fsparam_enum	("compr",	Opt_override_compr),
174ec10a24fSDavid Howells 	fsparam_u32	("rp_size",	Opt_rp_size),
175ec10a24fSDavid Howells 	{}
17692abc475SAndres Salomon };
17792abc475SAndres Salomon 
178ec10a24fSDavid Howells static const struct fs_parameter_enum jffs2_param_enums[] = {
179ec10a24fSDavid Howells 	{ Opt_override_compr,	"none",	JFFS2_COMPR_MODE_NONE },
180123005f3SAndres Salomon #ifdef CONFIG_JFFS2_LZO
181ec10a24fSDavid Howells 	{ Opt_override_compr,	"lzo",	JFFS2_COMPR_MODE_FORCELZO },
182123005f3SAndres Salomon #endif
183123005f3SAndres Salomon #ifdef CONFIG_JFFS2_ZLIB
184ec10a24fSDavid Howells 	{ Opt_override_compr,	"zlib",	JFFS2_COMPR_MODE_FORCEZLIB },
185123005f3SAndres Salomon #endif
186ec10a24fSDavid Howells 	{}
187ec10a24fSDavid Howells };
188ec10a24fSDavid Howells 
189ec10a24fSDavid Howells const struct fs_parameter_description jffs2_fs_parameters = {
190ec10a24fSDavid Howells 	.name		= "jffs2",
191ec10a24fSDavid Howells 	.specs		= jffs2_param_specs,
192ec10a24fSDavid Howells 	.enums		= jffs2_param_enums,
193ec10a24fSDavid Howells };
194ec10a24fSDavid Howells 
195ec10a24fSDavid Howells static int jffs2_parse_param(struct fs_context *fc, struct fs_parameter *param)
196ec10a24fSDavid Howells {
197ec10a24fSDavid Howells 	struct fs_parse_result result;
198ec10a24fSDavid Howells 	struct jffs2_sb_info *c = fc->s_fs_info;
199ec10a24fSDavid Howells 	int opt;
200ec10a24fSDavid Howells 
201ec10a24fSDavid Howells 	opt = fs_parse(fc, &jffs2_fs_parameters, param, &result);
202ec10a24fSDavid Howells 	if (opt < 0)
203ec10a24fSDavid Howells 		return opt;
204ec10a24fSDavid Howells 
205ec10a24fSDavid Howells 	switch (opt) {
206ec10a24fSDavid Howells 	case Opt_override_compr:
207ec10a24fSDavid Howells 		c->mount_opts.compr = result.uint_32;
208123005f3SAndres Salomon 		c->mount_opts.override_compr = true;
20992abc475SAndres Salomon 		break;
2108da8ba2eSDaniel Drake 	case Opt_rp_size:
211ec10a24fSDavid Howells 		if (result.uint_32 > UINT_MAX / 1024)
212ec10a24fSDavid Howells 			return invalf(fc, "jffs2: rp_size unrepresentable");
213ec10a24fSDavid Howells 		opt = result.uint_32 * 1024;
214ec10a24fSDavid Howells 		if (opt > c->mtd->size)
215ec10a24fSDavid Howells 			return invalf(fc, "jffs2: Too large reserve pool specified, max is %llu KB",
216ec10a24fSDavid Howells 				      c->mtd->size / 1024);
2178da8ba2eSDaniel Drake 		c->mount_opts.rp_size = opt;
2188da8ba2eSDaniel Drake 		break;
21992abc475SAndres Salomon 	default:
22092abc475SAndres Salomon 		return -EINVAL;
22192abc475SAndres Salomon 	}
22292abc475SAndres Salomon 
22392abc475SAndres Salomon 	return 0;
22492abc475SAndres Salomon }
22592abc475SAndres Salomon 
226ec10a24fSDavid Howells static int jffs2_reconfigure(struct fs_context *fc)
22792abc475SAndres Salomon {
228ec10a24fSDavid Howells 	struct super_block *sb = fc->root->d_sb;
22992abc475SAndres Salomon 
23002b9984dSTheodore Ts'o 	sync_filesystem(sb);
231ec10a24fSDavid Howells 	return jffs2_do_remount_fs(sb, fc);
23292abc475SAndres Salomon }
23392abc475SAndres Salomon 
234ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jffs2_super_operations =
2351da177e4SLinus Torvalds {
2361da177e4SLinus Torvalds 	.alloc_inode =	jffs2_alloc_inode,
237db0bd7b7SAl Viro 	.free_inode =	jffs2_free_inode,
2381da177e4SLinus Torvalds 	.put_super =	jffs2_put_super,
2391da177e4SLinus Torvalds 	.statfs =	jffs2_statfs,
240b57922d9SAl Viro 	.evict_inode =	jffs2_evict_inode,
2411da177e4SLinus Torvalds 	.dirty_inode =	jffs2_dirty_inode,
24292abc475SAndres Salomon 	.show_options =	jffs2_show_options,
2431da177e4SLinus Torvalds 	.sync_fs =	jffs2_sync_fs,
2441da177e4SLinus Torvalds };
2451da177e4SLinus Torvalds 
246acaebfd8SDavid Howells /*
247acaebfd8SDavid Howells  * fill in the superblock
248acaebfd8SDavid Howells  */
249ec10a24fSDavid Howells static int jffs2_fill_super(struct super_block *sb, struct fs_context *fc)
2501da177e4SLinus Torvalds {
251ec10a24fSDavid Howells 	struct jffs2_sb_info *c = sb->s_fs_info;
252db719222SJan Blunck 
2539c261b33SJoe Perches 	jffs2_dbg(1, "jffs2_get_sb_mtd():"
254acaebfd8SDavid Howells 		  " New superblock for device %d (\"%s\")\n",
2559c261b33SJoe Perches 		  sb->s_mtd->index, sb->s_mtd->name);
2561da177e4SLinus Torvalds 
257acaebfd8SDavid Howells 	c->mtd = sb->s_mtd;
258acaebfd8SDavid Howells 	c->os_priv = sb;
25992abc475SAndres Salomon 
260acaebfd8SDavid Howells 	/* Initialize JFFS2 superblock locks, the further initialization will
261acaebfd8SDavid Howells 	 * be done later */
262ced22070SDavid Woodhouse 	mutex_init(&c->alloc_sem);
263ced22070SDavid Woodhouse 	mutex_init(&c->erase_free_sem);
264b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->erase_wait);
265b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->inocache_wq);
266b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->erase_completion_lock);
267b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->inocache_lock);
268b6220598SArtem B. Bityuckiy 
2691da177e4SLinus Torvalds 	sb->s_op = &jffs2_super_operations;
2705f556aabSDavid Woodhouse 	sb->s_export_op = &jffs2_export_ops;
2711751e8a6SLinus Torvalds 	sb->s_flags = sb->s_flags | SB_NOATIME;
272aa98d7cfSKaiGai Kohei 	sb->s_xattr = jffs2_xattr_handlers;
273aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL
2741751e8a6SLinus Torvalds 	sb->s_flags |= SB_POSIXACL;
275aa98d7cfSKaiGai Kohei #endif
276ec10a24fSDavid Howells 	return jffs2_do_fill_super(sb, fc);
2771da177e4SLinus Torvalds }
2781da177e4SLinus Torvalds 
279ec10a24fSDavid Howells static int jffs2_get_tree(struct fs_context *fc)
2801da177e4SLinus Torvalds {
281ec10a24fSDavid Howells 	return get_tree_mtd(fc, jffs2_fill_super);
282ec10a24fSDavid Howells }
283ec10a24fSDavid Howells 
284ec10a24fSDavid Howells static void jffs2_free_fc(struct fs_context *fc)
285ec10a24fSDavid Howells {
286ec10a24fSDavid Howells 	kfree(fc->s_fs_info);
287ec10a24fSDavid Howells }
288ec10a24fSDavid Howells 
289ec10a24fSDavid Howells static const struct fs_context_operations jffs2_context_ops = {
290ec10a24fSDavid Howells 	.free		= jffs2_free_fc,
291ec10a24fSDavid Howells 	.parse_param	= jffs2_parse_param,
292ec10a24fSDavid Howells 	.get_tree	= jffs2_get_tree,
293ec10a24fSDavid Howells 	.reconfigure	= jffs2_reconfigure,
294ec10a24fSDavid Howells };
295ec10a24fSDavid Howells 
296ec10a24fSDavid Howells static int jffs2_init_fs_context(struct fs_context *fc)
297ec10a24fSDavid Howells {
298ec10a24fSDavid Howells 	struct jffs2_sb_info *ctx;
299ec10a24fSDavid Howells 
300ec10a24fSDavid Howells 	ctx = kzalloc(sizeof(struct jffs2_sb_info), GFP_KERNEL);
301ec10a24fSDavid Howells 	if (!ctx)
302ec10a24fSDavid Howells 		return -ENOMEM;
303ec10a24fSDavid Howells 
304ec10a24fSDavid Howells 	fc->s_fs_info = ctx;
305ec10a24fSDavid Howells 	fc->ops = &jffs2_context_ops;
306ec10a24fSDavid Howells 	return 0;
3071da177e4SLinus Torvalds }
3081da177e4SLinus Torvalds 
3091da177e4SLinus Torvalds static void jffs2_put_super (struct super_block *sb)
3101da177e4SLinus Torvalds {
3111da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
3121da177e4SLinus Torvalds 
3139c261b33SJoe Perches 	jffs2_dbg(2, "%s()\n", __func__);
3141da177e4SLinus Torvalds 
315ced22070SDavid Woodhouse 	mutex_lock(&c->alloc_sem);
3161da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
317ced22070SDavid Woodhouse 	mutex_unlock(&c->alloc_sem);
318e631ddbaSFerenc Havasi 
319e631ddbaSFerenc Havasi 	jffs2_sum_exit(c);
320e631ddbaSFerenc Havasi 
3211da177e4SLinus Torvalds 	jffs2_free_ino_caches(c);
3221da177e4SLinus Torvalds 	jffs2_free_raw_node_refs(c);
3231d5cfdb0STetsuo Handa 	kvfree(c->blocks);
3241da177e4SLinus Torvalds 	jffs2_flash_cleanup(c);
3251da177e4SLinus Torvalds 	kfree(c->inocache_list);
326aa98d7cfSKaiGai Kohei 	jffs2_clear_xattr_subsystem(c);
32785f2f2a8SArtem Bityutskiy 	mtd_sync(c->mtd);
3289c261b33SJoe Perches 	jffs2_dbg(1, "%s(): returning\n", __func__);
3291da177e4SLinus Torvalds }
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds static void jffs2_kill_sb(struct super_block *sb)
3321da177e4SLinus Torvalds {
3331da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
334c66b23c2SAl Viro 	if (c && !sb_rdonly(sb))
335a69dde91SArtem B. Bityuckiy 		jffs2_stop_garbage_collect_thread(c);
336acaebfd8SDavid Howells 	kill_mtd_super(sb);
3371da177e4SLinus Torvalds 	kfree(c);
3381da177e4SLinus Torvalds }
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds static struct file_system_type jffs2_fs_type = {
3411da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
3421da177e4SLinus Torvalds 	.name =		"jffs2",
343ec10a24fSDavid Howells 	.init_fs_context = jffs2_init_fs_context,
344ec10a24fSDavid Howells 	.parameters =	&jffs2_fs_parameters,
3451da177e4SLinus Torvalds 	.kill_sb =	jffs2_kill_sb,
3461da177e4SLinus Torvalds };
3477f78e035SEric W. Biederman MODULE_ALIAS_FS("jffs2");
3481da177e4SLinus Torvalds 
3491da177e4SLinus Torvalds static int __init init_jffs2_fs(void)
3501da177e4SLinus Torvalds {
3511da177e4SLinus Torvalds 	int ret;
3521da177e4SLinus Torvalds 
3533e68fbb5SDavid Woodhouse 	/* Paranoia checks for on-medium structures. If we ask GCC
3543e68fbb5SDavid Woodhouse 	   to pack them with __attribute__((packed)) then it _also_
3553e68fbb5SDavid Woodhouse 	   assumes that they're not aligned -- so it emits crappy
3563e68fbb5SDavid Woodhouse 	   code on some architectures. Ideally we want an attribute
3573e68fbb5SDavid Woodhouse 	   which means just 'no padding', without the alignment
3583e68fbb5SDavid Woodhouse 	   thing. But GCC doesn't have that -- we have to just
3593e68fbb5SDavid Woodhouse 	   hope the structs are the right sizes, instead. */
3602ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
3612ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
3622ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
3632ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
3643e68fbb5SDavid Woodhouse 
3655a528957SJoe Perches 	pr_info("version 2.2."
3662f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
3671da177e4SLinus Torvalds 	       " (NAND)"
3681da177e4SLinus Torvalds #endif
369e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY
370e631ddbaSFerenc Havasi 	       " (SUMMARY) "
371e631ddbaSFerenc Havasi #endif
372c00c310eSDavid Woodhouse 	       " © 2001-2006 Red Hat, Inc.\n");
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
3751da177e4SLinus Torvalds 					     sizeof(struct jffs2_inode_info),
376fffb60f9SPaul Jackson 					     0, (SLAB_RECLAIM_ACCOUNT|
3775d097056SVladimir Davydov 						SLAB_MEM_SPREAD|SLAB_ACCOUNT),
37820c2df83SPaul Mundt 					     jffs2_i_init_once);
3791da177e4SLinus Torvalds 	if (!jffs2_inode_cachep) {
3805a528957SJoe Perches 		pr_err("error: Failed to initialise inode cache\n");
3811da177e4SLinus Torvalds 		return -ENOMEM;
3821da177e4SLinus Torvalds 	}
3831da177e4SLinus Torvalds 	ret = jffs2_compressors_init();
3841da177e4SLinus Torvalds 	if (ret) {
3855a528957SJoe Perches 		pr_err("error: Failed to initialise compressors\n");
3861da177e4SLinus Torvalds 		goto out;
3871da177e4SLinus Torvalds 	}
3881da177e4SLinus Torvalds 	ret = jffs2_create_slab_caches();
3891da177e4SLinus Torvalds 	if (ret) {
3905a528957SJoe Perches 		pr_err("error: Failed to initialise slab caches\n");
3911da177e4SLinus Torvalds 		goto out_compressors;
3921da177e4SLinus Torvalds 	}
3931da177e4SLinus Torvalds 	ret = register_filesystem(&jffs2_fs_type);
3941da177e4SLinus Torvalds 	if (ret) {
3955a528957SJoe Perches 		pr_err("error: Failed to register filesystem\n");
3961da177e4SLinus Torvalds 		goto out_slab;
3971da177e4SLinus Torvalds 	}
3981da177e4SLinus Torvalds 	return 0;
3991da177e4SLinus Torvalds 
4001da177e4SLinus Torvalds  out_slab:
4011da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
4021da177e4SLinus Torvalds  out_compressors:
4031da177e4SLinus Torvalds 	jffs2_compressors_exit();
4041da177e4SLinus Torvalds  out:
4051da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
4061da177e4SLinus Torvalds 	return ret;
4071da177e4SLinus Torvalds }
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void)
4101da177e4SLinus Torvalds {
4111da177e4SLinus Torvalds 	unregister_filesystem(&jffs2_fs_type);
4121da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
4131da177e4SLinus Torvalds 	jffs2_compressors_exit();
4148c0a8537SKirill A. Shutemov 
4158c0a8537SKirill A. Shutemov 	/*
4168c0a8537SKirill A. Shutemov 	 * Make sure all delayed rcu free inodes are flushed before we
4178c0a8537SKirill A. Shutemov 	 * destroy cache.
4188c0a8537SKirill A. Shutemov 	 */
4198c0a8537SKirill A. Shutemov 	rcu_barrier();
4201da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
4211da177e4SLinus Torvalds }
4221da177e4SLinus Torvalds 
4231da177e4SLinus Torvalds module_init(init_jffs2_fs);
4241da177e4SLinus Torvalds module_exit(exit_jffs2_fs);
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journalling Flash File System, v2");
4271da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc.");
4281da177e4SLinus Torvalds MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
4291da177e4SLinus Torvalds 		       // the sake of this tag. It's Free Software.
430