xref: /openbmc/linux/fs/jffs2/super.c (revision acaebfd8)
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>
201da177e4SLinus Torvalds #include <linux/jffs2.h>
211da177e4SLinus Torvalds #include <linux/pagemap.h>
22acaebfd8SDavid Howells #include <linux/mtd/super.h>
231da177e4SLinus Torvalds #include <linux/ctype.h>
241da177e4SLinus Torvalds #include <linux/namei.h>
251da177e4SLinus Torvalds #include "compr.h"
261da177e4SLinus Torvalds #include "nodelist.h"
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds static void jffs2_put_super(struct super_block *);
291da177e4SLinus Torvalds 
30e18b890bSChristoph Lameter static struct kmem_cache *jffs2_inode_cachep;
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds static struct inode *jffs2_alloc_inode(struct super_block *sb)
331da177e4SLinus Torvalds {
341da177e4SLinus Torvalds 	struct jffs2_inode_info *ei;
35e94b1766SChristoph Lameter 	ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL);
361da177e4SLinus Torvalds 	if (!ei)
371da177e4SLinus Torvalds 		return NULL;
381da177e4SLinus Torvalds 	return &ei->vfs_inode;
391da177e4SLinus Torvalds }
401da177e4SLinus Torvalds 
411da177e4SLinus Torvalds static void jffs2_destroy_inode(struct inode *inode)
421da177e4SLinus Torvalds {
431da177e4SLinus Torvalds 	kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode));
441da177e4SLinus Torvalds }
451da177e4SLinus Torvalds 
46e18b890bSChristoph Lameter static void jffs2_i_init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
471da177e4SLinus Torvalds {
481da177e4SLinus Torvalds 	struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo;
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
511da177e4SLinus Torvalds 	    SLAB_CTOR_CONSTRUCTOR) {
5221eeb7aaSThomas Gleixner 		init_MUTEX(&ei->sem);
531da177e4SLinus Torvalds 		inode_init_once(&ei->vfs_inode);
541da177e4SLinus Torvalds 	}
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds static int jffs2_sync_fs(struct super_block *sb, int wait)
581da177e4SLinus Torvalds {
591da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds 	down(&c->alloc_sem);
621da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
631da177e4SLinus Torvalds 	up(&c->alloc_sem);
641da177e4SLinus Torvalds 	return 0;
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds 
67ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jffs2_super_operations =
681da177e4SLinus Torvalds {
691da177e4SLinus Torvalds 	.alloc_inode =	jffs2_alloc_inode,
701da177e4SLinus Torvalds 	.destroy_inode =jffs2_destroy_inode,
711da177e4SLinus Torvalds 	.read_inode =	jffs2_read_inode,
721da177e4SLinus Torvalds 	.put_super =	jffs2_put_super,
731da177e4SLinus Torvalds 	.write_super =	jffs2_write_super,
741da177e4SLinus Torvalds 	.statfs =	jffs2_statfs,
751da177e4SLinus Torvalds 	.remount_fs =	jffs2_remount_fs,
761da177e4SLinus Torvalds 	.clear_inode =	jffs2_clear_inode,
771da177e4SLinus Torvalds 	.dirty_inode =	jffs2_dirty_inode,
781da177e4SLinus Torvalds 	.sync_fs =	jffs2_sync_fs,
791da177e4SLinus Torvalds };
801da177e4SLinus Torvalds 
81acaebfd8SDavid Howells /*
82acaebfd8SDavid Howells  * fill in the superblock
83acaebfd8SDavid Howells  */
84acaebfd8SDavid Howells static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
851da177e4SLinus Torvalds {
861da177e4SLinus Torvalds 	struct jffs2_sb_info *c;
87acaebfd8SDavid Howells 
88acaebfd8SDavid Howells 	D1(printk(KERN_DEBUG "jffs2_get_sb_mtd():"
89acaebfd8SDavid Howells 		  " New superblock for device %d (\"%s\")\n",
90acaebfd8SDavid Howells 		  sb->s_mtd->index, sb->s_mtd->name));
911da177e4SLinus Torvalds 
92f8314dc6SPanagiotis Issaris 	c = kzalloc(sizeof(*c), GFP_KERNEL);
931da177e4SLinus Torvalds 	if (!c)
94454e2398SDavid Howells 		return -ENOMEM;
951da177e4SLinus Torvalds 
96acaebfd8SDavid Howells 	c->mtd = sb->s_mtd;
97acaebfd8SDavid Howells 	c->os_priv = sb;
98acaebfd8SDavid Howells 	sb->s_fs_info = c;
991da177e4SLinus Torvalds 
100acaebfd8SDavid Howells 	/* Initialize JFFS2 superblock locks, the further initialization will
101acaebfd8SDavid Howells 	 * be done later */
102b6220598SArtem B. Bityuckiy 	init_MUTEX(&c->alloc_sem);
103b6220598SArtem B. Bityuckiy 	init_MUTEX(&c->erase_free_sem);
104b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->erase_wait);
105b6220598SArtem B. Bityuckiy 	init_waitqueue_head(&c->inocache_wq);
106b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->erase_completion_lock);
107b6220598SArtem B. Bityuckiy 	spin_lock_init(&c->inocache_lock);
108b6220598SArtem B. Bityuckiy 
1091da177e4SLinus Torvalds 	sb->s_op = &jffs2_super_operations;
110acaebfd8SDavid Howells 	sb->s_flags = sb->s_flags | MS_NOATIME;
111aa98d7cfSKaiGai Kohei 	sb->s_xattr = jffs2_xattr_handlers;
112aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL
113aa98d7cfSKaiGai Kohei 	sb->s_flags |= MS_POSIXACL;
114aa98d7cfSKaiGai Kohei #endif
115acaebfd8SDavid Howells 	return jffs2_do_fill_super(sb, data, silent);
1161da177e4SLinus Torvalds }
1171da177e4SLinus Torvalds 
118454e2398SDavid Howells static int jffs2_get_sb(struct file_system_type *fs_type,
1191da177e4SLinus Torvalds 			int flags, const char *dev_name,
120454e2398SDavid Howells 			void *data, struct vfsmount *mnt)
1211da177e4SLinus Torvalds {
122acaebfd8SDavid Howells 	return get_sb_mtd(fs_type, flags, dev_name, data, jffs2_fill_super,
123acaebfd8SDavid Howells 			  mnt);
1241da177e4SLinus Torvalds }
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds static void jffs2_put_super (struct super_block *sb)
1271da177e4SLinus Torvalds {
1281da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds 	D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
1311da177e4SLinus Torvalds 
1321da177e4SLinus Torvalds 	down(&c->alloc_sem);
1331da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
1341da177e4SLinus Torvalds 	up(&c->alloc_sem);
135e631ddbaSFerenc Havasi 
136e631ddbaSFerenc Havasi 	jffs2_sum_exit(c);
137e631ddbaSFerenc Havasi 
1381da177e4SLinus Torvalds 	jffs2_free_ino_caches(c);
1391da177e4SLinus Torvalds 	jffs2_free_raw_node_refs(c);
1404ce1f562SFerenc Havasi 	if (jffs2_blocks_use_vmalloc(c))
1411da177e4SLinus Torvalds 		vfree(c->blocks);
1421da177e4SLinus Torvalds 	else
1431da177e4SLinus Torvalds 		kfree(c->blocks);
1441da177e4SLinus Torvalds 	jffs2_flash_cleanup(c);
1451da177e4SLinus Torvalds 	kfree(c->inocache_list);
146aa98d7cfSKaiGai Kohei 	jffs2_clear_xattr_subsystem(c);
1471da177e4SLinus Torvalds 	if (c->mtd->sync)
1481da177e4SLinus Torvalds 		c->mtd->sync(c->mtd);
1491da177e4SLinus Torvalds 
1501da177e4SLinus Torvalds 	D1(printk(KERN_DEBUG "jffs2_put_super returning\n"));
1511da177e4SLinus Torvalds }
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds static void jffs2_kill_sb(struct super_block *sb)
1541da177e4SLinus Torvalds {
1551da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
156a69dde91SArtem B. Bityuckiy 	if (!(sb->s_flags & MS_RDONLY))
157a69dde91SArtem B. Bityuckiy 		jffs2_stop_garbage_collect_thread(c);
158acaebfd8SDavid Howells 	kill_mtd_super(sb);
1591da177e4SLinus Torvalds 	kfree(c);
1601da177e4SLinus Torvalds }
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds static struct file_system_type jffs2_fs_type = {
1631da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
1641da177e4SLinus Torvalds 	.name =		"jffs2",
1651da177e4SLinus Torvalds 	.get_sb =	jffs2_get_sb,
1661da177e4SLinus Torvalds 	.kill_sb =	jffs2_kill_sb,
1671da177e4SLinus Torvalds };
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds static int __init init_jffs2_fs(void)
1701da177e4SLinus Torvalds {
1711da177e4SLinus Torvalds 	int ret;
1721da177e4SLinus Torvalds 
1733e68fbb5SDavid Woodhouse 	/* Paranoia checks for on-medium structures. If we ask GCC
1743e68fbb5SDavid Woodhouse 	   to pack them with __attribute__((packed)) then it _also_
1753e68fbb5SDavid Woodhouse 	   assumes that they're not aligned -- so it emits crappy
1763e68fbb5SDavid Woodhouse 	   code on some architectures. Ideally we want an attribute
1773e68fbb5SDavid Woodhouse 	   which means just 'no padding', without the alignment
1783e68fbb5SDavid Woodhouse 	   thing. But GCC doesn't have that -- we have to just
1793e68fbb5SDavid Woodhouse 	   hope the structs are the right sizes, instead. */
1802ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
1812ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
1822ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
1832ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
1843e68fbb5SDavid Woodhouse 
1851da177e4SLinus Torvalds 	printk(KERN_INFO "JFFS2 version 2.2."
1862f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
1871da177e4SLinus Torvalds 	       " (NAND)"
1881da177e4SLinus Torvalds #endif
189e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY
190e631ddbaSFerenc Havasi 	       " (SUMMARY) "
191e631ddbaSFerenc Havasi #endif
192c00c310eSDavid Woodhouse 	       " © 2001-2006 Red Hat, Inc.\n");
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
1951da177e4SLinus Torvalds 					     sizeof(struct jffs2_inode_info),
196fffb60f9SPaul Jackson 					     0, (SLAB_RECLAIM_ACCOUNT|
197fffb60f9SPaul Jackson 						SLAB_MEM_SPREAD),
1981da177e4SLinus Torvalds 					     jffs2_i_init_once, NULL);
1991da177e4SLinus Torvalds 	if (!jffs2_inode_cachep) {
2001da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
2011da177e4SLinus Torvalds 		return -ENOMEM;
2021da177e4SLinus Torvalds 	}
2031da177e4SLinus Torvalds 	ret = jffs2_compressors_init();
2041da177e4SLinus Torvalds 	if (ret) {
2051da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
2061da177e4SLinus Torvalds 		goto out;
2071da177e4SLinus Torvalds 	}
2081da177e4SLinus Torvalds 	ret = jffs2_create_slab_caches();
2091da177e4SLinus Torvalds 	if (ret) {
2101da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
2111da177e4SLinus Torvalds 		goto out_compressors;
2121da177e4SLinus Torvalds 	}
2131da177e4SLinus Torvalds 	ret = register_filesystem(&jffs2_fs_type);
2141da177e4SLinus Torvalds 	if (ret) {
2151da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n");
2161da177e4SLinus Torvalds 		goto out_slab;
2171da177e4SLinus Torvalds 	}
2181da177e4SLinus Torvalds 	return 0;
2191da177e4SLinus Torvalds 
2201da177e4SLinus Torvalds  out_slab:
2211da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
2221da177e4SLinus Torvalds  out_compressors:
2231da177e4SLinus Torvalds 	jffs2_compressors_exit();
2241da177e4SLinus Torvalds  out:
2251da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
2261da177e4SLinus Torvalds 	return ret;
2271da177e4SLinus Torvalds }
2281da177e4SLinus Torvalds 
2291da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void)
2301da177e4SLinus Torvalds {
2311da177e4SLinus Torvalds 	unregister_filesystem(&jffs2_fs_type);
2321da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
2331da177e4SLinus Torvalds 	jffs2_compressors_exit();
2341da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
2351da177e4SLinus Torvalds }
2361da177e4SLinus Torvalds 
2371da177e4SLinus Torvalds module_init(init_jffs2_fs);
2381da177e4SLinus Torvalds module_exit(exit_jffs2_fs);
2391da177e4SLinus Torvalds 
2401da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journalling Flash File System, v2");
2411da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc.");
2421da177e4SLinus Torvalds MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
2431da177e4SLinus Torvalds 		       // the sake of this tag. It's Free Software.
244