162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory.
962306a36Sopenharmony_ci *
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci#include <linux/init.h>
1862306a36Sopenharmony_ci#include <linux/list.h>
1962306a36Sopenharmony_ci#include <linux/fs.h>
2062306a36Sopenharmony_ci#include <linux/err.h>
2162306a36Sopenharmony_ci#include <linux/mount.h>
2262306a36Sopenharmony_ci#include <linux/fs_context.h>
2362306a36Sopenharmony_ci#include <linux/fs_parser.h>
2462306a36Sopenharmony_ci#include <linux/jffs2.h>
2562306a36Sopenharmony_ci#include <linux/pagemap.h>
2662306a36Sopenharmony_ci#include <linux/mtd/super.h>
2762306a36Sopenharmony_ci#include <linux/ctype.h>
2862306a36Sopenharmony_ci#include <linux/namei.h>
2962306a36Sopenharmony_ci#include <linux/seq_file.h>
3062306a36Sopenharmony_ci#include <linux/exportfs.h>
3162306a36Sopenharmony_ci#include "compr.h"
3262306a36Sopenharmony_ci#include "nodelist.h"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic void jffs2_put_super(struct super_block *);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic struct kmem_cache *jffs2_inode_cachep;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic struct inode *jffs2_alloc_inode(struct super_block *sb)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct jffs2_inode_info *f;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	f = alloc_inode_sb(sb, jffs2_inode_cachep, GFP_KERNEL);
4362306a36Sopenharmony_ci	if (!f)
4462306a36Sopenharmony_ci		return NULL;
4562306a36Sopenharmony_ci	return &f->vfs_inode;
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic void jffs2_free_inode(struct inode *inode)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	kfree(f->target);
5362306a36Sopenharmony_ci	kmem_cache_free(jffs2_inode_cachep, f);
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic void jffs2_i_init_once(void *foo)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	struct jffs2_inode_info *f = foo;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	mutex_init(&f->sem);
6162306a36Sopenharmony_ci	inode_init_once(&f->vfs_inode);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic const char *jffs2_compr_name(unsigned int compr)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	switch (compr) {
6762306a36Sopenharmony_ci	case JFFS2_COMPR_MODE_NONE:
6862306a36Sopenharmony_ci		return "none";
6962306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_LZO
7062306a36Sopenharmony_ci	case JFFS2_COMPR_MODE_FORCELZO:
7162306a36Sopenharmony_ci		return "lzo";
7262306a36Sopenharmony_ci#endif
7362306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_ZLIB
7462306a36Sopenharmony_ci	case JFFS2_COMPR_MODE_FORCEZLIB:
7562306a36Sopenharmony_ci		return "zlib";
7662306a36Sopenharmony_ci#endif
7762306a36Sopenharmony_ci	default:
7862306a36Sopenharmony_ci		/* should never happen; programmer error */
7962306a36Sopenharmony_ci		WARN_ON(1);
8062306a36Sopenharmony_ci		return "";
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic int jffs2_show_options(struct seq_file *s, struct dentry *root)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct jffs2_sb_info *c = JFFS2_SB_INFO(root->d_sb);
8762306a36Sopenharmony_ci	struct jffs2_mount_opts *opts = &c->mount_opts;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (opts->override_compr)
9062306a36Sopenharmony_ci		seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr));
9162306a36Sopenharmony_ci	if (opts->set_rp_size)
9262306a36Sopenharmony_ci		seq_printf(s, ",rp_size=%u", opts->rp_size / 1024);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	return 0;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic int jffs2_sync_fs(struct super_block *sb, int wait)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
10262306a36Sopenharmony_ci	if (jffs2_is_writebuffered(c))
10362306a36Sopenharmony_ci		cancel_delayed_work_sync(&c->wbuf_dwork);
10462306a36Sopenharmony_ci#endif
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	mutex_lock(&c->alloc_sem);
10762306a36Sopenharmony_ci	jffs2_flush_wbuf_pad(c);
10862306a36Sopenharmony_ci	mutex_unlock(&c->alloc_sem);
10962306a36Sopenharmony_ci	return 0;
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
11362306a36Sopenharmony_ci					 uint32_t generation)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	/* We don't care about i_generation. We'll destroy the flash
11662306a36Sopenharmony_ci	   before we start re-using inode numbers anyway. And even
11762306a36Sopenharmony_ci	   if that wasn't true, we'd have other problems...*/
11862306a36Sopenharmony_ci	return jffs2_iget(sb, ino);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
12262306a36Sopenharmony_ci					 int fh_len, int fh_type)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci        return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
12562306a36Sopenharmony_ci                                    jffs2_nfs_get_inode);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid,
12962306a36Sopenharmony_ci					 int fh_len, int fh_type)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci        return generic_fh_to_parent(sb, fid, fh_len, fh_type,
13262306a36Sopenharmony_ci                                    jffs2_nfs_get_inode);
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic struct dentry *jffs2_get_parent(struct dentry *child)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	struct jffs2_inode_info *f;
13862306a36Sopenharmony_ci	uint32_t pino;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	BUG_ON(!d_is_dir(child));
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	f = JFFS2_INODE_INFO(d_inode(child));
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	pino = f->inocache->pino_nlink;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	JFFS2_DEBUG("Parent of directory ino #%u is #%u\n",
14762306a36Sopenharmony_ci		    f->inocache->ino, pino);
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	return d_obtain_alias(jffs2_iget(child->d_sb, pino));
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic const struct export_operations jffs2_export_ops = {
15362306a36Sopenharmony_ci	.get_parent = jffs2_get_parent,
15462306a36Sopenharmony_ci	.fh_to_dentry = jffs2_fh_to_dentry,
15562306a36Sopenharmony_ci	.fh_to_parent = jffs2_fh_to_parent,
15662306a36Sopenharmony_ci};
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci/*
15962306a36Sopenharmony_ci * JFFS2 mount options.
16062306a36Sopenharmony_ci *
16162306a36Sopenharmony_ci * Opt_source: The source device
16262306a36Sopenharmony_ci * Opt_override_compr: override default compressor
16362306a36Sopenharmony_ci * Opt_rp_size: size of reserved pool in KiB
16462306a36Sopenharmony_ci */
16562306a36Sopenharmony_cienum {
16662306a36Sopenharmony_ci	Opt_override_compr,
16762306a36Sopenharmony_ci	Opt_rp_size,
16862306a36Sopenharmony_ci};
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_cistatic const struct constant_table jffs2_param_compr[] = {
17162306a36Sopenharmony_ci	{"none",	JFFS2_COMPR_MODE_NONE },
17262306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_LZO
17362306a36Sopenharmony_ci	{"lzo",		JFFS2_COMPR_MODE_FORCELZO },
17462306a36Sopenharmony_ci#endif
17562306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_ZLIB
17662306a36Sopenharmony_ci	{"zlib",	JFFS2_COMPR_MODE_FORCEZLIB },
17762306a36Sopenharmony_ci#endif
17862306a36Sopenharmony_ci	{}
17962306a36Sopenharmony_ci};
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic const struct fs_parameter_spec jffs2_fs_parameters[] = {
18262306a36Sopenharmony_ci	fsparam_enum	("compr",	Opt_override_compr, jffs2_param_compr),
18362306a36Sopenharmony_ci	fsparam_u32	("rp_size",	Opt_rp_size),
18462306a36Sopenharmony_ci	{}
18562306a36Sopenharmony_ci};
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic int jffs2_parse_param(struct fs_context *fc, struct fs_parameter *param)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct fs_parse_result result;
19062306a36Sopenharmony_ci	struct jffs2_sb_info *c = fc->s_fs_info;
19162306a36Sopenharmony_ci	int opt;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	opt = fs_parse(fc, jffs2_fs_parameters, param, &result);
19462306a36Sopenharmony_ci	if (opt < 0)
19562306a36Sopenharmony_ci		return opt;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	switch (opt) {
19862306a36Sopenharmony_ci	case Opt_override_compr:
19962306a36Sopenharmony_ci		c->mount_opts.compr = result.uint_32;
20062306a36Sopenharmony_ci		c->mount_opts.override_compr = true;
20162306a36Sopenharmony_ci		break;
20262306a36Sopenharmony_ci	case Opt_rp_size:
20362306a36Sopenharmony_ci		if (result.uint_32 > UINT_MAX / 1024)
20462306a36Sopenharmony_ci			return invalf(fc, "jffs2: rp_size unrepresentable");
20562306a36Sopenharmony_ci		c->mount_opts.rp_size = result.uint_32 * 1024;
20662306a36Sopenharmony_ci		c->mount_opts.set_rp_size = true;
20762306a36Sopenharmony_ci		break;
20862306a36Sopenharmony_ci	default:
20962306a36Sopenharmony_ci		return -EINVAL;
21062306a36Sopenharmony_ci	}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	return 0;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic inline void jffs2_update_mount_opts(struct fs_context *fc)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct jffs2_sb_info *new_c = fc->s_fs_info;
21862306a36Sopenharmony_ci	struct jffs2_sb_info *c = JFFS2_SB_INFO(fc->root->d_sb);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	mutex_lock(&c->alloc_sem);
22162306a36Sopenharmony_ci	if (new_c->mount_opts.override_compr) {
22262306a36Sopenharmony_ci		c->mount_opts.override_compr = new_c->mount_opts.override_compr;
22362306a36Sopenharmony_ci		c->mount_opts.compr = new_c->mount_opts.compr;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci	if (new_c->mount_opts.set_rp_size) {
22662306a36Sopenharmony_ci		c->mount_opts.set_rp_size = new_c->mount_opts.set_rp_size;
22762306a36Sopenharmony_ci		c->mount_opts.rp_size = new_c->mount_opts.rp_size;
22862306a36Sopenharmony_ci	}
22962306a36Sopenharmony_ci	mutex_unlock(&c->alloc_sem);
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cistatic int jffs2_reconfigure(struct fs_context *fc)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct super_block *sb = fc->root->d_sb;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	sync_filesystem(sb);
23762306a36Sopenharmony_ci	jffs2_update_mount_opts(fc);
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	return jffs2_do_remount_fs(sb, fc);
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_cistatic const struct super_operations jffs2_super_operations =
24362306a36Sopenharmony_ci{
24462306a36Sopenharmony_ci	.alloc_inode =	jffs2_alloc_inode,
24562306a36Sopenharmony_ci	.free_inode =	jffs2_free_inode,
24662306a36Sopenharmony_ci	.put_super =	jffs2_put_super,
24762306a36Sopenharmony_ci	.statfs =	jffs2_statfs,
24862306a36Sopenharmony_ci	.evict_inode =	jffs2_evict_inode,
24962306a36Sopenharmony_ci	.dirty_inode =	jffs2_dirty_inode,
25062306a36Sopenharmony_ci	.show_options =	jffs2_show_options,
25162306a36Sopenharmony_ci	.sync_fs =	jffs2_sync_fs,
25262306a36Sopenharmony_ci};
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci/*
25562306a36Sopenharmony_ci * fill in the superblock
25662306a36Sopenharmony_ci */
25762306a36Sopenharmony_cistatic int jffs2_fill_super(struct super_block *sb, struct fs_context *fc)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	struct jffs2_sb_info *c = sb->s_fs_info;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	jffs2_dbg(1, "jffs2_get_sb_mtd():"
26262306a36Sopenharmony_ci		  " New superblock for device %d (\"%s\")\n",
26362306a36Sopenharmony_ci		  sb->s_mtd->index, sb->s_mtd->name);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	c->mtd = sb->s_mtd;
26662306a36Sopenharmony_ci	c->os_priv = sb;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (c->mount_opts.rp_size > c->mtd->size)
26962306a36Sopenharmony_ci		return invalf(fc, "jffs2: Too large reserve pool specified, max is %llu KB",
27062306a36Sopenharmony_ci			      c->mtd->size / 1024);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* Initialize JFFS2 superblock locks, the further initialization will
27362306a36Sopenharmony_ci	 * be done later */
27462306a36Sopenharmony_ci	mutex_init(&c->alloc_sem);
27562306a36Sopenharmony_ci	mutex_init(&c->erase_free_sem);
27662306a36Sopenharmony_ci	init_waitqueue_head(&c->erase_wait);
27762306a36Sopenharmony_ci	init_waitqueue_head(&c->inocache_wq);
27862306a36Sopenharmony_ci	spin_lock_init(&c->erase_completion_lock);
27962306a36Sopenharmony_ci	spin_lock_init(&c->inocache_lock);
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	sb->s_op = &jffs2_super_operations;
28262306a36Sopenharmony_ci	sb->s_export_op = &jffs2_export_ops;
28362306a36Sopenharmony_ci	sb->s_flags = sb->s_flags | SB_NOATIME;
28462306a36Sopenharmony_ci	sb->s_xattr = jffs2_xattr_handlers;
28562306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_POSIX_ACL
28662306a36Sopenharmony_ci	sb->s_flags |= SB_POSIXACL;
28762306a36Sopenharmony_ci#endif
28862306a36Sopenharmony_ci	return jffs2_do_fill_super(sb, fc);
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic int jffs2_get_tree(struct fs_context *fc)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	return get_tree_mtd(fc, jffs2_fill_super);
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic void jffs2_free_fc(struct fs_context *fc)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	kfree(fc->s_fs_info);
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic const struct fs_context_operations jffs2_context_ops = {
30262306a36Sopenharmony_ci	.free		= jffs2_free_fc,
30362306a36Sopenharmony_ci	.parse_param	= jffs2_parse_param,
30462306a36Sopenharmony_ci	.get_tree	= jffs2_get_tree,
30562306a36Sopenharmony_ci	.reconfigure	= jffs2_reconfigure,
30662306a36Sopenharmony_ci};
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic int jffs2_init_fs_context(struct fs_context *fc)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct jffs2_sb_info *ctx;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	ctx = kzalloc(sizeof(struct jffs2_sb_info), GFP_KERNEL);
31362306a36Sopenharmony_ci	if (!ctx)
31462306a36Sopenharmony_ci		return -ENOMEM;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	fc->s_fs_info = ctx;
31762306a36Sopenharmony_ci	fc->ops = &jffs2_context_ops;
31862306a36Sopenharmony_ci	return 0;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic void jffs2_put_super (struct super_block *sb)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	jffs2_dbg(2, "%s()\n", __func__);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	mutex_lock(&c->alloc_sem);
32862306a36Sopenharmony_ci	jffs2_flush_wbuf_pad(c);
32962306a36Sopenharmony_ci	mutex_unlock(&c->alloc_sem);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	jffs2_sum_exit(c);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	jffs2_free_ino_caches(c);
33462306a36Sopenharmony_ci	jffs2_free_raw_node_refs(c);
33562306a36Sopenharmony_ci	kvfree(c->blocks);
33662306a36Sopenharmony_ci	jffs2_flash_cleanup(c);
33762306a36Sopenharmony_ci	kfree(c->inocache_list);
33862306a36Sopenharmony_ci	jffs2_clear_xattr_subsystem(c);
33962306a36Sopenharmony_ci	mtd_sync(c->mtd);
34062306a36Sopenharmony_ci	jffs2_dbg(1, "%s(): returning\n", __func__);
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic void jffs2_kill_sb(struct super_block *sb)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
34662306a36Sopenharmony_ci	if (c && !sb_rdonly(sb))
34762306a36Sopenharmony_ci		jffs2_stop_garbage_collect_thread(c);
34862306a36Sopenharmony_ci	kill_mtd_super(sb);
34962306a36Sopenharmony_ci	kfree(c);
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic struct file_system_type jffs2_fs_type = {
35362306a36Sopenharmony_ci	.owner =	THIS_MODULE,
35462306a36Sopenharmony_ci	.name =		"jffs2",
35562306a36Sopenharmony_ci	.init_fs_context = jffs2_init_fs_context,
35662306a36Sopenharmony_ci	.parameters =	jffs2_fs_parameters,
35762306a36Sopenharmony_ci	.kill_sb =	jffs2_kill_sb,
35862306a36Sopenharmony_ci};
35962306a36Sopenharmony_ciMODULE_ALIAS_FS("jffs2");
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic int __init init_jffs2_fs(void)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	int ret;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/* Paranoia checks for on-medium structures. If we ask GCC
36662306a36Sopenharmony_ci	   to pack them with __attribute__((packed)) then it _also_
36762306a36Sopenharmony_ci	   assumes that they're not aligned -- so it emits crappy
36862306a36Sopenharmony_ci	   code on some architectures. Ideally we want an attribute
36962306a36Sopenharmony_ci	   which means just 'no padding', without the alignment
37062306a36Sopenharmony_ci	   thing. But GCC doesn't have that -- we have to just
37162306a36Sopenharmony_ci	   hope the structs are the right sizes, instead. */
37262306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
37362306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
37462306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
37562306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	pr_info("version 2.2."
37862306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
37962306a36Sopenharmony_ci	       " (NAND)"
38062306a36Sopenharmony_ci#endif
38162306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_SUMMARY
38262306a36Sopenharmony_ci	       " (SUMMARY) "
38362306a36Sopenharmony_ci#endif
38462306a36Sopenharmony_ci	       " © 2001-2006 Red Hat, Inc.\n");
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
38762306a36Sopenharmony_ci					     sizeof(struct jffs2_inode_info),
38862306a36Sopenharmony_ci					     0, (SLAB_RECLAIM_ACCOUNT|
38962306a36Sopenharmony_ci						SLAB_MEM_SPREAD|SLAB_ACCOUNT),
39062306a36Sopenharmony_ci					     jffs2_i_init_once);
39162306a36Sopenharmony_ci	if (!jffs2_inode_cachep) {
39262306a36Sopenharmony_ci		pr_err("error: Failed to initialise inode cache\n");
39362306a36Sopenharmony_ci		return -ENOMEM;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci	ret = jffs2_compressors_init();
39662306a36Sopenharmony_ci	if (ret) {
39762306a36Sopenharmony_ci		pr_err("error: Failed to initialise compressors\n");
39862306a36Sopenharmony_ci		goto out;
39962306a36Sopenharmony_ci	}
40062306a36Sopenharmony_ci	ret = jffs2_create_slab_caches();
40162306a36Sopenharmony_ci	if (ret) {
40262306a36Sopenharmony_ci		pr_err("error: Failed to initialise slab caches\n");
40362306a36Sopenharmony_ci		goto out_compressors;
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci	ret = register_filesystem(&jffs2_fs_type);
40662306a36Sopenharmony_ci	if (ret) {
40762306a36Sopenharmony_ci		pr_err("error: Failed to register filesystem\n");
40862306a36Sopenharmony_ci		goto out_slab;
40962306a36Sopenharmony_ci	}
41062306a36Sopenharmony_ci	return 0;
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci out_slab:
41362306a36Sopenharmony_ci	jffs2_destroy_slab_caches();
41462306a36Sopenharmony_ci out_compressors:
41562306a36Sopenharmony_ci	jffs2_compressors_exit();
41662306a36Sopenharmony_ci out:
41762306a36Sopenharmony_ci	kmem_cache_destroy(jffs2_inode_cachep);
41862306a36Sopenharmony_ci	return ret;
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistatic void __exit exit_jffs2_fs(void)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	unregister_filesystem(&jffs2_fs_type);
42462306a36Sopenharmony_ci	jffs2_destroy_slab_caches();
42562306a36Sopenharmony_ci	jffs2_compressors_exit();
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	/*
42862306a36Sopenharmony_ci	 * Make sure all delayed rcu free inodes are flushed before we
42962306a36Sopenharmony_ci	 * destroy cache.
43062306a36Sopenharmony_ci	 */
43162306a36Sopenharmony_ci	rcu_barrier();
43262306a36Sopenharmony_ci	kmem_cache_destroy(jffs2_inode_cachep);
43362306a36Sopenharmony_ci}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cimodule_init(init_jffs2_fs);
43662306a36Sopenharmony_cimodule_exit(exit_jffs2_fs);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ciMODULE_DESCRIPTION("The Journalling Flash File System, v2");
43962306a36Sopenharmony_ciMODULE_AUTHOR("Red Hat, Inc.");
44062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
44162306a36Sopenharmony_ci		       // the sake of this tag. It's Free Software.
442