xref: /openbmc/linux/fs/jffs2/super.c (revision 123005f3)
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";
85123005f3SAndres Salomon #ifdef CONFIG_JFFS2_LZO
86123005f3SAndres Salomon 	case JFFS2_COMPR_MODE_FORCELZO:
87123005f3SAndres Salomon 		return "lzo";
88123005f3SAndres Salomon #endif
89123005f3SAndres Salomon #ifdef CONFIG_JFFS2_ZLIB
90123005f3SAndres Salomon 	case JFFS2_COMPR_MODE_FORCEZLIB:
91123005f3SAndres Salomon 		return "zlib";
92123005f3SAndres Salomon #endif
9392abc475SAndres Salomon 	default:
9492abc475SAndres Salomon 		/* should never happen; programmer error */
9592abc475SAndres Salomon 		WARN_ON(1);
9692abc475SAndres Salomon 		return "";
9792abc475SAndres Salomon 	}
9892abc475SAndres Salomon }
9992abc475SAndres Salomon 
10092abc475SAndres Salomon static int jffs2_show_options(struct seq_file *s, struct vfsmount *mnt)
10192abc475SAndres Salomon {
10292abc475SAndres Salomon 	struct jffs2_sb_info *c = JFFS2_SB_INFO(mnt->mnt_sb);
10392abc475SAndres Salomon 	struct jffs2_mount_opts *opts = &c->mount_opts;
10492abc475SAndres Salomon 
10592abc475SAndres Salomon 	if (opts->override_compr)
10692abc475SAndres Salomon 		seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr));
10792abc475SAndres Salomon 
10892abc475SAndres Salomon 	return 0;
10992abc475SAndres Salomon }
11092abc475SAndres Salomon 
1111da177e4SLinus Torvalds static int jffs2_sync_fs(struct super_block *sb, int wait)
1121da177e4SLinus Torvalds {
1131da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
1141da177e4SLinus Torvalds 
115d579ed00SChristoph Hellwig 	jffs2_write_super(sb);
116d579ed00SChristoph Hellwig 
117ced22070SDavid Woodhouse 	mutex_lock(&c->alloc_sem);
1181da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
119ced22070SDavid Woodhouse 	mutex_unlock(&c->alloc_sem);
1201da177e4SLinus Torvalds 	return 0;
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds 
1235f556aabSDavid Woodhouse static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
1245f556aabSDavid Woodhouse 					 uint32_t generation)
1255f556aabSDavid Woodhouse {
1265f556aabSDavid Woodhouse 	/* We don't care about i_generation. We'll destroy the flash
1275f556aabSDavid Woodhouse 	   before we start re-using inode numbers anyway. And even
1285f556aabSDavid Woodhouse 	   if that wasn't true, we'd have other problems...*/
1295f556aabSDavid Woodhouse 	return jffs2_iget(sb, ino);
1305f556aabSDavid Woodhouse }
1315f556aabSDavid Woodhouse 
1325f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
1335f556aabSDavid Woodhouse 					 int fh_len, int fh_type)
1345f556aabSDavid Woodhouse {
1355f556aabSDavid Woodhouse         return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
1365f556aabSDavid Woodhouse                                     jffs2_nfs_get_inode);
1375f556aabSDavid Woodhouse }
1385f556aabSDavid Woodhouse 
1395f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid,
1405f556aabSDavid Woodhouse 					 int fh_len, int fh_type)
1415f556aabSDavid Woodhouse {
1425f556aabSDavid Woodhouse         return generic_fh_to_parent(sb, fid, fh_len, fh_type,
1435f556aabSDavid Woodhouse                                     jffs2_nfs_get_inode);
1445f556aabSDavid Woodhouse }
1455f556aabSDavid Woodhouse 
1465f556aabSDavid Woodhouse static struct dentry *jffs2_get_parent(struct dentry *child)
1475f556aabSDavid Woodhouse {
1485f556aabSDavid Woodhouse 	struct jffs2_inode_info *f;
1495f556aabSDavid Woodhouse 	uint32_t pino;
1505f556aabSDavid Woodhouse 
1515f556aabSDavid Woodhouse 	BUG_ON(!S_ISDIR(child->d_inode->i_mode));
1525f556aabSDavid Woodhouse 
1535f556aabSDavid Woodhouse 	f = JFFS2_INODE_INFO(child->d_inode);
1545f556aabSDavid Woodhouse 
1555f556aabSDavid Woodhouse 	pino = f->inocache->pino_nlink;
1565f556aabSDavid Woodhouse 
1575f556aabSDavid Woodhouse 	JFFS2_DEBUG("Parent of directory ino #%u is #%u\n",
1585f556aabSDavid Woodhouse 		    f->inocache->ino, pino);
1595f556aabSDavid Woodhouse 
1605f556aabSDavid Woodhouse 	return d_obtain_alias(jffs2_iget(child->d_inode->i_sb, pino));
1615f556aabSDavid Woodhouse }
1625f556aabSDavid Woodhouse 
163ac4cfdd6SAlexey Dobriyan static const struct export_operations jffs2_export_ops = {
1645f556aabSDavid Woodhouse 	.get_parent = jffs2_get_parent,
1655f556aabSDavid Woodhouse 	.fh_to_dentry = jffs2_fh_to_dentry,
1665f556aabSDavid Woodhouse 	.fh_to_parent = jffs2_fh_to_parent,
1675f556aabSDavid Woodhouse };
1685f556aabSDavid Woodhouse 
16992abc475SAndres Salomon /*
17092abc475SAndres Salomon  * JFFS2 mount options.
17192abc475SAndres Salomon  *
17292abc475SAndres Salomon  * Opt_override_compr: override default compressor
17392abc475SAndres Salomon  * Opt_err: just end of array marker
17492abc475SAndres Salomon  */
17592abc475SAndres Salomon enum {
17692abc475SAndres Salomon 	Opt_override_compr,
17792abc475SAndres Salomon 	Opt_err,
17892abc475SAndres Salomon };
17992abc475SAndres Salomon 
18092abc475SAndres Salomon static const match_table_t tokens = {
18192abc475SAndres Salomon 	{Opt_override_compr, "compr=%s"},
18292abc475SAndres Salomon 	{Opt_err, NULL},
18392abc475SAndres Salomon };
18492abc475SAndres Salomon 
18592abc475SAndres Salomon static int jffs2_parse_options(struct jffs2_sb_info *c, char *data)
18692abc475SAndres Salomon {
18792abc475SAndres Salomon 	substring_t args[MAX_OPT_ARGS];
18892abc475SAndres Salomon 	char *p, *name;
18992abc475SAndres Salomon 
19092abc475SAndres Salomon 	if (!data)
19192abc475SAndres Salomon 		return 0;
19292abc475SAndres Salomon 
19392abc475SAndres Salomon 	while ((p = strsep(&data, ","))) {
19492abc475SAndres Salomon 		int token;
19592abc475SAndres Salomon 
19692abc475SAndres Salomon 		if (!*p)
19792abc475SAndres Salomon 			continue;
19892abc475SAndres Salomon 
19992abc475SAndres Salomon 		token = match_token(p, tokens, args);
20092abc475SAndres Salomon 		switch (token) {
20192abc475SAndres Salomon 		case Opt_override_compr:
20292abc475SAndres Salomon 			name = match_strdup(&args[0]);
20392abc475SAndres Salomon 
20492abc475SAndres Salomon 			if (!name)
20592abc475SAndres Salomon 				return -ENOMEM;
206123005f3SAndres Salomon 			if (!strcmp(name, "none"))
20792abc475SAndres Salomon 				c->mount_opts.compr = JFFS2_COMPR_MODE_NONE;
208123005f3SAndres Salomon #ifdef CONFIG_JFFS2_LZO
209123005f3SAndres Salomon 			else if (!strcmp(name, "lzo"))
210123005f3SAndres Salomon 				c->mount_opts.compr = JFFS2_COMPR_MODE_FORCELZO;
211123005f3SAndres Salomon #endif
212123005f3SAndres Salomon #ifdef CONFIG_JFFS2_ZLIB
213123005f3SAndres Salomon 			else if (!strcmp(name, "zlib"))
214123005f3SAndres Salomon 				c->mount_opts.compr =
215123005f3SAndres Salomon 						JFFS2_COMPR_MODE_FORCEZLIB;
216123005f3SAndres Salomon #endif
217123005f3SAndres Salomon 			else {
218123005f3SAndres Salomon 				printk(KERN_ERR "JFFS2 Error: unknown compressor \"%s\"",
219123005f3SAndres Salomon 						name);
220123005f3SAndres Salomon 				kfree(name);
221123005f3SAndres Salomon 				return -EINVAL;
22292abc475SAndres Salomon 			}
22392abc475SAndres Salomon 			kfree(name);
224123005f3SAndres Salomon 			c->mount_opts.override_compr = true;
22592abc475SAndres Salomon 			break;
22692abc475SAndres Salomon 		default:
22792abc475SAndres Salomon 			printk(KERN_ERR "JFFS2 Error: unrecognized mount option '%s' or missing value\n",
22892abc475SAndres Salomon 					p);
22992abc475SAndres Salomon 			return -EINVAL;
23092abc475SAndres Salomon 		}
23192abc475SAndres Salomon 	}
23292abc475SAndres Salomon 
23392abc475SAndres Salomon 	return 0;
23492abc475SAndres Salomon }
23592abc475SAndres Salomon 
23692abc475SAndres Salomon static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data)
23792abc475SAndres Salomon {
23892abc475SAndres Salomon 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
23992abc475SAndres Salomon 	int err;
24092abc475SAndres Salomon 
24192abc475SAndres Salomon 	err = jffs2_parse_options(c, data);
24292abc475SAndres Salomon 	if (err)
24392abc475SAndres Salomon 		return -EINVAL;
24492abc475SAndres Salomon 
24592abc475SAndres Salomon 	return jffs2_do_remount_fs(sb, flags, data);
24692abc475SAndres Salomon }
24792abc475SAndres Salomon 
248ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jffs2_super_operations =
2491da177e4SLinus Torvalds {
2501da177e4SLinus Torvalds 	.alloc_inode =	jffs2_alloc_inode,
2511da177e4SLinus Torvalds 	.destroy_inode =jffs2_destroy_inode,
2521da177e4SLinus Torvalds 	.put_super =	jffs2_put_super,
2531da177e4SLinus Torvalds 	.write_super =	jffs2_write_super,
2541da177e4SLinus Torvalds 	.statfs =	jffs2_statfs,
2551da177e4SLinus Torvalds 	.remount_fs =	jffs2_remount_fs,
256b57922d9SAl Viro 	.evict_inode =	jffs2_evict_inode,
2571da177e4SLinus Torvalds 	.dirty_inode =	jffs2_dirty_inode,
25892abc475SAndres Salomon 	.show_options =	jffs2_show_options,
2591da177e4SLinus Torvalds 	.sync_fs =	jffs2_sync_fs,
2601da177e4SLinus Torvalds };
2611da177e4SLinus Torvalds 
262acaebfd8SDavid Howells /*
263acaebfd8SDavid Howells  * fill in the superblock
264acaebfd8SDavid Howells  */
265acaebfd8SDavid Howells static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
2661da177e4SLinus Torvalds {
2671da177e4SLinus Torvalds 	struct jffs2_sb_info *c;
268db719222SJan Blunck 	int ret;
269db719222SJan Blunck 
270acaebfd8SDavid Howells 	D1(printk(KERN_DEBUG "jffs2_get_sb_mtd():"
271acaebfd8SDavid Howells 		  " New superblock for device %d (\"%s\")\n",
272acaebfd8SDavid Howells 		  sb->s_mtd->index, sb->s_mtd->name));
2731da177e4SLinus Torvalds 
274f8314dc6SPanagiotis Issaris 	c = kzalloc(sizeof(*c), GFP_KERNEL);
2751a028dd2SArnd Bergmann 	if (!c)
276454e2398SDavid Howells 		return -ENOMEM;
2771da177e4SLinus Torvalds 
278acaebfd8SDavid Howells 	c->mtd = sb->s_mtd;
279acaebfd8SDavid Howells 	c->os_priv = sb;
280acaebfd8SDavid Howells 	sb->s_fs_info = c;
2811da177e4SLinus Torvalds 
28292abc475SAndres Salomon 	ret = jffs2_parse_options(c, data);
28392abc475SAndres Salomon 	if (ret) {
28492abc475SAndres Salomon 		kfree(c);
28592abc475SAndres Salomon 		return -EINVAL;
28692abc475SAndres Salomon 	}
28792abc475SAndres Salomon 
288acaebfd8SDavid Howells 	/* Initialize JFFS2 superblock locks, the further initialization will
289acaebfd8SDavid Howells 	 * be done later */
290ced22070SDavid Woodhouse 	mutex_init(&c->alloc_sem);
291ced22070SDavid Woodhouse 	mutex_init(&c->erase_free_sem);
292b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->erase_wait);
293b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->inocache_wq);
294b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->erase_completion_lock);
295b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->inocache_lock);
296b6220598SArtem B. Bityuckiy 
2971da177e4SLinus Torvalds 	sb->s_op = &jffs2_super_operations;
2985f556aabSDavid Woodhouse 	sb->s_export_op = &jffs2_export_ops;
299acaebfd8SDavid Howells 	sb->s_flags = sb->s_flags | MS_NOATIME;
300aa98d7cfSKaiGai Kohei 	sb->s_xattr = jffs2_xattr_handlers;
301aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL
302aa98d7cfSKaiGai Kohei 	sb->s_flags |= MS_POSIXACL;
303aa98d7cfSKaiGai Kohei #endif
304db719222SJan Blunck 	ret = jffs2_do_fill_super(sb, data, silent);
305db719222SJan Blunck 	return ret;
3061da177e4SLinus Torvalds }
3071da177e4SLinus Torvalds 
308848b83a5SAl Viro static struct dentry *jffs2_mount(struct file_system_type *fs_type,
3091da177e4SLinus Torvalds 			int flags, const char *dev_name,
310848b83a5SAl Viro 			void *data)
3111da177e4SLinus Torvalds {
312848b83a5SAl Viro 	return mount_mtd(fs_type, flags, dev_name, data, jffs2_fill_super);
3131da177e4SLinus Torvalds }
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds static void jffs2_put_super (struct super_block *sb)
3161da177e4SLinus Torvalds {
3171da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds 	D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
3201da177e4SLinus Torvalds 
3218c85e125SChristoph Hellwig 	if (sb->s_dirt)
3228c85e125SChristoph Hellwig 		jffs2_write_super(sb);
3238c85e125SChristoph Hellwig 
324ced22070SDavid Woodhouse 	mutex_lock(&c->alloc_sem);
3251da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
326ced22070SDavid Woodhouse 	mutex_unlock(&c->alloc_sem);
327e631ddbaSFerenc Havasi 
328e631ddbaSFerenc Havasi 	jffs2_sum_exit(c);
329e631ddbaSFerenc Havasi 
3301da177e4SLinus Torvalds 	jffs2_free_ino_caches(c);
3311da177e4SLinus Torvalds 	jffs2_free_raw_node_refs(c);
3324ce1f562SFerenc Havasi 	if (jffs2_blocks_use_vmalloc(c))
3331da177e4SLinus Torvalds 		vfree(c->blocks);
3341da177e4SLinus Torvalds 	else
3351da177e4SLinus Torvalds 		kfree(c->blocks);
3361da177e4SLinus Torvalds 	jffs2_flash_cleanup(c);
3371da177e4SLinus Torvalds 	kfree(c->inocache_list);
338aa98d7cfSKaiGai Kohei 	jffs2_clear_xattr_subsystem(c);
3391da177e4SLinus Torvalds 	if (c->mtd->sync)
3401da177e4SLinus Torvalds 		c->mtd->sync(c->mtd);
3411da177e4SLinus Torvalds 
3421da177e4SLinus Torvalds 	D1(printk(KERN_DEBUG "jffs2_put_super returning\n"));
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds 
3451da177e4SLinus Torvalds static void jffs2_kill_sb(struct super_block *sb)
3461da177e4SLinus Torvalds {
3471da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
348a69dde91SArtem B. Bityuckiy 	if (!(sb->s_flags & MS_RDONLY))
349a69dde91SArtem B. Bityuckiy 		jffs2_stop_garbage_collect_thread(c);
350acaebfd8SDavid Howells 	kill_mtd_super(sb);
3511da177e4SLinus Torvalds 	kfree(c);
3521da177e4SLinus Torvalds }
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds static struct file_system_type jffs2_fs_type = {
3551da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
3561da177e4SLinus Torvalds 	.name =		"jffs2",
357848b83a5SAl Viro 	.mount =	jffs2_mount,
3581da177e4SLinus Torvalds 	.kill_sb =	jffs2_kill_sb,
3591da177e4SLinus Torvalds };
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds static int __init init_jffs2_fs(void)
3621da177e4SLinus Torvalds {
3631da177e4SLinus Torvalds 	int ret;
3641da177e4SLinus Torvalds 
3653e68fbb5SDavid Woodhouse 	/* Paranoia checks for on-medium structures. If we ask GCC
3663e68fbb5SDavid Woodhouse 	   to pack them with __attribute__((packed)) then it _also_
3673e68fbb5SDavid Woodhouse 	   assumes that they're not aligned -- so it emits crappy
3683e68fbb5SDavid Woodhouse 	   code on some architectures. Ideally we want an attribute
3693e68fbb5SDavid Woodhouse 	   which means just 'no padding', without the alignment
3703e68fbb5SDavid Woodhouse 	   thing. But GCC doesn't have that -- we have to just
3713e68fbb5SDavid Woodhouse 	   hope the structs are the right sizes, instead. */
3722ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
3732ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
3742ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
3752ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
3763e68fbb5SDavid Woodhouse 
3771da177e4SLinus Torvalds 	printk(KERN_INFO "JFFS2 version 2.2."
3782f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
3791da177e4SLinus Torvalds 	       " (NAND)"
3801da177e4SLinus Torvalds #endif
381e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY
382e631ddbaSFerenc Havasi 	       " (SUMMARY) "
383e631ddbaSFerenc Havasi #endif
384c00c310eSDavid Woodhouse 	       " © 2001-2006 Red Hat, Inc.\n");
3851da177e4SLinus Torvalds 
3861da177e4SLinus Torvalds 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
3871da177e4SLinus Torvalds 					     sizeof(struct jffs2_inode_info),
388fffb60f9SPaul Jackson 					     0, (SLAB_RECLAIM_ACCOUNT|
389fffb60f9SPaul Jackson 						SLAB_MEM_SPREAD),
39020c2df83SPaul Mundt 					     jffs2_i_init_once);
3911da177e4SLinus Torvalds 	if (!jffs2_inode_cachep) {
3921da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
3931da177e4SLinus Torvalds 		return -ENOMEM;
3941da177e4SLinus Torvalds 	}
3951da177e4SLinus Torvalds 	ret = jffs2_compressors_init();
3961da177e4SLinus Torvalds 	if (ret) {
3971da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
3981da177e4SLinus Torvalds 		goto out;
3991da177e4SLinus Torvalds 	}
4001da177e4SLinus Torvalds 	ret = jffs2_create_slab_caches();
4011da177e4SLinus Torvalds 	if (ret) {
4021da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
4031da177e4SLinus Torvalds 		goto out_compressors;
4041da177e4SLinus Torvalds 	}
4051da177e4SLinus Torvalds 	ret = register_filesystem(&jffs2_fs_type);
4061da177e4SLinus Torvalds 	if (ret) {
4071da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n");
4081da177e4SLinus Torvalds 		goto out_slab;
4091da177e4SLinus Torvalds 	}
4101da177e4SLinus Torvalds 	return 0;
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds  out_slab:
4131da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
4141da177e4SLinus Torvalds  out_compressors:
4151da177e4SLinus Torvalds 	jffs2_compressors_exit();
4161da177e4SLinus Torvalds  out:
4171da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
4181da177e4SLinus Torvalds 	return ret;
4191da177e4SLinus Torvalds }
4201da177e4SLinus Torvalds 
4211da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void)
4221da177e4SLinus Torvalds {
4231da177e4SLinus Torvalds 	unregister_filesystem(&jffs2_fs_type);
4241da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
4251da177e4SLinus Torvalds 	jffs2_compressors_exit();
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