xref: /openbmc/linux/fs/jffs2/super.c (revision 9c261b33)
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 	kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode));
49fa0d7e3dSNick Piggin }
50fa0d7e3dSNick Piggin 
511da177e4SLinus Torvalds static void jffs2_destroy_inode(struct inode *inode)
521da177e4SLinus Torvalds {
53fa0d7e3dSNick Piggin 	call_rcu(&inode->i_rcu, jffs2_i_callback);
541da177e4SLinus Torvalds }
551da177e4SLinus Torvalds 
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 
6401ba6875SChristoph Hellwig static void jffs2_write_super(struct super_block *sb)
6501ba6875SChristoph Hellwig {
6601ba6875SChristoph Hellwig 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
67ebc1ac16SChristoph Hellwig 
68ebc1ac16SChristoph Hellwig 	lock_super(sb);
6901ba6875SChristoph Hellwig 	sb->s_dirt = 0;
7001ba6875SChristoph Hellwig 
71ebc1ac16SChristoph Hellwig 	if (!(sb->s_flags & MS_RDONLY)) {
729c261b33SJoe Perches 		jffs2_dbg(1, "%s()\n", __func__);
7301ba6875SChristoph Hellwig 		jffs2_flush_wbuf_gc(c, 0);
7401ba6875SChristoph Hellwig 	}
7501ba6875SChristoph Hellwig 
76ebc1ac16SChristoph Hellwig 	unlock_super(sb);
77ebc1ac16SChristoph Hellwig }
78ebc1ac16SChristoph Hellwig 
7992abc475SAndres Salomon static const char *jffs2_compr_name(unsigned int compr)
8092abc475SAndres Salomon {
8192abc475SAndres Salomon 	switch (compr) {
8292abc475SAndres Salomon 	case JFFS2_COMPR_MODE_NONE:
8392abc475SAndres Salomon 		return "none";
84123005f3SAndres Salomon #ifdef CONFIG_JFFS2_LZO
85123005f3SAndres Salomon 	case JFFS2_COMPR_MODE_FORCELZO:
86123005f3SAndres Salomon 		return "lzo";
87123005f3SAndres Salomon #endif
88123005f3SAndres Salomon #ifdef CONFIG_JFFS2_ZLIB
89123005f3SAndres Salomon 	case JFFS2_COMPR_MODE_FORCEZLIB:
90123005f3SAndres Salomon 		return "zlib";
91123005f3SAndres Salomon #endif
9292abc475SAndres Salomon 	default:
9392abc475SAndres Salomon 		/* should never happen; programmer error */
9492abc475SAndres Salomon 		WARN_ON(1);
9592abc475SAndres Salomon 		return "";
9692abc475SAndres Salomon 	}
9792abc475SAndres Salomon }
9892abc475SAndres Salomon 
9934c80b1dSAl Viro static int jffs2_show_options(struct seq_file *s, struct dentry *root)
10092abc475SAndres Salomon {
10134c80b1dSAl Viro 	struct jffs2_sb_info *c = JFFS2_SB_INFO(root->d_sb);
10292abc475SAndres Salomon 	struct jffs2_mount_opts *opts = &c->mount_opts;
10392abc475SAndres Salomon 
10492abc475SAndres Salomon 	if (opts->override_compr)
10592abc475SAndres Salomon 		seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr));
10692abc475SAndres Salomon 
10792abc475SAndres Salomon 	return 0;
10892abc475SAndres Salomon }
10992abc475SAndres Salomon 
1101da177e4SLinus Torvalds static int jffs2_sync_fs(struct super_block *sb, int wait)
1111da177e4SLinus Torvalds {
1121da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
1131da177e4SLinus Torvalds 
114d579ed00SChristoph Hellwig 	jffs2_write_super(sb);
115d579ed00SChristoph Hellwig 
116ced22070SDavid Woodhouse 	mutex_lock(&c->alloc_sem);
1171da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
118ced22070SDavid Woodhouse 	mutex_unlock(&c->alloc_sem);
1191da177e4SLinus Torvalds 	return 0;
1201da177e4SLinus Torvalds }
1211da177e4SLinus Torvalds 
1225f556aabSDavid Woodhouse static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
1235f556aabSDavid Woodhouse 					 uint32_t generation)
1245f556aabSDavid Woodhouse {
1255f556aabSDavid Woodhouse 	/* We don't care about i_generation. We'll destroy the flash
1265f556aabSDavid Woodhouse 	   before we start re-using inode numbers anyway. And even
1275f556aabSDavid Woodhouse 	   if that wasn't true, we'd have other problems...*/
1285f556aabSDavid Woodhouse 	return jffs2_iget(sb, ino);
1295f556aabSDavid Woodhouse }
1305f556aabSDavid Woodhouse 
1315f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
1325f556aabSDavid Woodhouse 					 int fh_len, int fh_type)
1335f556aabSDavid Woodhouse {
1345f556aabSDavid Woodhouse         return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
1355f556aabSDavid Woodhouse                                     jffs2_nfs_get_inode);
1365f556aabSDavid Woodhouse }
1375f556aabSDavid Woodhouse 
1385f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid,
1395f556aabSDavid Woodhouse 					 int fh_len, int fh_type)
1405f556aabSDavid Woodhouse {
1415f556aabSDavid Woodhouse         return generic_fh_to_parent(sb, fid, fh_len, fh_type,
1425f556aabSDavid Woodhouse                                     jffs2_nfs_get_inode);
1435f556aabSDavid Woodhouse }
1445f556aabSDavid Woodhouse 
1455f556aabSDavid Woodhouse static struct dentry *jffs2_get_parent(struct dentry *child)
1465f556aabSDavid Woodhouse {
1475f556aabSDavid Woodhouse 	struct jffs2_inode_info *f;
1485f556aabSDavid Woodhouse 	uint32_t pino;
1495f556aabSDavid Woodhouse 
1505f556aabSDavid Woodhouse 	BUG_ON(!S_ISDIR(child->d_inode->i_mode));
1515f556aabSDavid Woodhouse 
1525f556aabSDavid Woodhouse 	f = JFFS2_INODE_INFO(child->d_inode);
1535f556aabSDavid Woodhouse 
1545f556aabSDavid Woodhouse 	pino = f->inocache->pino_nlink;
1555f556aabSDavid Woodhouse 
1565f556aabSDavid Woodhouse 	JFFS2_DEBUG("Parent of directory ino #%u is #%u\n",
1575f556aabSDavid Woodhouse 		    f->inocache->ino, pino);
1585f556aabSDavid Woodhouse 
1595f556aabSDavid Woodhouse 	return d_obtain_alias(jffs2_iget(child->d_inode->i_sb, pino));
1605f556aabSDavid Woodhouse }
1615f556aabSDavid Woodhouse 
162ac4cfdd6SAlexey Dobriyan static const struct export_operations jffs2_export_ops = {
1635f556aabSDavid Woodhouse 	.get_parent = jffs2_get_parent,
1645f556aabSDavid Woodhouse 	.fh_to_dentry = jffs2_fh_to_dentry,
1655f556aabSDavid Woodhouse 	.fh_to_parent = jffs2_fh_to_parent,
1665f556aabSDavid Woodhouse };
1675f556aabSDavid Woodhouse 
16892abc475SAndres Salomon /*
16992abc475SAndres Salomon  * JFFS2 mount options.
17092abc475SAndres Salomon  *
17192abc475SAndres Salomon  * Opt_override_compr: override default compressor
17292abc475SAndres Salomon  * Opt_err: just end of array marker
17392abc475SAndres Salomon  */
17492abc475SAndres Salomon enum {
17592abc475SAndres Salomon 	Opt_override_compr,
17692abc475SAndres Salomon 	Opt_err,
17792abc475SAndres Salomon };
17892abc475SAndres Salomon 
17992abc475SAndres Salomon static const match_table_t tokens = {
18092abc475SAndres Salomon 	{Opt_override_compr, "compr=%s"},
18192abc475SAndres Salomon 	{Opt_err, NULL},
18292abc475SAndres Salomon };
18392abc475SAndres Salomon 
18492abc475SAndres Salomon static int jffs2_parse_options(struct jffs2_sb_info *c, char *data)
18592abc475SAndres Salomon {
18692abc475SAndres Salomon 	substring_t args[MAX_OPT_ARGS];
18792abc475SAndres Salomon 	char *p, *name;
18892abc475SAndres Salomon 
18992abc475SAndres Salomon 	if (!data)
19092abc475SAndres Salomon 		return 0;
19192abc475SAndres Salomon 
19292abc475SAndres Salomon 	while ((p = strsep(&data, ","))) {
19392abc475SAndres Salomon 		int token;
19492abc475SAndres Salomon 
19592abc475SAndres Salomon 		if (!*p)
19692abc475SAndres Salomon 			continue;
19792abc475SAndres Salomon 
19892abc475SAndres Salomon 		token = match_token(p, tokens, args);
19992abc475SAndres Salomon 		switch (token) {
20092abc475SAndres Salomon 		case Opt_override_compr:
20192abc475SAndres Salomon 			name = match_strdup(&args[0]);
20292abc475SAndres Salomon 
20392abc475SAndres Salomon 			if (!name)
20492abc475SAndres Salomon 				return -ENOMEM;
205123005f3SAndres Salomon 			if (!strcmp(name, "none"))
20692abc475SAndres Salomon 				c->mount_opts.compr = JFFS2_COMPR_MODE_NONE;
207123005f3SAndres Salomon #ifdef CONFIG_JFFS2_LZO
208123005f3SAndres Salomon 			else if (!strcmp(name, "lzo"))
209123005f3SAndres Salomon 				c->mount_opts.compr = JFFS2_COMPR_MODE_FORCELZO;
210123005f3SAndres Salomon #endif
211123005f3SAndres Salomon #ifdef CONFIG_JFFS2_ZLIB
212123005f3SAndres Salomon 			else if (!strcmp(name, "zlib"))
213123005f3SAndres Salomon 				c->mount_opts.compr =
214123005f3SAndres Salomon 						JFFS2_COMPR_MODE_FORCEZLIB;
215123005f3SAndres Salomon #endif
216123005f3SAndres Salomon 			else {
217123005f3SAndres Salomon 				printk(KERN_ERR "JFFS2 Error: unknown compressor \"%s\"",
218123005f3SAndres Salomon 						name);
219123005f3SAndres Salomon 				kfree(name);
220123005f3SAndres Salomon 				return -EINVAL;
22192abc475SAndres Salomon 			}
22292abc475SAndres Salomon 			kfree(name);
223123005f3SAndres Salomon 			c->mount_opts.override_compr = true;
22492abc475SAndres Salomon 			break;
22592abc475SAndres Salomon 		default:
22692abc475SAndres Salomon 			printk(KERN_ERR "JFFS2 Error: unrecognized mount option '%s' or missing value\n",
22792abc475SAndres Salomon 					p);
22892abc475SAndres Salomon 			return -EINVAL;
22992abc475SAndres Salomon 		}
23092abc475SAndres Salomon 	}
23192abc475SAndres Salomon 
23292abc475SAndres Salomon 	return 0;
23392abc475SAndres Salomon }
23492abc475SAndres Salomon 
23592abc475SAndres Salomon static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data)
23692abc475SAndres Salomon {
23792abc475SAndres Salomon 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
23892abc475SAndres Salomon 	int err;
23992abc475SAndres Salomon 
24092abc475SAndres Salomon 	err = jffs2_parse_options(c, data);
24192abc475SAndres Salomon 	if (err)
24292abc475SAndres Salomon 		return -EINVAL;
24392abc475SAndres Salomon 
24492abc475SAndres Salomon 	return jffs2_do_remount_fs(sb, flags, data);
24592abc475SAndres Salomon }
24692abc475SAndres Salomon 
247ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jffs2_super_operations =
2481da177e4SLinus Torvalds {
2491da177e4SLinus Torvalds 	.alloc_inode =	jffs2_alloc_inode,
2501da177e4SLinus Torvalds 	.destroy_inode =jffs2_destroy_inode,
2511da177e4SLinus Torvalds 	.put_super =	jffs2_put_super,
2521da177e4SLinus Torvalds 	.write_super =	jffs2_write_super,
2531da177e4SLinus Torvalds 	.statfs =	jffs2_statfs,
2541da177e4SLinus Torvalds 	.remount_fs =	jffs2_remount_fs,
255b57922d9SAl Viro 	.evict_inode =	jffs2_evict_inode,
2561da177e4SLinus Torvalds 	.dirty_inode =	jffs2_dirty_inode,
25792abc475SAndres Salomon 	.show_options =	jffs2_show_options,
2581da177e4SLinus Torvalds 	.sync_fs =	jffs2_sync_fs,
2591da177e4SLinus Torvalds };
2601da177e4SLinus Torvalds 
261acaebfd8SDavid Howells /*
262acaebfd8SDavid Howells  * fill in the superblock
263acaebfd8SDavid Howells  */
264acaebfd8SDavid Howells static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
2651da177e4SLinus Torvalds {
2661da177e4SLinus Torvalds 	struct jffs2_sb_info *c;
267db719222SJan Blunck 	int ret;
268db719222SJan Blunck 
2699c261b33SJoe Perches 	jffs2_dbg(1, "jffs2_get_sb_mtd():"
270acaebfd8SDavid Howells 		  " New superblock for device %d (\"%s\")\n",
2719c261b33SJoe Perches 		  sb->s_mtd->index, sb->s_mtd->name);
2721da177e4SLinus Torvalds 
273f8314dc6SPanagiotis Issaris 	c = kzalloc(sizeof(*c), GFP_KERNEL);
2741a028dd2SArnd Bergmann 	if (!c)
275454e2398SDavid Howells 		return -ENOMEM;
2761da177e4SLinus Torvalds 
277acaebfd8SDavid Howells 	c->mtd = sb->s_mtd;
278acaebfd8SDavid Howells 	c->os_priv = sb;
279acaebfd8SDavid Howells 	sb->s_fs_info = c;
2801da177e4SLinus Torvalds 
28192abc475SAndres Salomon 	ret = jffs2_parse_options(c, data);
28292abc475SAndres Salomon 	if (ret) {
28392abc475SAndres Salomon 		kfree(c);
28492abc475SAndres Salomon 		return -EINVAL;
28592abc475SAndres Salomon 	}
28692abc475SAndres Salomon 
287acaebfd8SDavid Howells 	/* Initialize JFFS2 superblock locks, the further initialization will
288acaebfd8SDavid Howells 	 * be done later */
289ced22070SDavid Woodhouse 	mutex_init(&c->alloc_sem);
290ced22070SDavid Woodhouse 	mutex_init(&c->erase_free_sem);
291b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->erase_wait);
292b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->inocache_wq);
293b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->erase_completion_lock);
294b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->inocache_lock);
295b6220598SArtem B. Bityuckiy 
2961da177e4SLinus Torvalds 	sb->s_op = &jffs2_super_operations;
2975f556aabSDavid Woodhouse 	sb->s_export_op = &jffs2_export_ops;
298acaebfd8SDavid Howells 	sb->s_flags = sb->s_flags | MS_NOATIME;
299aa98d7cfSKaiGai Kohei 	sb->s_xattr = jffs2_xattr_handlers;
300aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL
301aa98d7cfSKaiGai Kohei 	sb->s_flags |= MS_POSIXACL;
302aa98d7cfSKaiGai Kohei #endif
303db719222SJan Blunck 	ret = jffs2_do_fill_super(sb, data, silent);
304db719222SJan Blunck 	return ret;
3051da177e4SLinus Torvalds }
3061da177e4SLinus Torvalds 
307848b83a5SAl Viro static struct dentry *jffs2_mount(struct file_system_type *fs_type,
3081da177e4SLinus Torvalds 			int flags, const char *dev_name,
309848b83a5SAl Viro 			void *data)
3101da177e4SLinus Torvalds {
311848b83a5SAl Viro 	return mount_mtd(fs_type, flags, dev_name, data, jffs2_fill_super);
3121da177e4SLinus Torvalds }
3131da177e4SLinus Torvalds 
3141da177e4SLinus Torvalds static void jffs2_put_super (struct super_block *sb)
3151da177e4SLinus Torvalds {
3161da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
3171da177e4SLinus Torvalds 
3189c261b33SJoe Perches 	jffs2_dbg(2, "%s()\n", __func__);
3191da177e4SLinus Torvalds 
3208c85e125SChristoph Hellwig 	if (sb->s_dirt)
3218c85e125SChristoph Hellwig 		jffs2_write_super(sb);
3228c85e125SChristoph Hellwig 
323ced22070SDavid Woodhouse 	mutex_lock(&c->alloc_sem);
3241da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
325ced22070SDavid Woodhouse 	mutex_unlock(&c->alloc_sem);
326e631ddbaSFerenc Havasi 
327e631ddbaSFerenc Havasi 	jffs2_sum_exit(c);
328e631ddbaSFerenc Havasi 
3291da177e4SLinus Torvalds 	jffs2_free_ino_caches(c);
3301da177e4SLinus Torvalds 	jffs2_free_raw_node_refs(c);
3314ce1f562SFerenc Havasi 	if (jffs2_blocks_use_vmalloc(c))
3321da177e4SLinus Torvalds 		vfree(c->blocks);
3331da177e4SLinus Torvalds 	else
3341da177e4SLinus Torvalds 		kfree(c->blocks);
3351da177e4SLinus Torvalds 	jffs2_flash_cleanup(c);
3361da177e4SLinus Torvalds 	kfree(c->inocache_list);
337aa98d7cfSKaiGai Kohei 	jffs2_clear_xattr_subsystem(c);
33885f2f2a8SArtem Bityutskiy 	mtd_sync(c->mtd);
3399c261b33SJoe Perches 	jffs2_dbg(1, "%s(): returning\n", __func__);
3401da177e4SLinus Torvalds }
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds static void jffs2_kill_sb(struct super_block *sb)
3431da177e4SLinus Torvalds {
3441da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
345a69dde91SArtem B. Bityuckiy 	if (!(sb->s_flags & MS_RDONLY))
346a69dde91SArtem B. Bityuckiy 		jffs2_stop_garbage_collect_thread(c);
347acaebfd8SDavid Howells 	kill_mtd_super(sb);
3481da177e4SLinus Torvalds 	kfree(c);
3491da177e4SLinus Torvalds }
3501da177e4SLinus Torvalds 
3511da177e4SLinus Torvalds static struct file_system_type jffs2_fs_type = {
3521da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
3531da177e4SLinus Torvalds 	.name =		"jffs2",
354848b83a5SAl Viro 	.mount =	jffs2_mount,
3551da177e4SLinus Torvalds 	.kill_sb =	jffs2_kill_sb,
3561da177e4SLinus Torvalds };
3571da177e4SLinus Torvalds 
3581da177e4SLinus Torvalds static int __init init_jffs2_fs(void)
3591da177e4SLinus Torvalds {
3601da177e4SLinus Torvalds 	int ret;
3611da177e4SLinus Torvalds 
3623e68fbb5SDavid Woodhouse 	/* Paranoia checks for on-medium structures. If we ask GCC
3633e68fbb5SDavid Woodhouse 	   to pack them with __attribute__((packed)) then it _also_
3643e68fbb5SDavid Woodhouse 	   assumes that they're not aligned -- so it emits crappy
3653e68fbb5SDavid Woodhouse 	   code on some architectures. Ideally we want an attribute
3663e68fbb5SDavid Woodhouse 	   which means just 'no padding', without the alignment
3673e68fbb5SDavid Woodhouse 	   thing. But GCC doesn't have that -- we have to just
3683e68fbb5SDavid Woodhouse 	   hope the structs are the right sizes, instead. */
3692ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
3702ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
3712ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
3722ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
3733e68fbb5SDavid Woodhouse 
3741da177e4SLinus Torvalds 	printk(KERN_INFO "JFFS2 version 2.2."
3752f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
3761da177e4SLinus Torvalds 	       " (NAND)"
3771da177e4SLinus Torvalds #endif
378e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY
379e631ddbaSFerenc Havasi 	       " (SUMMARY) "
380e631ddbaSFerenc Havasi #endif
381c00c310eSDavid Woodhouse 	       " © 2001-2006 Red Hat, Inc.\n");
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
3841da177e4SLinus Torvalds 					     sizeof(struct jffs2_inode_info),
385fffb60f9SPaul Jackson 					     0, (SLAB_RECLAIM_ACCOUNT|
386fffb60f9SPaul Jackson 						SLAB_MEM_SPREAD),
38720c2df83SPaul Mundt 					     jffs2_i_init_once);
3881da177e4SLinus Torvalds 	if (!jffs2_inode_cachep) {
3891da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
3901da177e4SLinus Torvalds 		return -ENOMEM;
3911da177e4SLinus Torvalds 	}
3921da177e4SLinus Torvalds 	ret = jffs2_compressors_init();
3931da177e4SLinus Torvalds 	if (ret) {
3941da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
3951da177e4SLinus Torvalds 		goto out;
3961da177e4SLinus Torvalds 	}
3971da177e4SLinus Torvalds 	ret = jffs2_create_slab_caches();
3981da177e4SLinus Torvalds 	if (ret) {
3991da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
4001da177e4SLinus Torvalds 		goto out_compressors;
4011da177e4SLinus Torvalds 	}
4021da177e4SLinus Torvalds 	ret = register_filesystem(&jffs2_fs_type);
4031da177e4SLinus Torvalds 	if (ret) {
4041da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n");
4051da177e4SLinus Torvalds 		goto out_slab;
4061da177e4SLinus Torvalds 	}
4071da177e4SLinus Torvalds 	return 0;
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds  out_slab:
4101da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
4111da177e4SLinus Torvalds  out_compressors:
4121da177e4SLinus Torvalds 	jffs2_compressors_exit();
4131da177e4SLinus Torvalds  out:
4141da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
4151da177e4SLinus Torvalds 	return ret;
4161da177e4SLinus Torvalds }
4171da177e4SLinus Torvalds 
4181da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void)
4191da177e4SLinus Torvalds {
4201da177e4SLinus Torvalds 	unregister_filesystem(&jffs2_fs_type);
4211da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
4221da177e4SLinus Torvalds 	jffs2_compressors_exit();
4231da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
4241da177e4SLinus Torvalds }
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds module_init(init_jffs2_fs);
4271da177e4SLinus Torvalds module_exit(exit_jffs2_fs);
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journalling Flash File System, v2");
4301da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc.");
4311da177e4SLinus Torvalds MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
4321da177e4SLinus Torvalds 		       // the sake of this tag. It's Free Software.
433