xref: /openbmc/linux/fs/jffs2/super.c (revision 9c74034f)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * JFFS2 -- Journalling Flash File System, Version 2.
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (C) 2001-2003 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  *
10182ec4eeSThomas Gleixner  * $Id: super.c,v 1.110 2005/11/07 11:14:42 gleixner Exp $
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
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>
221da177e4SLinus Torvalds #include <linux/jffs2.h>
231da177e4SLinus Torvalds #include <linux/pagemap.h>
241da177e4SLinus Torvalds #include <linux/mtd/mtd.h>
251da177e4SLinus Torvalds #include <linux/ctype.h>
261da177e4SLinus Torvalds #include <linux/namei.h>
271da177e4SLinus Torvalds #include "compr.h"
281da177e4SLinus Torvalds #include "nodelist.h"
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds static void jffs2_put_super(struct super_block *);
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds static kmem_cache_t *jffs2_inode_cachep;
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds static struct inode *jffs2_alloc_inode(struct super_block *sb)
351da177e4SLinus Torvalds {
361da177e4SLinus Torvalds 	struct jffs2_inode_info *ei;
371da177e4SLinus Torvalds 	ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, SLAB_KERNEL);
381da177e4SLinus Torvalds 	if (!ei)
391da177e4SLinus Torvalds 		return NULL;
401da177e4SLinus Torvalds 	return &ei->vfs_inode;
411da177e4SLinus Torvalds }
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds static void jffs2_destroy_inode(struct inode *inode)
441da177e4SLinus Torvalds {
451da177e4SLinus Torvalds 	kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode));
461da177e4SLinus Torvalds }
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds static void jffs2_i_init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
491da177e4SLinus Torvalds {
501da177e4SLinus Torvalds 	struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo;
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
531da177e4SLinus Torvalds 	    SLAB_CTOR_CONSTRUCTOR) {
5421eeb7aaSThomas Gleixner 		init_MUTEX(&ei->sem);
551da177e4SLinus Torvalds 		inode_init_once(&ei->vfs_inode);
561da177e4SLinus Torvalds 	}
571da177e4SLinus Torvalds }
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds static int jffs2_sync_fs(struct super_block *sb, int wait)
601da177e4SLinus Torvalds {
611da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds 	down(&c->alloc_sem);
641da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
651da177e4SLinus Torvalds 	up(&c->alloc_sem);
661da177e4SLinus Torvalds 	return 0;
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds 
691da177e4SLinus Torvalds static struct super_operations jffs2_super_operations =
701da177e4SLinus Torvalds {
711da177e4SLinus Torvalds 	.alloc_inode =	jffs2_alloc_inode,
721da177e4SLinus Torvalds 	.destroy_inode =jffs2_destroy_inode,
731da177e4SLinus Torvalds 	.read_inode =	jffs2_read_inode,
741da177e4SLinus Torvalds 	.put_super =	jffs2_put_super,
751da177e4SLinus Torvalds 	.write_super =	jffs2_write_super,
761da177e4SLinus Torvalds 	.statfs =	jffs2_statfs,
771da177e4SLinus Torvalds 	.remount_fs =	jffs2_remount_fs,
781da177e4SLinus Torvalds 	.clear_inode =	jffs2_clear_inode,
791da177e4SLinus Torvalds 	.dirty_inode =	jffs2_dirty_inode,
801da177e4SLinus Torvalds 	.sync_fs =	jffs2_sync_fs,
811da177e4SLinus Torvalds };
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds static int jffs2_sb_compare(struct super_block *sb, void *data)
841da177e4SLinus Torvalds {
851da177e4SLinus Torvalds 	struct jffs2_sb_info *p = data;
861da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
871da177e4SLinus Torvalds 
881da177e4SLinus Torvalds 	/* The superblocks are considered to be equivalent if the underlying MTD
891da177e4SLinus Torvalds 	   device is the same one */
901da177e4SLinus Torvalds 	if (c->mtd == p->mtd) {
911da177e4SLinus Torvalds 		D1(printk(KERN_DEBUG "jffs2_sb_compare: match on device %d (\"%s\")\n", p->mtd->index, p->mtd->name));
921da177e4SLinus Torvalds 		return 1;
931da177e4SLinus Torvalds 	} else {
941da177e4SLinus Torvalds 		D1(printk(KERN_DEBUG "jffs2_sb_compare: No match, device %d (\"%s\"), device %d (\"%s\")\n",
951da177e4SLinus Torvalds 			  c->mtd->index, c->mtd->name, p->mtd->index, p->mtd->name));
961da177e4SLinus Torvalds 		return 0;
971da177e4SLinus Torvalds 	}
981da177e4SLinus Torvalds }
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds static int jffs2_sb_set(struct super_block *sb, void *data)
1011da177e4SLinus Torvalds {
1021da177e4SLinus Torvalds 	struct jffs2_sb_info *p = data;
1031da177e4SLinus Torvalds 
1041da177e4SLinus Torvalds 	/* For persistence of NFS exports etc. we use the same s_dev
1051da177e4SLinus Torvalds 	   each time we mount the device, don't just use an anonymous
1061da177e4SLinus Torvalds 	   device */
1071da177e4SLinus Torvalds 	sb->s_fs_info = p;
1081da177e4SLinus Torvalds 	p->os_priv = sb;
1091da177e4SLinus Torvalds 	sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, p->mtd->index);
1101da177e4SLinus Torvalds 
1111da177e4SLinus Torvalds 	return 0;
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds 
114454e2398SDavid Howells static int jffs2_get_sb_mtd(struct file_system_type *fs_type,
1151da177e4SLinus Torvalds 			    int flags, const char *dev_name,
116454e2398SDavid Howells 			    void *data, struct mtd_info *mtd,
117454e2398SDavid Howells 			    struct vfsmount *mnt)
1181da177e4SLinus Torvalds {
1191da177e4SLinus Torvalds 	struct super_block *sb;
1201da177e4SLinus Torvalds 	struct jffs2_sb_info *c;
1211da177e4SLinus Torvalds 	int ret;
1221da177e4SLinus Torvalds 
123f8314dc6SPanagiotis Issaris 	c = kzalloc(sizeof(*c), GFP_KERNEL);
1241da177e4SLinus Torvalds 	if (!c)
125454e2398SDavid Howells 		return -ENOMEM;
1261da177e4SLinus Torvalds 	c->mtd = mtd;
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds 	sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, c);
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 	if (IS_ERR(sb))
131454e2398SDavid Howells 		goto out_error;
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds 	if (sb->s_root) {
1341da177e4SLinus Torvalds 		/* New mountpoint for JFFS2 which is already mounted */
1351da177e4SLinus Torvalds 		D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): Device %d (\"%s\") is already mounted\n",
1361da177e4SLinus Torvalds 			  mtd->index, mtd->name));
137454e2398SDavid Howells 		ret = simple_set_mnt(mnt, sb);
1381da177e4SLinus Torvalds 		goto out_put;
1391da177e4SLinus Torvalds 	}
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 	D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): New superblock for device %d (\"%s\")\n",
1421da177e4SLinus Torvalds 		  mtd->index, mtd->name));
1431da177e4SLinus Torvalds 
144b6220598SArtem B. Bityuckiy 	/* Initialize JFFS2 superblock locks, the further initialization will be
145b6220598SArtem B. Bityuckiy 	 * done later */
146b6220598SArtem B. Bityuckiy 	init_MUTEX(&c->alloc_sem);
147b6220598SArtem B. Bityuckiy 	init_MUTEX(&c->erase_free_sem);
148b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->erase_wait);
149b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->inocache_wq);
150b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->erase_completion_lock);
151b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->inocache_lock);
152b6220598SArtem B. Bityuckiy 
1531da177e4SLinus Torvalds 	sb->s_op = &jffs2_super_operations;
1541da177e4SLinus Torvalds 	sb->s_flags = flags | MS_NOATIME;
155aa98d7cfSKaiGai Kohei 	sb->s_xattr = jffs2_xattr_handlers;
156aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL
157aa98d7cfSKaiGai Kohei 	sb->s_flags |= MS_POSIXACL;
158aa98d7cfSKaiGai Kohei #endif
1599b04c997STheodore Ts'o 	ret = jffs2_do_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds 	if (ret) {
1621da177e4SLinus Torvalds 		/* Failure case... */
1631da177e4SLinus Torvalds 		up_write(&sb->s_umount);
1641da177e4SLinus Torvalds 		deactivate_super(sb);
165454e2398SDavid Howells 		return ret;
1661da177e4SLinus Torvalds 	}
1671da177e4SLinus Torvalds 
1681da177e4SLinus Torvalds 	sb->s_flags |= MS_ACTIVE;
169454e2398SDavid Howells 	return simple_set_mnt(mnt, sb);
1701da177e4SLinus Torvalds 
171454e2398SDavid Howells out_error:
172454e2398SDavid Howells 	ret = PTR_ERR(sb);
1731da177e4SLinus Torvalds  out_put:
1741da177e4SLinus Torvalds 	kfree(c);
1751da177e4SLinus Torvalds 	put_mtd_device(mtd);
1761da177e4SLinus Torvalds 
177454e2398SDavid Howells 	return ret;
1781da177e4SLinus Torvalds }
1791da177e4SLinus Torvalds 
180454e2398SDavid Howells static int jffs2_get_sb_mtdnr(struct file_system_type *fs_type,
1811da177e4SLinus Torvalds 			      int flags, const char *dev_name,
182454e2398SDavid Howells 			      void *data, int mtdnr,
183454e2398SDavid Howells 			      struct vfsmount *mnt)
1841da177e4SLinus Torvalds {
1851da177e4SLinus Torvalds 	struct mtd_info *mtd;
1861da177e4SLinus Torvalds 
1871da177e4SLinus Torvalds 	mtd = get_mtd_device(NULL, mtdnr);
1889c74034fSArtem Bityutskiy 	if (IS_ERR(mtd)) {
1891da177e4SLinus Torvalds 		D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr));
1909c74034fSArtem Bityutskiy 		return PTR_ERR(mtd);
1911da177e4SLinus Torvalds 	}
1921da177e4SLinus Torvalds 
193454e2398SDavid Howells 	return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt);
1941da177e4SLinus Torvalds }
1951da177e4SLinus Torvalds 
196454e2398SDavid Howells static int jffs2_get_sb(struct file_system_type *fs_type,
1971da177e4SLinus Torvalds 			int flags, const char *dev_name,
198454e2398SDavid Howells 			void *data, struct vfsmount *mnt)
1991da177e4SLinus Torvalds {
2001da177e4SLinus Torvalds 	int err;
2011da177e4SLinus Torvalds 	struct nameidata nd;
2021da177e4SLinus Torvalds 	int mtdnr;
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds 	if (!dev_name)
205454e2398SDavid Howells 		return -EINVAL;
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds 	D1(printk(KERN_DEBUG "jffs2_get_sb(): dev_name \"%s\"\n", dev_name));
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds 	/* The preferred way of mounting in future; especially when
2101da177e4SLinus Torvalds 	   CONFIG_BLK_DEV is implemented - we specify the underlying
2111da177e4SLinus Torvalds 	   MTD device by number or by name, so that we don't require
2121da177e4SLinus Torvalds 	   block device support to be present in the kernel. */
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds 	/* FIXME: How to do the root fs this way? */
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds 	if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') {
2171da177e4SLinus Torvalds 		/* Probably mounting without the blkdev crap */
2181da177e4SLinus Torvalds 		if (dev_name[3] == ':') {
2191da177e4SLinus Torvalds 			struct mtd_info *mtd;
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 			/* Mount by MTD device name */
2221da177e4SLinus Torvalds 			D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd:%%s, name \"%s\"\n", dev_name+4));
2231da177e4SLinus Torvalds 			for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) {
2241da177e4SLinus Torvalds 				mtd = get_mtd_device(NULL, mtdnr);
2259c74034fSArtem Bityutskiy 				if (!IS_ERR(mtd)) {
2261da177e4SLinus Torvalds 					if (!strcmp(mtd->name, dev_name+4))
227454e2398SDavid Howells 						return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd, mnt);
2281da177e4SLinus Torvalds 					put_mtd_device(mtd);
2291da177e4SLinus Torvalds 				}
2301da177e4SLinus Torvalds 			}
2311da177e4SLinus Torvalds 			printk(KERN_NOTICE "jffs2_get_sb(): MTD device with name \"%s\" not found.\n", dev_name+4);
2321da177e4SLinus Torvalds 		} else if (isdigit(dev_name[3])) {
2331da177e4SLinus Torvalds 			/* Mount by MTD device number name */
2341da177e4SLinus Torvalds 			char *endptr;
2351da177e4SLinus Torvalds 
2361da177e4SLinus Torvalds 			mtdnr = simple_strtoul(dev_name+3, &endptr, 0);
2371da177e4SLinus Torvalds 			if (!*endptr) {
2381da177e4SLinus Torvalds 				/* It was a valid number */
2391da177e4SLinus Torvalds 				D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd%%d, mtdnr %d\n", mtdnr));
240454e2398SDavid Howells 				return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt);
2411da177e4SLinus Torvalds 			}
2421da177e4SLinus Torvalds 		}
2431da177e4SLinus Torvalds 	}
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds 	/* Try the old way - the hack where we allowed users to mount
2461da177e4SLinus Torvalds 	   /dev/mtdblock$(n) but didn't actually _use_ the blkdev */
2471da177e4SLinus Torvalds 
2481da177e4SLinus Torvalds 	err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
2491da177e4SLinus Torvalds 
2501da177e4SLinus Torvalds 	D1(printk(KERN_DEBUG "jffs2_get_sb(): path_lookup() returned %d, inode %p\n",
2511da177e4SLinus Torvalds 		  err, nd.dentry->d_inode));
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds 	if (err)
254454e2398SDavid Howells 		return err;
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	err = -EINVAL;
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	if (!S_ISBLK(nd.dentry->d_inode->i_mode))
2591da177e4SLinus Torvalds 		goto out;
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds 	if (nd.mnt->mnt_flags & MNT_NODEV) {
2621da177e4SLinus Torvalds 		err = -EACCES;
2631da177e4SLinus Torvalds 		goto out;
2641da177e4SLinus Torvalds 	}
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds 	if (imajor(nd.dentry->d_inode) != MTD_BLOCK_MAJOR) {
2679b04c997STheodore Ts'o 		if (!(flags & MS_SILENT))
2681da177e4SLinus Torvalds 			printk(KERN_NOTICE "Attempt to mount non-MTD device \"%s\" as JFFS2\n",
2691da177e4SLinus Torvalds 			       dev_name);
2701da177e4SLinus Torvalds 		goto out;
2711da177e4SLinus Torvalds 	}
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds 	mtdnr = iminor(nd.dentry->d_inode);
2741da177e4SLinus Torvalds 	path_release(&nd);
2751da177e4SLinus Torvalds 
276454e2398SDavid Howells 	return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr, mnt);
2771da177e4SLinus Torvalds 
2781da177e4SLinus Torvalds out:
2791da177e4SLinus Torvalds 	path_release(&nd);
280454e2398SDavid Howells 	return err;
2811da177e4SLinus Torvalds }
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds static void jffs2_put_super (struct super_block *sb)
2841da177e4SLinus Torvalds {
2851da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds 	down(&c->alloc_sem);
2901da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
2911da177e4SLinus Torvalds 	up(&c->alloc_sem);
292e631ddbaSFerenc Havasi 
293e631ddbaSFerenc Havasi 	jffs2_sum_exit(c);
294e631ddbaSFerenc Havasi 
2951da177e4SLinus Torvalds 	jffs2_free_ino_caches(c);
2961da177e4SLinus Torvalds 	jffs2_free_raw_node_refs(c);
2974ce1f562SFerenc Havasi 	if (jffs2_blocks_use_vmalloc(c))
2981da177e4SLinus Torvalds 		vfree(c->blocks);
2991da177e4SLinus Torvalds 	else
3001da177e4SLinus Torvalds 		kfree(c->blocks);
3011da177e4SLinus Torvalds 	jffs2_flash_cleanup(c);
3021da177e4SLinus Torvalds 	kfree(c->inocache_list);
303aa98d7cfSKaiGai Kohei 	jffs2_clear_xattr_subsystem(c);
3041da177e4SLinus Torvalds 	if (c->mtd->sync)
3051da177e4SLinus Torvalds 		c->mtd->sync(c->mtd);
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds 	D1(printk(KERN_DEBUG "jffs2_put_super returning\n"));
3081da177e4SLinus Torvalds }
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds static void jffs2_kill_sb(struct super_block *sb)
3111da177e4SLinus Torvalds {
3121da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
313a69dde91SArtem B. Bityuckiy 	if (!(sb->s_flags & MS_RDONLY))
314a69dde91SArtem B. Bityuckiy 		jffs2_stop_garbage_collect_thread(c);
3151da177e4SLinus Torvalds 	generic_shutdown_super(sb);
3161da177e4SLinus Torvalds 	put_mtd_device(c->mtd);
3171da177e4SLinus Torvalds 	kfree(c);
3181da177e4SLinus Torvalds }
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds static struct file_system_type jffs2_fs_type = {
3211da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
3221da177e4SLinus Torvalds 	.name =		"jffs2",
3231da177e4SLinus Torvalds 	.get_sb =	jffs2_get_sb,
3241da177e4SLinus Torvalds 	.kill_sb =	jffs2_kill_sb,
3251da177e4SLinus Torvalds };
3261da177e4SLinus Torvalds 
3271da177e4SLinus Torvalds static int __init init_jffs2_fs(void)
3281da177e4SLinus Torvalds {
3291da177e4SLinus Torvalds 	int ret;
3301da177e4SLinus Torvalds 
3313e68fbb5SDavid Woodhouse 	/* Paranoia checks for on-medium structures. If we ask GCC
3323e68fbb5SDavid Woodhouse 	   to pack them with __attribute__((packed)) then it _also_
3333e68fbb5SDavid Woodhouse 	   assumes that they're not aligned -- so it emits crappy
3343e68fbb5SDavid Woodhouse 	   code on some architectures. Ideally we want an attribute
3353e68fbb5SDavid Woodhouse 	   which means just 'no padding', without the alignment
3363e68fbb5SDavid Woodhouse 	   thing. But GCC doesn't have that -- we have to just
3373e68fbb5SDavid Woodhouse 	   hope the structs are the right sizes, instead. */
3382ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
3392ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
3402ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
3412ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
3423e68fbb5SDavid Woodhouse 
3431da177e4SLinus Torvalds 	printk(KERN_INFO "JFFS2 version 2.2."
3442f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
3451da177e4SLinus Torvalds 	       " (NAND)"
3461da177e4SLinus Torvalds #endif
347e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY
348e631ddbaSFerenc Havasi 	       " (SUMMARY) "
349e631ddbaSFerenc Havasi #endif
3503e68fbb5SDavid Woodhouse 	       " (C) 2001-2006 Red Hat, Inc.\n");
3511da177e4SLinus Torvalds 
3521da177e4SLinus Torvalds 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
3531da177e4SLinus Torvalds 					     sizeof(struct jffs2_inode_info),
354fffb60f9SPaul Jackson 					     0, (SLAB_RECLAIM_ACCOUNT|
355fffb60f9SPaul Jackson 						SLAB_MEM_SPREAD),
3561da177e4SLinus Torvalds 					     jffs2_i_init_once, NULL);
3571da177e4SLinus Torvalds 	if (!jffs2_inode_cachep) {
3581da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
3591da177e4SLinus Torvalds 		return -ENOMEM;
3601da177e4SLinus Torvalds 	}
3611da177e4SLinus Torvalds 	ret = jffs2_compressors_init();
3621da177e4SLinus Torvalds 	if (ret) {
3631da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
3641da177e4SLinus Torvalds 		goto out;
3651da177e4SLinus Torvalds 	}
3661da177e4SLinus Torvalds 	ret = jffs2_create_slab_caches();
3671da177e4SLinus Torvalds 	if (ret) {
3681da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
3691da177e4SLinus Torvalds 		goto out_compressors;
3701da177e4SLinus Torvalds 	}
3711da177e4SLinus Torvalds 	ret = register_filesystem(&jffs2_fs_type);
3721da177e4SLinus Torvalds 	if (ret) {
3731da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n");
3741da177e4SLinus Torvalds 		goto out_slab;
3751da177e4SLinus Torvalds 	}
3761da177e4SLinus Torvalds 	return 0;
3771da177e4SLinus Torvalds 
3781da177e4SLinus Torvalds  out_slab:
3791da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
3801da177e4SLinus Torvalds  out_compressors:
3811da177e4SLinus Torvalds 	jffs2_compressors_exit();
3821da177e4SLinus Torvalds  out:
3831da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
3841da177e4SLinus Torvalds 	return ret;
3851da177e4SLinus Torvalds }
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void)
3881da177e4SLinus Torvalds {
3891da177e4SLinus Torvalds 	unregister_filesystem(&jffs2_fs_type);
3901da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
3911da177e4SLinus Torvalds 	jffs2_compressors_exit();
3921da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
3931da177e4SLinus Torvalds }
3941da177e4SLinus Torvalds 
3951da177e4SLinus Torvalds module_init(init_jffs2_fs);
3961da177e4SLinus Torvalds module_exit(exit_jffs2_fs);
3971da177e4SLinus Torvalds 
3981da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journalling Flash File System, v2");
3991da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc.");
4001da177e4SLinus Torvalds MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
4011da177e4SLinus Torvalds 		       // the sake of this tag. It's Free Software.
402