xref: /openbmc/linux/fs/jffs2/super.c (revision 92abc475)
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 
121da177e4SLinus Torvalds #include <linux/kernel.h>
131da177e4SLinus Torvalds #include <linux/module.h>
141da177e4SLinus Torvalds #include <linux/slab.h>
151da177e4SLinus Torvalds #include <linux/init.h>
161da177e4SLinus Torvalds #include <linux/list.h>
171da177e4SLinus Torvalds #include <linux/fs.h>
189c74034fSArtem Bityutskiy #include <linux/err.h>
191da177e4SLinus Torvalds #include <linux/mount.h>
2092abc475SAndres Salomon #include <linux/parser.h>
211da177e4SLinus Torvalds #include <linux/jffs2.h>
221da177e4SLinus Torvalds #include <linux/pagemap.h>
23acaebfd8SDavid Howells #include <linux/mtd/super.h>
241da177e4SLinus Torvalds #include <linux/ctype.h>
251da177e4SLinus Torvalds #include <linux/namei.h>
2692abc475SAndres Salomon #include <linux/seq_file.h>
275f556aabSDavid Woodhouse #include <linux/exportfs.h>
281da177e4SLinus Torvalds #include "compr.h"
291da177e4SLinus Torvalds #include "nodelist.h"
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds static void jffs2_put_super(struct super_block *);
321da177e4SLinus Torvalds 
33e18b890bSChristoph Lameter static struct kmem_cache *jffs2_inode_cachep;
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds static struct inode *jffs2_alloc_inode(struct super_block *sb)
361da177e4SLinus Torvalds {
374e571abaSDavid Woodhouse 	struct jffs2_inode_info *f;
384e571abaSDavid Woodhouse 
394e571abaSDavid Woodhouse 	f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL);
404e571abaSDavid Woodhouse 	if (!f)
411da177e4SLinus Torvalds 		return NULL;
424e571abaSDavid Woodhouse 	return &f->vfs_inode;
431da177e4SLinus Torvalds }
441da177e4SLinus Torvalds 
45fa0d7e3dSNick Piggin static void jffs2_i_callback(struct rcu_head *head)
46fa0d7e3dSNick Piggin {
47fa0d7e3dSNick Piggin 	struct inode *inode = container_of(head, struct inode, i_rcu);
48fa0d7e3dSNick Piggin 	INIT_LIST_HEAD(&inode->i_dentry);
49fa0d7e3dSNick Piggin 	kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode));
50fa0d7e3dSNick Piggin }
51fa0d7e3dSNick Piggin 
521da177e4SLinus Torvalds static void jffs2_destroy_inode(struct inode *inode)
531da177e4SLinus Torvalds {
54fa0d7e3dSNick Piggin 	call_rcu(&inode->i_rcu, jffs2_i_callback);
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds 
5751cc5068SAlexey Dobriyan static void jffs2_i_init_once(void *foo)
581da177e4SLinus Torvalds {
594e571abaSDavid Woodhouse 	struct jffs2_inode_info *f = foo;
601da177e4SLinus Torvalds 
614e571abaSDavid Woodhouse 	mutex_init(&f->sem);
624e571abaSDavid Woodhouse 	inode_init_once(&f->vfs_inode);
631da177e4SLinus Torvalds }
641da177e4SLinus Torvalds 
6501ba6875SChristoph Hellwig static void jffs2_write_super(struct super_block *sb)
6601ba6875SChristoph Hellwig {
6701ba6875SChristoph Hellwig 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
68ebc1ac16SChristoph Hellwig 
69ebc1ac16SChristoph Hellwig 	lock_super(sb);
7001ba6875SChristoph Hellwig 	sb->s_dirt = 0;
7101ba6875SChristoph Hellwig 
72ebc1ac16SChristoph Hellwig 	if (!(sb->s_flags & MS_RDONLY)) {
7301ba6875SChristoph Hellwig 		D1(printk(KERN_DEBUG "jffs2_write_super()\n"));
7401ba6875SChristoph Hellwig 		jffs2_flush_wbuf_gc(c, 0);
7501ba6875SChristoph Hellwig 	}
7601ba6875SChristoph Hellwig 
77ebc1ac16SChristoph Hellwig 	unlock_super(sb);
78ebc1ac16SChristoph Hellwig }
79ebc1ac16SChristoph Hellwig 
8092abc475SAndres Salomon static const char *jffs2_compr_name(unsigned int compr)
8192abc475SAndres Salomon {
8292abc475SAndres Salomon 	switch (compr) {
8392abc475SAndres Salomon 	case JFFS2_COMPR_MODE_NONE:
8492abc475SAndres Salomon 		return "none";
8592abc475SAndres Salomon 	default:
8692abc475SAndres Salomon 		/* should never happen; programmer error */
8792abc475SAndres Salomon 		WARN_ON(1);
8892abc475SAndres Salomon 		return "";
8992abc475SAndres Salomon 	}
9092abc475SAndres Salomon }
9192abc475SAndres Salomon 
9292abc475SAndres Salomon static int jffs2_show_options(struct seq_file *s, struct vfsmount *mnt)
9392abc475SAndres Salomon {
9492abc475SAndres Salomon 	struct jffs2_sb_info *c = JFFS2_SB_INFO(mnt->mnt_sb);
9592abc475SAndres Salomon 	struct jffs2_mount_opts *opts = &c->mount_opts;
9692abc475SAndres Salomon 
9792abc475SAndres Salomon 	if (opts->override_compr)
9892abc475SAndres Salomon 		seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr));
9992abc475SAndres Salomon 
10092abc475SAndres Salomon 	return 0;
10192abc475SAndres Salomon }
10292abc475SAndres Salomon 
1031da177e4SLinus Torvalds static int jffs2_sync_fs(struct super_block *sb, int wait)
1041da177e4SLinus Torvalds {
1051da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
1061da177e4SLinus Torvalds 
107d579ed00SChristoph Hellwig 	jffs2_write_super(sb);
108d579ed00SChristoph Hellwig 
109ced22070SDavid Woodhouse 	mutex_lock(&c->alloc_sem);
1101da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
111ced22070SDavid Woodhouse 	mutex_unlock(&c->alloc_sem);
1121da177e4SLinus Torvalds 	return 0;
1131da177e4SLinus Torvalds }
1141da177e4SLinus Torvalds 
1155f556aabSDavid Woodhouse static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
1165f556aabSDavid Woodhouse 					 uint32_t generation)
1175f556aabSDavid Woodhouse {
1185f556aabSDavid Woodhouse 	/* We don't care about i_generation. We'll destroy the flash
1195f556aabSDavid Woodhouse 	   before we start re-using inode numbers anyway. And even
1205f556aabSDavid Woodhouse 	   if that wasn't true, we'd have other problems...*/
1215f556aabSDavid Woodhouse 	return jffs2_iget(sb, ino);
1225f556aabSDavid Woodhouse }
1235f556aabSDavid Woodhouse 
1245f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
1255f556aabSDavid Woodhouse 					 int fh_len, int fh_type)
1265f556aabSDavid Woodhouse {
1275f556aabSDavid Woodhouse         return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
1285f556aabSDavid Woodhouse                                     jffs2_nfs_get_inode);
1295f556aabSDavid Woodhouse }
1305f556aabSDavid Woodhouse 
1315f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid,
1325f556aabSDavid Woodhouse 					 int fh_len, int fh_type)
1335f556aabSDavid Woodhouse {
1345f556aabSDavid Woodhouse         return generic_fh_to_parent(sb, fid, fh_len, fh_type,
1355f556aabSDavid Woodhouse                                     jffs2_nfs_get_inode);
1365f556aabSDavid Woodhouse }
1375f556aabSDavid Woodhouse 
1385f556aabSDavid Woodhouse static struct dentry *jffs2_get_parent(struct dentry *child)
1395f556aabSDavid Woodhouse {
1405f556aabSDavid Woodhouse 	struct jffs2_inode_info *f;
1415f556aabSDavid Woodhouse 	uint32_t pino;
1425f556aabSDavid Woodhouse 
1435f556aabSDavid Woodhouse 	BUG_ON(!S_ISDIR(child->d_inode->i_mode));
1445f556aabSDavid Woodhouse 
1455f556aabSDavid Woodhouse 	f = JFFS2_INODE_INFO(child->d_inode);
1465f556aabSDavid Woodhouse 
1475f556aabSDavid Woodhouse 	pino = f->inocache->pino_nlink;
1485f556aabSDavid Woodhouse 
1495f556aabSDavid Woodhouse 	JFFS2_DEBUG("Parent of directory ino #%u is #%u\n",
1505f556aabSDavid Woodhouse 		    f->inocache->ino, pino);
1515f556aabSDavid Woodhouse 
1525f556aabSDavid Woodhouse 	return d_obtain_alias(jffs2_iget(child->d_inode->i_sb, pino));
1535f556aabSDavid Woodhouse }
1545f556aabSDavid Woodhouse 
155ac4cfdd6SAlexey Dobriyan static const struct export_operations jffs2_export_ops = {
1565f556aabSDavid Woodhouse 	.get_parent = jffs2_get_parent,
1575f556aabSDavid Woodhouse 	.fh_to_dentry = jffs2_fh_to_dentry,
1585f556aabSDavid Woodhouse 	.fh_to_parent = jffs2_fh_to_parent,
1595f556aabSDavid Woodhouse };
1605f556aabSDavid Woodhouse 
16192abc475SAndres Salomon /*
16292abc475SAndres Salomon  * JFFS2 mount options.
16392abc475SAndres Salomon  *
16492abc475SAndres Salomon  * Opt_override_compr: override default compressor
16592abc475SAndres Salomon  * Opt_err: just end of array marker
16692abc475SAndres Salomon  */
16792abc475SAndres Salomon enum {
16892abc475SAndres Salomon 	Opt_override_compr,
16992abc475SAndres Salomon 	Opt_err,
17092abc475SAndres Salomon };
17192abc475SAndres Salomon 
17292abc475SAndres Salomon static const match_table_t tokens = {
17392abc475SAndres Salomon 	{Opt_override_compr, "compr=%s"},
17492abc475SAndres Salomon 	{Opt_err, NULL},
17592abc475SAndres Salomon };
17692abc475SAndres Salomon 
17792abc475SAndres Salomon static int jffs2_parse_options(struct jffs2_sb_info *c, char *data)
17892abc475SAndres Salomon {
17992abc475SAndres Salomon 	substring_t args[MAX_OPT_ARGS];
18092abc475SAndres Salomon 	char *p, *name;
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;
19892abc475SAndres Salomon 			if (!strcmp(name, "none")) {
19992abc475SAndres Salomon 				c->mount_opts.compr = JFFS2_COMPR_MODE_NONE;
20092abc475SAndres Salomon 				c->mount_opts.override_compr = true;
20192abc475SAndres Salomon 			}
20292abc475SAndres Salomon 			kfree(name);
20392abc475SAndres Salomon 			break;
20492abc475SAndres Salomon 		default:
20592abc475SAndres Salomon 			printk(KERN_ERR "JFFS2 Error: unrecognized mount option '%s' or missing value\n",
20692abc475SAndres Salomon 					p);
20792abc475SAndres Salomon 			return -EINVAL;
20892abc475SAndres Salomon 		}
20992abc475SAndres Salomon 	}
21092abc475SAndres Salomon 
21192abc475SAndres Salomon 	return 0;
21292abc475SAndres Salomon }
21392abc475SAndres Salomon 
21492abc475SAndres Salomon static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data)
21592abc475SAndres Salomon {
21692abc475SAndres Salomon 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
21792abc475SAndres Salomon 	int err;
21892abc475SAndres Salomon 
21992abc475SAndres Salomon 	err = jffs2_parse_options(c, data);
22092abc475SAndres Salomon 	if (err)
22192abc475SAndres Salomon 		return -EINVAL;
22292abc475SAndres Salomon 
22392abc475SAndres Salomon 	return jffs2_do_remount_fs(sb, flags, data);
22492abc475SAndres Salomon }
22592abc475SAndres Salomon 
226ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jffs2_super_operations =
2271da177e4SLinus Torvalds {
2281da177e4SLinus Torvalds 	.alloc_inode =	jffs2_alloc_inode,
2291da177e4SLinus Torvalds 	.destroy_inode =jffs2_destroy_inode,
2301da177e4SLinus Torvalds 	.put_super =	jffs2_put_super,
2311da177e4SLinus Torvalds 	.write_super =	jffs2_write_super,
2321da177e4SLinus Torvalds 	.statfs =	jffs2_statfs,
2331da177e4SLinus Torvalds 	.remount_fs =	jffs2_remount_fs,
234b57922d9SAl Viro 	.evict_inode =	jffs2_evict_inode,
2351da177e4SLinus Torvalds 	.dirty_inode =	jffs2_dirty_inode,
23692abc475SAndres Salomon 	.show_options =	jffs2_show_options,
2371da177e4SLinus Torvalds 	.sync_fs =	jffs2_sync_fs,
2381da177e4SLinus Torvalds };
2391da177e4SLinus Torvalds 
240acaebfd8SDavid Howells /*
241acaebfd8SDavid Howells  * fill in the superblock
242acaebfd8SDavid Howells  */
243acaebfd8SDavid Howells static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
2441da177e4SLinus Torvalds {
2451da177e4SLinus Torvalds 	struct jffs2_sb_info *c;
246db719222SJan Blunck 	int ret;
247db719222SJan Blunck 
248acaebfd8SDavid Howells 	D1(printk(KERN_DEBUG "jffs2_get_sb_mtd():"
249acaebfd8SDavid Howells 		  " New superblock for device %d (\"%s\")\n",
250acaebfd8SDavid Howells 		  sb->s_mtd->index, sb->s_mtd->name));
2511da177e4SLinus Torvalds 
252f8314dc6SPanagiotis Issaris 	c = kzalloc(sizeof(*c), GFP_KERNEL);
2531a028dd2SArnd Bergmann 	if (!c)
254454e2398SDavid Howells 		return -ENOMEM;
2551da177e4SLinus Torvalds 
256acaebfd8SDavid Howells 	c->mtd = sb->s_mtd;
257acaebfd8SDavid Howells 	c->os_priv = sb;
258acaebfd8SDavid Howells 	sb->s_fs_info = c;
2591da177e4SLinus Torvalds 
26092abc475SAndres Salomon 	ret = jffs2_parse_options(c, data);
26192abc475SAndres Salomon 	if (ret) {
26292abc475SAndres Salomon 		kfree(c);
26392abc475SAndres Salomon 		return -EINVAL;
26492abc475SAndres Salomon 	}
26592abc475SAndres Salomon 
266acaebfd8SDavid Howells 	/* Initialize JFFS2 superblock locks, the further initialization will
267acaebfd8SDavid Howells 	 * be done later */
268ced22070SDavid Woodhouse 	mutex_init(&c->alloc_sem);
269ced22070SDavid Woodhouse 	mutex_init(&c->erase_free_sem);
270b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->erase_wait);
271b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->inocache_wq);
272b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->erase_completion_lock);
273b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->inocache_lock);
274b6220598SArtem B. Bityuckiy 
2751da177e4SLinus Torvalds 	sb->s_op = &jffs2_super_operations;
2765f556aabSDavid Woodhouse 	sb->s_export_op = &jffs2_export_ops;
277acaebfd8SDavid Howells 	sb->s_flags = sb->s_flags | MS_NOATIME;
278aa98d7cfSKaiGai Kohei 	sb->s_xattr = jffs2_xattr_handlers;
279aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL
280aa98d7cfSKaiGai Kohei 	sb->s_flags |= MS_POSIXACL;
281aa98d7cfSKaiGai Kohei #endif
282db719222SJan Blunck 	ret = jffs2_do_fill_super(sb, data, silent);
283db719222SJan Blunck 	return ret;
2841da177e4SLinus Torvalds }
2851da177e4SLinus Torvalds 
286848b83a5SAl Viro static struct dentry *jffs2_mount(struct file_system_type *fs_type,
2871da177e4SLinus Torvalds 			int flags, const char *dev_name,
288848b83a5SAl Viro 			void *data)
2891da177e4SLinus Torvalds {
290848b83a5SAl Viro 	return mount_mtd(fs_type, flags, dev_name, data, jffs2_fill_super);
2911da177e4SLinus Torvalds }
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds static void jffs2_put_super (struct super_block *sb)
2941da177e4SLinus Torvalds {
2951da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds 	D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
2981da177e4SLinus Torvalds 
2998c85e125SChristoph Hellwig 	if (sb->s_dirt)
3008c85e125SChristoph Hellwig 		jffs2_write_super(sb);
3018c85e125SChristoph Hellwig 
302ced22070SDavid Woodhouse 	mutex_lock(&c->alloc_sem);
3031da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
304ced22070SDavid Woodhouse 	mutex_unlock(&c->alloc_sem);
305e631ddbaSFerenc Havasi 
306e631ddbaSFerenc Havasi 	jffs2_sum_exit(c);
307e631ddbaSFerenc Havasi 
3081da177e4SLinus Torvalds 	jffs2_free_ino_caches(c);
3091da177e4SLinus Torvalds 	jffs2_free_raw_node_refs(c);
3104ce1f562SFerenc Havasi 	if (jffs2_blocks_use_vmalloc(c))
3111da177e4SLinus Torvalds 		vfree(c->blocks);
3121da177e4SLinus Torvalds 	else
3131da177e4SLinus Torvalds 		kfree(c->blocks);
3141da177e4SLinus Torvalds 	jffs2_flash_cleanup(c);
3151da177e4SLinus Torvalds 	kfree(c->inocache_list);
316aa98d7cfSKaiGai Kohei 	jffs2_clear_xattr_subsystem(c);
3171da177e4SLinus Torvalds 	if (c->mtd->sync)
3181da177e4SLinus Torvalds 		c->mtd->sync(c->mtd);
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 	D1(printk(KERN_DEBUG "jffs2_put_super returning\n"));
3211da177e4SLinus Torvalds }
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds static void jffs2_kill_sb(struct super_block *sb)
3241da177e4SLinus Torvalds {
3251da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
326a69dde91SArtem B. Bityuckiy 	if (!(sb->s_flags & MS_RDONLY))
327a69dde91SArtem B. Bityuckiy 		jffs2_stop_garbage_collect_thread(c);
328acaebfd8SDavid Howells 	kill_mtd_super(sb);
3291da177e4SLinus Torvalds 	kfree(c);
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds 
3321da177e4SLinus Torvalds static struct file_system_type jffs2_fs_type = {
3331da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
3341da177e4SLinus Torvalds 	.name =		"jffs2",
335848b83a5SAl Viro 	.mount =	jffs2_mount,
3361da177e4SLinus Torvalds 	.kill_sb =	jffs2_kill_sb,
3371da177e4SLinus Torvalds };
3381da177e4SLinus Torvalds 
3391da177e4SLinus Torvalds static int __init init_jffs2_fs(void)
3401da177e4SLinus Torvalds {
3411da177e4SLinus Torvalds 	int ret;
3421da177e4SLinus Torvalds 
3433e68fbb5SDavid Woodhouse 	/* Paranoia checks for on-medium structures. If we ask GCC
3443e68fbb5SDavid Woodhouse 	   to pack them with __attribute__((packed)) then it _also_
3453e68fbb5SDavid Woodhouse 	   assumes that they're not aligned -- so it emits crappy
3463e68fbb5SDavid Woodhouse 	   code on some architectures. Ideally we want an attribute
3473e68fbb5SDavid Woodhouse 	   which means just 'no padding', without the alignment
3483e68fbb5SDavid Woodhouse 	   thing. But GCC doesn't have that -- we have to just
3493e68fbb5SDavid Woodhouse 	   hope the structs are the right sizes, instead. */
3502ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
3512ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
3522ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
3532ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
3543e68fbb5SDavid Woodhouse 
3551da177e4SLinus Torvalds 	printk(KERN_INFO "JFFS2 version 2.2."
3562f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
3571da177e4SLinus Torvalds 	       " (NAND)"
3581da177e4SLinus Torvalds #endif
359e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY
360e631ddbaSFerenc Havasi 	       " (SUMMARY) "
361e631ddbaSFerenc Havasi #endif
362c00c310eSDavid Woodhouse 	       " © 2001-2006 Red Hat, Inc.\n");
3631da177e4SLinus Torvalds 
3641da177e4SLinus Torvalds 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
3651da177e4SLinus Torvalds 					     sizeof(struct jffs2_inode_info),
366fffb60f9SPaul Jackson 					     0, (SLAB_RECLAIM_ACCOUNT|
367fffb60f9SPaul Jackson 						SLAB_MEM_SPREAD),
36820c2df83SPaul Mundt 					     jffs2_i_init_once);
3691da177e4SLinus Torvalds 	if (!jffs2_inode_cachep) {
3701da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
3711da177e4SLinus Torvalds 		return -ENOMEM;
3721da177e4SLinus Torvalds 	}
3731da177e4SLinus Torvalds 	ret = jffs2_compressors_init();
3741da177e4SLinus Torvalds 	if (ret) {
3751da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
3761da177e4SLinus Torvalds 		goto out;
3771da177e4SLinus Torvalds 	}
3781da177e4SLinus Torvalds 	ret = jffs2_create_slab_caches();
3791da177e4SLinus Torvalds 	if (ret) {
3801da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
3811da177e4SLinus Torvalds 		goto out_compressors;
3821da177e4SLinus Torvalds 	}
3831da177e4SLinus Torvalds 	ret = register_filesystem(&jffs2_fs_type);
3841da177e4SLinus Torvalds 	if (ret) {
3851da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n");
3861da177e4SLinus Torvalds 		goto out_slab;
3871da177e4SLinus Torvalds 	}
3881da177e4SLinus Torvalds 	return 0;
3891da177e4SLinus Torvalds 
3901da177e4SLinus Torvalds  out_slab:
3911da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
3921da177e4SLinus Torvalds  out_compressors:
3931da177e4SLinus Torvalds 	jffs2_compressors_exit();
3941da177e4SLinus Torvalds  out:
3951da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
3961da177e4SLinus Torvalds 	return ret;
3971da177e4SLinus Torvalds }
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void)
4001da177e4SLinus Torvalds {
4011da177e4SLinus Torvalds 	unregister_filesystem(&jffs2_fs_type);
4021da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
4031da177e4SLinus Torvalds 	jffs2_compressors_exit();
4041da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
4051da177e4SLinus Torvalds }
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds module_init(init_jffs2_fs);
4081da177e4SLinus Torvalds module_exit(exit_jffs2_fs);
4091da177e4SLinus Torvalds 
4101da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journalling Flash File System, v2");
4111da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc.");
4121da177e4SLinus Torvalds MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
4131da177e4SLinus Torvalds 		       // the sake of this tag. It's Free Software.
414