18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory.
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/list.h>
198c2ecf20Sopenharmony_ci#include <linux/fs.h>
208c2ecf20Sopenharmony_ci#include <linux/err.h>
218c2ecf20Sopenharmony_ci#include <linux/mount.h>
228c2ecf20Sopenharmony_ci#include <linux/fs_context.h>
238c2ecf20Sopenharmony_ci#include <linux/fs_parser.h>
248c2ecf20Sopenharmony_ci#include <linux/jffs2.h>
258c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
268c2ecf20Sopenharmony_ci#include <linux/mtd/super.h>
278c2ecf20Sopenharmony_ci#include <linux/ctype.h>
288c2ecf20Sopenharmony_ci#include <linux/namei.h>
298c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
308c2ecf20Sopenharmony_ci#include <linux/exportfs.h>
318c2ecf20Sopenharmony_ci#include "compr.h"
328c2ecf20Sopenharmony_ci#include "nodelist.h"
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic void jffs2_put_super(struct super_block *);
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic struct kmem_cache *jffs2_inode_cachep;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic struct inode *jffs2_alloc_inode(struct super_block *sb)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	struct jffs2_inode_info *f;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL);
438c2ecf20Sopenharmony_ci	if (!f)
448c2ecf20Sopenharmony_ci		return NULL;
458c2ecf20Sopenharmony_ci	return &f->vfs_inode;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic void jffs2_free_inode(struct inode *inode)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	kfree(f->target);
538c2ecf20Sopenharmony_ci	kmem_cache_free(jffs2_inode_cachep, f);
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic void jffs2_i_init_once(void *foo)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	struct jffs2_inode_info *f = foo;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	mutex_init(&f->sem);
618c2ecf20Sopenharmony_ci	f->target = NULL;
628c2ecf20Sopenharmony_ci	inode_init_once(&f->vfs_inode);
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic const char *jffs2_compr_name(unsigned int compr)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	switch (compr) {
688c2ecf20Sopenharmony_ci	case JFFS2_COMPR_MODE_NONE:
698c2ecf20Sopenharmony_ci		return "none";
708c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_LZO
718c2ecf20Sopenharmony_ci	case JFFS2_COMPR_MODE_FORCELZO:
728c2ecf20Sopenharmony_ci		return "lzo";
738c2ecf20Sopenharmony_ci#endif
748c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_ZLIB
758c2ecf20Sopenharmony_ci	case JFFS2_COMPR_MODE_FORCEZLIB:
768c2ecf20Sopenharmony_ci		return "zlib";
778c2ecf20Sopenharmony_ci#endif
788c2ecf20Sopenharmony_ci	default:
798c2ecf20Sopenharmony_ci		/* should never happen; programmer error */
808c2ecf20Sopenharmony_ci		WARN_ON(1);
818c2ecf20Sopenharmony_ci		return "";
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic int jffs2_show_options(struct seq_file *s, struct dentry *root)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c = JFFS2_SB_INFO(root->d_sb);
888c2ecf20Sopenharmony_ci	struct jffs2_mount_opts *opts = &c->mount_opts;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (opts->override_compr)
918c2ecf20Sopenharmony_ci		seq_printf(s, ",compr=%s", jffs2_compr_name(opts->compr));
928c2ecf20Sopenharmony_ci	if (opts->set_rp_size)
938c2ecf20Sopenharmony_ci		seq_printf(s, ",rp_size=%u", opts->rp_size / 1024);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	return 0;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic int jffs2_sync_fs(struct super_block *sb, int wait)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
1038c2ecf20Sopenharmony_ci	if (jffs2_is_writebuffered(c))
1048c2ecf20Sopenharmony_ci		cancel_delayed_work_sync(&c->wbuf_dwork);
1058c2ecf20Sopenharmony_ci#endif
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	mutex_lock(&c->alloc_sem);
1088c2ecf20Sopenharmony_ci	jffs2_flush_wbuf_pad(c);
1098c2ecf20Sopenharmony_ci	mutex_unlock(&c->alloc_sem);
1108c2ecf20Sopenharmony_ci	return 0;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
1148c2ecf20Sopenharmony_ci					 uint32_t generation)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	/* We don't care about i_generation. We'll destroy the flash
1178c2ecf20Sopenharmony_ci	   before we start re-using inode numbers anyway. And even
1188c2ecf20Sopenharmony_ci	   if that wasn't true, we'd have other problems...*/
1198c2ecf20Sopenharmony_ci	return jffs2_iget(sb, ino);
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
1238c2ecf20Sopenharmony_ci					 int fh_len, int fh_type)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci        return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
1268c2ecf20Sopenharmony_ci                                    jffs2_nfs_get_inode);
1278c2ecf20Sopenharmony_ci}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_cistatic struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid,
1308c2ecf20Sopenharmony_ci					 int fh_len, int fh_type)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci        return generic_fh_to_parent(sb, fid, fh_len, fh_type,
1338c2ecf20Sopenharmony_ci                                    jffs2_nfs_get_inode);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic struct dentry *jffs2_get_parent(struct dentry *child)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	struct jffs2_inode_info *f;
1398c2ecf20Sopenharmony_ci	uint32_t pino;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	BUG_ON(!d_is_dir(child));
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	f = JFFS2_INODE_INFO(d_inode(child));
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	pino = f->inocache->pino_nlink;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	JFFS2_DEBUG("Parent of directory ino #%u is #%u\n",
1488c2ecf20Sopenharmony_ci		    f->inocache->ino, pino);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return d_obtain_alias(jffs2_iget(child->d_sb, pino));
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic const struct export_operations jffs2_export_ops = {
1548c2ecf20Sopenharmony_ci	.get_parent = jffs2_get_parent,
1558c2ecf20Sopenharmony_ci	.fh_to_dentry = jffs2_fh_to_dentry,
1568c2ecf20Sopenharmony_ci	.fh_to_parent = jffs2_fh_to_parent,
1578c2ecf20Sopenharmony_ci};
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci/*
1608c2ecf20Sopenharmony_ci * JFFS2 mount options.
1618c2ecf20Sopenharmony_ci *
1628c2ecf20Sopenharmony_ci * Opt_source: The source device
1638c2ecf20Sopenharmony_ci * Opt_override_compr: override default compressor
1648c2ecf20Sopenharmony_ci * Opt_rp_size: size of reserved pool in KiB
1658c2ecf20Sopenharmony_ci */
1668c2ecf20Sopenharmony_cienum {
1678c2ecf20Sopenharmony_ci	Opt_override_compr,
1688c2ecf20Sopenharmony_ci	Opt_rp_size,
1698c2ecf20Sopenharmony_ci};
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic const struct constant_table jffs2_param_compr[] = {
1728c2ecf20Sopenharmony_ci	{"none",	JFFS2_COMPR_MODE_NONE },
1738c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_LZO
1748c2ecf20Sopenharmony_ci	{"lzo",		JFFS2_COMPR_MODE_FORCELZO },
1758c2ecf20Sopenharmony_ci#endif
1768c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_ZLIB
1778c2ecf20Sopenharmony_ci	{"zlib",	JFFS2_COMPR_MODE_FORCEZLIB },
1788c2ecf20Sopenharmony_ci#endif
1798c2ecf20Sopenharmony_ci	{}
1808c2ecf20Sopenharmony_ci};
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic const struct fs_parameter_spec jffs2_fs_parameters[] = {
1838c2ecf20Sopenharmony_ci	fsparam_enum	("compr",	Opt_override_compr, jffs2_param_compr),
1848c2ecf20Sopenharmony_ci	fsparam_u32	("rp_size",	Opt_rp_size),
1858c2ecf20Sopenharmony_ci	{}
1868c2ecf20Sopenharmony_ci};
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic int jffs2_parse_param(struct fs_context *fc, struct fs_parameter *param)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	struct fs_parse_result result;
1918c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c = fc->s_fs_info;
1928c2ecf20Sopenharmony_ci	int opt;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	opt = fs_parse(fc, jffs2_fs_parameters, param, &result);
1958c2ecf20Sopenharmony_ci	if (opt < 0)
1968c2ecf20Sopenharmony_ci		return opt;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	switch (opt) {
1998c2ecf20Sopenharmony_ci	case Opt_override_compr:
2008c2ecf20Sopenharmony_ci		c->mount_opts.compr = result.uint_32;
2018c2ecf20Sopenharmony_ci		c->mount_opts.override_compr = true;
2028c2ecf20Sopenharmony_ci		break;
2038c2ecf20Sopenharmony_ci	case Opt_rp_size:
2048c2ecf20Sopenharmony_ci		if (result.uint_32 > UINT_MAX / 1024)
2058c2ecf20Sopenharmony_ci			return invalf(fc, "jffs2: rp_size unrepresentable");
2068c2ecf20Sopenharmony_ci		c->mount_opts.rp_size = result.uint_32 * 1024;
2078c2ecf20Sopenharmony_ci		c->mount_opts.set_rp_size = true;
2088c2ecf20Sopenharmony_ci		break;
2098c2ecf20Sopenharmony_ci	default:
2108c2ecf20Sopenharmony_ci		return -EINVAL;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	return 0;
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic inline void jffs2_update_mount_opts(struct fs_context *fc)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	struct jffs2_sb_info *new_c = fc->s_fs_info;
2198c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c = JFFS2_SB_INFO(fc->root->d_sb);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	mutex_lock(&c->alloc_sem);
2228c2ecf20Sopenharmony_ci	if (new_c->mount_opts.override_compr) {
2238c2ecf20Sopenharmony_ci		c->mount_opts.override_compr = new_c->mount_opts.override_compr;
2248c2ecf20Sopenharmony_ci		c->mount_opts.compr = new_c->mount_opts.compr;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci	if (new_c->mount_opts.set_rp_size) {
2278c2ecf20Sopenharmony_ci		c->mount_opts.set_rp_size = new_c->mount_opts.set_rp_size;
2288c2ecf20Sopenharmony_ci		c->mount_opts.rp_size = new_c->mount_opts.rp_size;
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci	mutex_unlock(&c->alloc_sem);
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic int jffs2_reconfigure(struct fs_context *fc)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct super_block *sb = fc->root->d_sb;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	sync_filesystem(sb);
2388c2ecf20Sopenharmony_ci	jffs2_update_mount_opts(fc);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return jffs2_do_remount_fs(sb, fc);
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic const struct super_operations jffs2_super_operations =
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	.alloc_inode =	jffs2_alloc_inode,
2468c2ecf20Sopenharmony_ci	.free_inode =	jffs2_free_inode,
2478c2ecf20Sopenharmony_ci	.put_super =	jffs2_put_super,
2488c2ecf20Sopenharmony_ci	.statfs =	jffs2_statfs,
2498c2ecf20Sopenharmony_ci	.evict_inode =	jffs2_evict_inode,
2508c2ecf20Sopenharmony_ci	.dirty_inode =	jffs2_dirty_inode,
2518c2ecf20Sopenharmony_ci	.show_options =	jffs2_show_options,
2528c2ecf20Sopenharmony_ci	.sync_fs =	jffs2_sync_fs,
2538c2ecf20Sopenharmony_ci};
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/*
2568c2ecf20Sopenharmony_ci * fill in the superblock
2578c2ecf20Sopenharmony_ci */
2588c2ecf20Sopenharmony_cistatic int jffs2_fill_super(struct super_block *sb, struct fs_context *fc)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c = sb->s_fs_info;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	jffs2_dbg(1, "jffs2_get_sb_mtd():"
2638c2ecf20Sopenharmony_ci		  " New superblock for device %d (\"%s\")\n",
2648c2ecf20Sopenharmony_ci		  sb->s_mtd->index, sb->s_mtd->name);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	c->mtd = sb->s_mtd;
2678c2ecf20Sopenharmony_ci	c->os_priv = sb;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	if (c->mount_opts.rp_size > c->mtd->size)
2708c2ecf20Sopenharmony_ci		return invalf(fc, "jffs2: Too large reserve pool specified, max is %llu KB",
2718c2ecf20Sopenharmony_ci			      c->mtd->size / 1024);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	/* Initialize JFFS2 superblock locks, the further initialization will
2748c2ecf20Sopenharmony_ci	 * be done later */
2758c2ecf20Sopenharmony_ci	mutex_init(&c->alloc_sem);
2768c2ecf20Sopenharmony_ci	mutex_init(&c->erase_free_sem);
2778c2ecf20Sopenharmony_ci	init_waitqueue_head(&c->erase_wait);
2788c2ecf20Sopenharmony_ci	init_waitqueue_head(&c->inocache_wq);
2798c2ecf20Sopenharmony_ci	spin_lock_init(&c->erase_completion_lock);
2808c2ecf20Sopenharmony_ci	spin_lock_init(&c->inocache_lock);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	sb->s_op = &jffs2_super_operations;
2838c2ecf20Sopenharmony_ci	sb->s_export_op = &jffs2_export_ops;
2848c2ecf20Sopenharmony_ci	sb->s_flags = sb->s_flags | SB_NOATIME;
2858c2ecf20Sopenharmony_ci	sb->s_xattr = jffs2_xattr_handlers;
2868c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_POSIX_ACL
2878c2ecf20Sopenharmony_ci	sb->s_flags |= SB_POSIXACL;
2888c2ecf20Sopenharmony_ci#endif
2898c2ecf20Sopenharmony_ci	return jffs2_do_fill_super(sb, fc);
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic int jffs2_get_tree(struct fs_context *fc)
2938c2ecf20Sopenharmony_ci{
2948c2ecf20Sopenharmony_ci	return get_tree_mtd(fc, jffs2_fill_super);
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic void jffs2_free_fc(struct fs_context *fc)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	kfree(fc->s_fs_info);
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic const struct fs_context_operations jffs2_context_ops = {
3038c2ecf20Sopenharmony_ci	.free		= jffs2_free_fc,
3048c2ecf20Sopenharmony_ci	.parse_param	= jffs2_parse_param,
3058c2ecf20Sopenharmony_ci	.get_tree	= jffs2_get_tree,
3068c2ecf20Sopenharmony_ci	.reconfigure	= jffs2_reconfigure,
3078c2ecf20Sopenharmony_ci};
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic int jffs2_init_fs_context(struct fs_context *fc)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	struct jffs2_sb_info *ctx;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	ctx = kzalloc(sizeof(struct jffs2_sb_info), GFP_KERNEL);
3148c2ecf20Sopenharmony_ci	if (!ctx)
3158c2ecf20Sopenharmony_ci		return -ENOMEM;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	fc->s_fs_info = ctx;
3188c2ecf20Sopenharmony_ci	fc->ops = &jffs2_context_ops;
3198c2ecf20Sopenharmony_ci	return 0;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic void jffs2_put_super (struct super_block *sb)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	jffs2_dbg(2, "%s()\n", __func__);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	mutex_lock(&c->alloc_sem);
3298c2ecf20Sopenharmony_ci	jffs2_flush_wbuf_pad(c);
3308c2ecf20Sopenharmony_ci	mutex_unlock(&c->alloc_sem);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	jffs2_sum_exit(c);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	jffs2_free_ino_caches(c);
3358c2ecf20Sopenharmony_ci	jffs2_free_raw_node_refs(c);
3368c2ecf20Sopenharmony_ci	kvfree(c->blocks);
3378c2ecf20Sopenharmony_ci	jffs2_flash_cleanup(c);
3388c2ecf20Sopenharmony_ci	kfree(c->inocache_list);
3398c2ecf20Sopenharmony_ci	jffs2_clear_xattr_subsystem(c);
3408c2ecf20Sopenharmony_ci	mtd_sync(c->mtd);
3418c2ecf20Sopenharmony_ci	jffs2_dbg(1, "%s(): returning\n", __func__);
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic void jffs2_kill_sb(struct super_block *sb)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
3478c2ecf20Sopenharmony_ci	if (c && !sb_rdonly(sb))
3488c2ecf20Sopenharmony_ci		jffs2_stop_garbage_collect_thread(c);
3498c2ecf20Sopenharmony_ci	kill_mtd_super(sb);
3508c2ecf20Sopenharmony_ci	kfree(c);
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic struct file_system_type jffs2_fs_type = {
3548c2ecf20Sopenharmony_ci	.owner =	THIS_MODULE,
3558c2ecf20Sopenharmony_ci	.name =		"jffs2",
3568c2ecf20Sopenharmony_ci	.init_fs_context = jffs2_init_fs_context,
3578c2ecf20Sopenharmony_ci	.parameters =	jffs2_fs_parameters,
3588c2ecf20Sopenharmony_ci	.kill_sb =	jffs2_kill_sb,
3598c2ecf20Sopenharmony_ci};
3608c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("jffs2");
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic int __init init_jffs2_fs(void)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	int ret;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	/* Paranoia checks for on-medium structures. If we ask GCC
3678c2ecf20Sopenharmony_ci	   to pack them with __attribute__((packed)) then it _also_
3688c2ecf20Sopenharmony_ci	   assumes that they're not aligned -- so it emits crappy
3698c2ecf20Sopenharmony_ci	   code on some architectures. Ideally we want an attribute
3708c2ecf20Sopenharmony_ci	   which means just 'no padding', without the alignment
3718c2ecf20Sopenharmony_ci	   thing. But GCC doesn't have that -- we have to just
3728c2ecf20Sopenharmony_ci	   hope the structs are the right sizes, instead. */
3738c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
3748c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
3758c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
3768c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	pr_info("version 2.2."
3798c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
3808c2ecf20Sopenharmony_ci	       " (NAND)"
3818c2ecf20Sopenharmony_ci#endif
3828c2ecf20Sopenharmony_ci#ifdef CONFIG_JFFS2_SUMMARY
3838c2ecf20Sopenharmony_ci	       " (SUMMARY) "
3848c2ecf20Sopenharmony_ci#endif
3858c2ecf20Sopenharmony_ci	       " © 2001-2006 Red Hat, Inc.\n");
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
3888c2ecf20Sopenharmony_ci					     sizeof(struct jffs2_inode_info),
3898c2ecf20Sopenharmony_ci					     0, (SLAB_RECLAIM_ACCOUNT|
3908c2ecf20Sopenharmony_ci						SLAB_MEM_SPREAD|SLAB_ACCOUNT),
3918c2ecf20Sopenharmony_ci					     jffs2_i_init_once);
3928c2ecf20Sopenharmony_ci	if (!jffs2_inode_cachep) {
3938c2ecf20Sopenharmony_ci		pr_err("error: Failed to initialise inode cache\n");
3948c2ecf20Sopenharmony_ci		return -ENOMEM;
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci	ret = jffs2_compressors_init();
3978c2ecf20Sopenharmony_ci	if (ret) {
3988c2ecf20Sopenharmony_ci		pr_err("error: Failed to initialise compressors\n");
3998c2ecf20Sopenharmony_ci		goto out;
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci	ret = jffs2_create_slab_caches();
4028c2ecf20Sopenharmony_ci	if (ret) {
4038c2ecf20Sopenharmony_ci		pr_err("error: Failed to initialise slab caches\n");
4048c2ecf20Sopenharmony_ci		goto out_compressors;
4058c2ecf20Sopenharmony_ci	}
4068c2ecf20Sopenharmony_ci	ret = register_filesystem(&jffs2_fs_type);
4078c2ecf20Sopenharmony_ci	if (ret) {
4088c2ecf20Sopenharmony_ci		pr_err("error: Failed to register filesystem\n");
4098c2ecf20Sopenharmony_ci		goto out_slab;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci	return 0;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci out_slab:
4148c2ecf20Sopenharmony_ci	jffs2_destroy_slab_caches();
4158c2ecf20Sopenharmony_ci out_compressors:
4168c2ecf20Sopenharmony_ci	jffs2_compressors_exit();
4178c2ecf20Sopenharmony_ci out:
4188c2ecf20Sopenharmony_ci	kmem_cache_destroy(jffs2_inode_cachep);
4198c2ecf20Sopenharmony_ci	return ret;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic void __exit exit_jffs2_fs(void)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	unregister_filesystem(&jffs2_fs_type);
4258c2ecf20Sopenharmony_ci	jffs2_destroy_slab_caches();
4268c2ecf20Sopenharmony_ci	jffs2_compressors_exit();
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	/*
4298c2ecf20Sopenharmony_ci	 * Make sure all delayed rcu free inodes are flushed before we
4308c2ecf20Sopenharmony_ci	 * destroy cache.
4318c2ecf20Sopenharmony_ci	 */
4328c2ecf20Sopenharmony_ci	rcu_barrier();
4338c2ecf20Sopenharmony_ci	kmem_cache_destroy(jffs2_inode_cachep);
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cimodule_init(init_jffs2_fs);
4378c2ecf20Sopenharmony_cimodule_exit(exit_jffs2_fs);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("The Journalling Flash File System, v2");
4408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Red Hat, Inc.");
4418c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
4428c2ecf20Sopenharmony_ci		       // the sake of this tag. It's Free Software.
443