xref: /openbmc/linux/fs/jffs2/super.c (revision 8da8ba2e)
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 
47fa0d7e3dSNick Piggin static void jffs2_i_callback(struct rcu_head *head)
48fa0d7e3dSNick Piggin {
49fa0d7e3dSNick Piggin 	struct inode *inode = container_of(head, struct inode, i_rcu);
50fa0d7e3dSNick Piggin 	kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode));
51fa0d7e3dSNick Piggin }
52fa0d7e3dSNick Piggin 
531da177e4SLinus Torvalds static void jffs2_destroy_inode(struct inode *inode)
541da177e4SLinus Torvalds {
55fa0d7e3dSNick Piggin 	call_rcu(&inode->i_rcu, jffs2_i_callback);
561da177e4SLinus Torvalds }
571da177e4SLinus Torvalds 
5851cc5068SAlexey Dobriyan static void jffs2_i_init_once(void *foo)
591da177e4SLinus Torvalds {
604e571abaSDavid Woodhouse 	struct jffs2_inode_info *f = foo;
611da177e4SLinus Torvalds 
624e571abaSDavid Woodhouse 	mutex_init(&f->sem);
634e571abaSDavid Woodhouse 	inode_init_once(&f->vfs_inode);
641da177e4SLinus Torvalds }
651da177e4SLinus Torvalds 
6601ba6875SChristoph Hellwig static void jffs2_write_super(struct super_block *sb)
6701ba6875SChristoph Hellwig {
6801ba6875SChristoph Hellwig 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
69ebc1ac16SChristoph Hellwig 
70ebc1ac16SChristoph Hellwig 	lock_super(sb);
7101ba6875SChristoph Hellwig 	sb->s_dirt = 0;
7201ba6875SChristoph Hellwig 
73ebc1ac16SChristoph Hellwig 	if (!(sb->s_flags & MS_RDONLY)) {
749c261b33SJoe Perches 		jffs2_dbg(1, "%s()\n", __func__);
7501ba6875SChristoph Hellwig 		jffs2_flush_wbuf_gc(c, 0);
7601ba6875SChristoph Hellwig 	}
7701ba6875SChristoph Hellwig 
78ebc1ac16SChristoph Hellwig 	unlock_super(sb);
79ebc1ac16SChristoph Hellwig }
80ebc1ac16SChristoph Hellwig 
8192abc475SAndres Salomon static const char *jffs2_compr_name(unsigned int compr)
8292abc475SAndres Salomon {
8392abc475SAndres Salomon 	switch (compr) {
8492abc475SAndres Salomon 	case JFFS2_COMPR_MODE_NONE:
8592abc475SAndres Salomon 		return "none";
86123005f3SAndres Salomon #ifdef CONFIG_JFFS2_LZO
87123005f3SAndres Salomon 	case JFFS2_COMPR_MODE_FORCELZO:
88123005f3SAndres Salomon 		return "lzo";
89123005f3SAndres Salomon #endif
90123005f3SAndres Salomon #ifdef CONFIG_JFFS2_ZLIB
91123005f3SAndres Salomon 	case JFFS2_COMPR_MODE_FORCEZLIB:
92123005f3SAndres Salomon 		return "zlib";
93123005f3SAndres Salomon #endif
9492abc475SAndres Salomon 	default:
9592abc475SAndres Salomon 		/* should never happen; programmer error */
9692abc475SAndres Salomon 		WARN_ON(1);
9792abc475SAndres Salomon 		return "";
9892abc475SAndres Salomon 	}
9992abc475SAndres Salomon }
10092abc475SAndres Salomon 
10134c80b1dSAl Viro static int jffs2_show_options(struct seq_file *s, struct dentry *root)
10292abc475SAndres Salomon {
10334c80b1dSAl Viro 	struct jffs2_sb_info *c = JFFS2_SB_INFO(root->d_sb);
10492abc475SAndres Salomon 	struct jffs2_mount_opts *opts = &c->mount_opts;
10592abc475SAndres Salomon 
10692abc475SAndres Salomon 	if (opts->override_compr)
10792abc475SAndres Salomon 		seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr));
1088da8ba2eSDaniel Drake 	if (opts->rp_size)
1098da8ba2eSDaniel Drake 		seq_printf(s, ",rp_size=%u", opts->rp_size / 1024);
11092abc475SAndres Salomon 
11192abc475SAndres Salomon 	return 0;
11292abc475SAndres Salomon }
11392abc475SAndres Salomon 
1141da177e4SLinus Torvalds static int jffs2_sync_fs(struct super_block *sb, int wait)
1151da177e4SLinus Torvalds {
1161da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
1171da177e4SLinus Torvalds 
118d579ed00SChristoph Hellwig 	jffs2_write_super(sb);
119d579ed00SChristoph Hellwig 
120ced22070SDavid Woodhouse 	mutex_lock(&c->alloc_sem);
1211da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
122ced22070SDavid Woodhouse 	mutex_unlock(&c->alloc_sem);
1231da177e4SLinus Torvalds 	return 0;
1241da177e4SLinus Torvalds }
1251da177e4SLinus Torvalds 
1265f556aabSDavid Woodhouse static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
1275f556aabSDavid Woodhouse 					 uint32_t generation)
1285f556aabSDavid Woodhouse {
1295f556aabSDavid Woodhouse 	/* We don't care about i_generation. We'll destroy the flash
1305f556aabSDavid Woodhouse 	   before we start re-using inode numbers anyway. And even
1315f556aabSDavid Woodhouse 	   if that wasn't true, we'd have other problems...*/
1325f556aabSDavid Woodhouse 	return jffs2_iget(sb, ino);
1335f556aabSDavid Woodhouse }
1345f556aabSDavid Woodhouse 
1355f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
1365f556aabSDavid Woodhouse 					 int fh_len, int fh_type)
1375f556aabSDavid Woodhouse {
1385f556aabSDavid Woodhouse         return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
1395f556aabSDavid Woodhouse                                     jffs2_nfs_get_inode);
1405f556aabSDavid Woodhouse }
1415f556aabSDavid Woodhouse 
1425f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid,
1435f556aabSDavid Woodhouse 					 int fh_len, int fh_type)
1445f556aabSDavid Woodhouse {
1455f556aabSDavid Woodhouse         return generic_fh_to_parent(sb, fid, fh_len, fh_type,
1465f556aabSDavid Woodhouse                                     jffs2_nfs_get_inode);
1475f556aabSDavid Woodhouse }
1485f556aabSDavid Woodhouse 
1495f556aabSDavid Woodhouse static struct dentry *jffs2_get_parent(struct dentry *child)
1505f556aabSDavid Woodhouse {
1515f556aabSDavid Woodhouse 	struct jffs2_inode_info *f;
1525f556aabSDavid Woodhouse 	uint32_t pino;
1535f556aabSDavid Woodhouse 
1545f556aabSDavid Woodhouse 	BUG_ON(!S_ISDIR(child->d_inode->i_mode));
1555f556aabSDavid Woodhouse 
1565f556aabSDavid Woodhouse 	f = JFFS2_INODE_INFO(child->d_inode);
1575f556aabSDavid Woodhouse 
1585f556aabSDavid Woodhouse 	pino = f->inocache->pino_nlink;
1595f556aabSDavid Woodhouse 
1605f556aabSDavid Woodhouse 	JFFS2_DEBUG("Parent of directory ino #%u is #%u\n",
1615f556aabSDavid Woodhouse 		    f->inocache->ino, pino);
1625f556aabSDavid Woodhouse 
1635f556aabSDavid Woodhouse 	return d_obtain_alias(jffs2_iget(child->d_inode->i_sb, pino));
1645f556aabSDavid Woodhouse }
1655f556aabSDavid Woodhouse 
166ac4cfdd6SAlexey Dobriyan static const struct export_operations jffs2_export_ops = {
1675f556aabSDavid Woodhouse 	.get_parent = jffs2_get_parent,
1685f556aabSDavid Woodhouse 	.fh_to_dentry = jffs2_fh_to_dentry,
1695f556aabSDavid Woodhouse 	.fh_to_parent = jffs2_fh_to_parent,
1705f556aabSDavid Woodhouse };
1715f556aabSDavid Woodhouse 
17292abc475SAndres Salomon /*
17392abc475SAndres Salomon  * JFFS2 mount options.
17492abc475SAndres Salomon  *
17592abc475SAndres Salomon  * Opt_override_compr: override default compressor
1768da8ba2eSDaniel Drake  * Opt_rp_size: size of reserved pool in KiB
17792abc475SAndres Salomon  * Opt_err: just end of array marker
17892abc475SAndres Salomon  */
17992abc475SAndres Salomon enum {
18092abc475SAndres Salomon 	Opt_override_compr,
1818da8ba2eSDaniel Drake 	Opt_rp_size,
18292abc475SAndres Salomon 	Opt_err,
18392abc475SAndres Salomon };
18492abc475SAndres Salomon 
18592abc475SAndres Salomon static const match_table_t tokens = {
18692abc475SAndres Salomon 	{Opt_override_compr, "compr=%s"},
1878da8ba2eSDaniel Drake 	{Opt_rp_size, "rp_size=%u"},
18892abc475SAndres Salomon 	{Opt_err, NULL},
18992abc475SAndres Salomon };
19092abc475SAndres Salomon 
19192abc475SAndres Salomon static int jffs2_parse_options(struct jffs2_sb_info *c, char *data)
19292abc475SAndres Salomon {
19392abc475SAndres Salomon 	substring_t args[MAX_OPT_ARGS];
19492abc475SAndres Salomon 	char *p, *name;
1958da8ba2eSDaniel Drake 	unsigned int opt;
19692abc475SAndres Salomon 
19792abc475SAndres Salomon 	if (!data)
19892abc475SAndres Salomon 		return 0;
19992abc475SAndres Salomon 
20092abc475SAndres Salomon 	while ((p = strsep(&data, ","))) {
20192abc475SAndres Salomon 		int token;
20292abc475SAndres Salomon 
20392abc475SAndres Salomon 		if (!*p)
20492abc475SAndres Salomon 			continue;
20592abc475SAndres Salomon 
20692abc475SAndres Salomon 		token = match_token(p, tokens, args);
20792abc475SAndres Salomon 		switch (token) {
20892abc475SAndres Salomon 		case Opt_override_compr:
20992abc475SAndres Salomon 			name = match_strdup(&args[0]);
21092abc475SAndres Salomon 
21192abc475SAndres Salomon 			if (!name)
21292abc475SAndres Salomon 				return -ENOMEM;
213123005f3SAndres Salomon 			if (!strcmp(name, "none"))
21492abc475SAndres Salomon 				c->mount_opts.compr = JFFS2_COMPR_MODE_NONE;
215123005f3SAndres Salomon #ifdef CONFIG_JFFS2_LZO
216123005f3SAndres Salomon 			else if (!strcmp(name, "lzo"))
217123005f3SAndres Salomon 				c->mount_opts.compr = JFFS2_COMPR_MODE_FORCELZO;
218123005f3SAndres Salomon #endif
219123005f3SAndres Salomon #ifdef CONFIG_JFFS2_ZLIB
220123005f3SAndres Salomon 			else if (!strcmp(name, "zlib"))
221123005f3SAndres Salomon 				c->mount_opts.compr =
222123005f3SAndres Salomon 						JFFS2_COMPR_MODE_FORCEZLIB;
223123005f3SAndres Salomon #endif
224123005f3SAndres Salomon 			else {
2255a528957SJoe Perches 				pr_err("Error: unknown compressor \"%s\"\n",
226123005f3SAndres Salomon 				       name);
227123005f3SAndres Salomon 				kfree(name);
228123005f3SAndres Salomon 				return -EINVAL;
22992abc475SAndres Salomon 			}
23092abc475SAndres Salomon 			kfree(name);
231123005f3SAndres Salomon 			c->mount_opts.override_compr = true;
23292abc475SAndres Salomon 			break;
2338da8ba2eSDaniel Drake 		case Opt_rp_size:
2348da8ba2eSDaniel Drake 			if (match_int(&args[0], &opt))
2358da8ba2eSDaniel Drake 				return -EINVAL;
2368da8ba2eSDaniel Drake 			opt *= 1024;
2378da8ba2eSDaniel Drake 			if (opt > c->mtd->size) {
2388da8ba2eSDaniel Drake 				pr_warn("Too large reserve pool specified, max "
2398da8ba2eSDaniel Drake 					"is %llu KB\n", c->mtd->size / 1024);
2408da8ba2eSDaniel Drake 				return -EINVAL;
2418da8ba2eSDaniel Drake 			}
2428da8ba2eSDaniel Drake 			c->mount_opts.rp_size = opt;
2438da8ba2eSDaniel Drake 			break;
24492abc475SAndres Salomon 		default:
2455a528957SJoe Perches 			pr_err("Error: unrecognized mount option '%s' or missing value\n",
24692abc475SAndres Salomon 			       p);
24792abc475SAndres Salomon 			return -EINVAL;
24892abc475SAndres Salomon 		}
24992abc475SAndres Salomon 	}
25092abc475SAndres Salomon 
25192abc475SAndres Salomon 	return 0;
25292abc475SAndres Salomon }
25392abc475SAndres Salomon 
25492abc475SAndres Salomon static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data)
25592abc475SAndres Salomon {
25692abc475SAndres Salomon 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
25792abc475SAndres Salomon 	int err;
25892abc475SAndres Salomon 
25992abc475SAndres Salomon 	err = jffs2_parse_options(c, data);
26092abc475SAndres Salomon 	if (err)
26192abc475SAndres Salomon 		return -EINVAL;
26292abc475SAndres Salomon 
26392abc475SAndres Salomon 	return jffs2_do_remount_fs(sb, flags, data);
26492abc475SAndres Salomon }
26592abc475SAndres Salomon 
266ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jffs2_super_operations =
2671da177e4SLinus Torvalds {
2681da177e4SLinus Torvalds 	.alloc_inode =	jffs2_alloc_inode,
2691da177e4SLinus Torvalds 	.destroy_inode =jffs2_destroy_inode,
2701da177e4SLinus Torvalds 	.put_super =	jffs2_put_super,
2711da177e4SLinus Torvalds 	.write_super =	jffs2_write_super,
2721da177e4SLinus Torvalds 	.statfs =	jffs2_statfs,
2731da177e4SLinus Torvalds 	.remount_fs =	jffs2_remount_fs,
274b57922d9SAl Viro 	.evict_inode =	jffs2_evict_inode,
2751da177e4SLinus Torvalds 	.dirty_inode =	jffs2_dirty_inode,
27692abc475SAndres Salomon 	.show_options =	jffs2_show_options,
2771da177e4SLinus Torvalds 	.sync_fs =	jffs2_sync_fs,
2781da177e4SLinus Torvalds };
2791da177e4SLinus Torvalds 
280acaebfd8SDavid Howells /*
281acaebfd8SDavid Howells  * fill in the superblock
282acaebfd8SDavid Howells  */
283acaebfd8SDavid Howells static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
2841da177e4SLinus Torvalds {
2851da177e4SLinus Torvalds 	struct jffs2_sb_info *c;
286db719222SJan Blunck 	int ret;
287db719222SJan Blunck 
2889c261b33SJoe Perches 	jffs2_dbg(1, "jffs2_get_sb_mtd():"
289acaebfd8SDavid Howells 		  " New superblock for device %d (\"%s\")\n",
2909c261b33SJoe Perches 		  sb->s_mtd->index, sb->s_mtd->name);
2911da177e4SLinus Torvalds 
292f8314dc6SPanagiotis Issaris 	c = kzalloc(sizeof(*c), GFP_KERNEL);
2931a028dd2SArnd Bergmann 	if (!c)
294454e2398SDavid Howells 		return -ENOMEM;
2951da177e4SLinus Torvalds 
296acaebfd8SDavid Howells 	c->mtd = sb->s_mtd;
297acaebfd8SDavid Howells 	c->os_priv = sb;
298acaebfd8SDavid Howells 	sb->s_fs_info = c;
2991da177e4SLinus Torvalds 
30092abc475SAndres Salomon 	ret = jffs2_parse_options(c, data);
30192abc475SAndres Salomon 	if (ret) {
30292abc475SAndres Salomon 		kfree(c);
30392abc475SAndres Salomon 		return -EINVAL;
30492abc475SAndres Salomon 	}
30592abc475SAndres Salomon 
306acaebfd8SDavid Howells 	/* Initialize JFFS2 superblock locks, the further initialization will
307acaebfd8SDavid Howells 	 * be done later */
308ced22070SDavid Woodhouse 	mutex_init(&c->alloc_sem);
309ced22070SDavid Woodhouse 	mutex_init(&c->erase_free_sem);
310b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->erase_wait);
311b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->inocache_wq);
312b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->erase_completion_lock);
313b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->inocache_lock);
314b6220598SArtem B. Bityuckiy 
3151da177e4SLinus Torvalds 	sb->s_op = &jffs2_super_operations;
3165f556aabSDavid Woodhouse 	sb->s_export_op = &jffs2_export_ops;
317acaebfd8SDavid Howells 	sb->s_flags = sb->s_flags | MS_NOATIME;
318aa98d7cfSKaiGai Kohei 	sb->s_xattr = jffs2_xattr_handlers;
319aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL
320aa98d7cfSKaiGai Kohei 	sb->s_flags |= MS_POSIXACL;
321aa98d7cfSKaiGai Kohei #endif
322db719222SJan Blunck 	ret = jffs2_do_fill_super(sb, data, silent);
323db719222SJan Blunck 	return ret;
3241da177e4SLinus Torvalds }
3251da177e4SLinus Torvalds 
326848b83a5SAl Viro static struct dentry *jffs2_mount(struct file_system_type *fs_type,
3271da177e4SLinus Torvalds 			int flags, const char *dev_name,
328848b83a5SAl Viro 			void *data)
3291da177e4SLinus Torvalds {
330848b83a5SAl Viro 	return mount_mtd(fs_type, flags, dev_name, data, jffs2_fill_super);
3311da177e4SLinus Torvalds }
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds static void jffs2_put_super (struct super_block *sb)
3341da177e4SLinus Torvalds {
3351da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
3361da177e4SLinus Torvalds 
3379c261b33SJoe Perches 	jffs2_dbg(2, "%s()\n", __func__);
3381da177e4SLinus Torvalds 
3398c85e125SChristoph Hellwig 	if (sb->s_dirt)
3408c85e125SChristoph Hellwig 		jffs2_write_super(sb);
3418c85e125SChristoph Hellwig 
342ced22070SDavid Woodhouse 	mutex_lock(&c->alloc_sem);
3431da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
344ced22070SDavid Woodhouse 	mutex_unlock(&c->alloc_sem);
345e631ddbaSFerenc Havasi 
346e631ddbaSFerenc Havasi 	jffs2_sum_exit(c);
347e631ddbaSFerenc Havasi 
3481da177e4SLinus Torvalds 	jffs2_free_ino_caches(c);
3491da177e4SLinus Torvalds 	jffs2_free_raw_node_refs(c);
3504ce1f562SFerenc Havasi 	if (jffs2_blocks_use_vmalloc(c))
3511da177e4SLinus Torvalds 		vfree(c->blocks);
3521da177e4SLinus Torvalds 	else
3531da177e4SLinus Torvalds 		kfree(c->blocks);
3541da177e4SLinus Torvalds 	jffs2_flash_cleanup(c);
3551da177e4SLinus Torvalds 	kfree(c->inocache_list);
356aa98d7cfSKaiGai Kohei 	jffs2_clear_xattr_subsystem(c);
35785f2f2a8SArtem Bityutskiy 	mtd_sync(c->mtd);
3589c261b33SJoe Perches 	jffs2_dbg(1, "%s(): returning\n", __func__);
3591da177e4SLinus Torvalds }
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds static void jffs2_kill_sb(struct super_block *sb)
3621da177e4SLinus Torvalds {
3631da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
364a69dde91SArtem B. Bityuckiy 	if (!(sb->s_flags & MS_RDONLY))
365a69dde91SArtem B. Bityuckiy 		jffs2_stop_garbage_collect_thread(c);
366acaebfd8SDavid Howells 	kill_mtd_super(sb);
3671da177e4SLinus Torvalds 	kfree(c);
3681da177e4SLinus Torvalds }
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds static struct file_system_type jffs2_fs_type = {
3711da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
3721da177e4SLinus Torvalds 	.name =		"jffs2",
373848b83a5SAl Viro 	.mount =	jffs2_mount,
3741da177e4SLinus Torvalds 	.kill_sb =	jffs2_kill_sb,
3751da177e4SLinus Torvalds };
3761da177e4SLinus Torvalds 
3771da177e4SLinus Torvalds static int __init init_jffs2_fs(void)
3781da177e4SLinus Torvalds {
3791da177e4SLinus Torvalds 	int ret;
3801da177e4SLinus Torvalds 
3813e68fbb5SDavid Woodhouse 	/* Paranoia checks for on-medium structures. If we ask GCC
3823e68fbb5SDavid Woodhouse 	   to pack them with __attribute__((packed)) then it _also_
3833e68fbb5SDavid Woodhouse 	   assumes that they're not aligned -- so it emits crappy
3843e68fbb5SDavid Woodhouse 	   code on some architectures. Ideally we want an attribute
3853e68fbb5SDavid Woodhouse 	   which means just 'no padding', without the alignment
3863e68fbb5SDavid Woodhouse 	   thing. But GCC doesn't have that -- we have to just
3873e68fbb5SDavid Woodhouse 	   hope the structs are the right sizes, instead. */
3882ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
3892ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
3902ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
3912ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
3923e68fbb5SDavid Woodhouse 
3935a528957SJoe Perches 	pr_info("version 2.2."
3942f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
3951da177e4SLinus Torvalds 	       " (NAND)"
3961da177e4SLinus Torvalds #endif
397e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY
398e631ddbaSFerenc Havasi 	       " (SUMMARY) "
399e631ddbaSFerenc Havasi #endif
400c00c310eSDavid Woodhouse 	       " © 2001-2006 Red Hat, Inc.\n");
4011da177e4SLinus Torvalds 
4021da177e4SLinus Torvalds 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
4031da177e4SLinus Torvalds 					     sizeof(struct jffs2_inode_info),
404fffb60f9SPaul Jackson 					     0, (SLAB_RECLAIM_ACCOUNT|
405fffb60f9SPaul Jackson 						SLAB_MEM_SPREAD),
40620c2df83SPaul Mundt 					     jffs2_i_init_once);
4071da177e4SLinus Torvalds 	if (!jffs2_inode_cachep) {
4085a528957SJoe Perches 		pr_err("error: Failed to initialise inode cache\n");
4091da177e4SLinus Torvalds 		return -ENOMEM;
4101da177e4SLinus Torvalds 	}
4111da177e4SLinus Torvalds 	ret = jffs2_compressors_init();
4121da177e4SLinus Torvalds 	if (ret) {
4135a528957SJoe Perches 		pr_err("error: Failed to initialise compressors\n");
4141da177e4SLinus Torvalds 		goto out;
4151da177e4SLinus Torvalds 	}
4161da177e4SLinus Torvalds 	ret = jffs2_create_slab_caches();
4171da177e4SLinus Torvalds 	if (ret) {
4185a528957SJoe Perches 		pr_err("error: Failed to initialise slab caches\n");
4191da177e4SLinus Torvalds 		goto out_compressors;
4201da177e4SLinus Torvalds 	}
4211da177e4SLinus Torvalds 	ret = register_filesystem(&jffs2_fs_type);
4221da177e4SLinus Torvalds 	if (ret) {
4235a528957SJoe Perches 		pr_err("error: Failed to register filesystem\n");
4241da177e4SLinus Torvalds 		goto out_slab;
4251da177e4SLinus Torvalds 	}
4261da177e4SLinus Torvalds 	return 0;
4271da177e4SLinus Torvalds 
4281da177e4SLinus Torvalds  out_slab:
4291da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
4301da177e4SLinus Torvalds  out_compressors:
4311da177e4SLinus Torvalds 	jffs2_compressors_exit();
4321da177e4SLinus Torvalds  out:
4331da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
4341da177e4SLinus Torvalds 	return ret;
4351da177e4SLinus Torvalds }
4361da177e4SLinus Torvalds 
4371da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void)
4381da177e4SLinus Torvalds {
4391da177e4SLinus Torvalds 	unregister_filesystem(&jffs2_fs_type);
4401da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
4411da177e4SLinus Torvalds 	jffs2_compressors_exit();
4421da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
4431da177e4SLinus Torvalds }
4441da177e4SLinus Torvalds 
4451da177e4SLinus Torvalds module_init(init_jffs2_fs);
4461da177e4SLinus Torvalds module_exit(exit_jffs2_fs);
4471da177e4SLinus Torvalds 
4481da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journalling Flash File System, v2");
4491da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc.");
4501da177e4SLinus Torvalds MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
4511da177e4SLinus Torvalds 		       // the sake of this tag. It's Free Software.
452