xref: /openbmc/linux/fs/jffs2/super.c (revision 5f556aab)
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>
255f556aabSDavid Woodhouse #include <linux/exportfs.h>
261da177e4SLinus Torvalds #include "compr.h"
271da177e4SLinus Torvalds #include "nodelist.h"
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds static void jffs2_put_super(struct super_block *);
301da177e4SLinus Torvalds 
31e18b890bSChristoph Lameter static struct kmem_cache *jffs2_inode_cachep;
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds static struct inode *jffs2_alloc_inode(struct super_block *sb)
341da177e4SLinus Torvalds {
354e571abaSDavid Woodhouse 	struct jffs2_inode_info *f;
364e571abaSDavid Woodhouse 
374e571abaSDavid Woodhouse 	f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL);
384e571abaSDavid Woodhouse 	if (!f)
391da177e4SLinus Torvalds 		return NULL;
404e571abaSDavid Woodhouse 	return &f->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 
4851cc5068SAlexey Dobriyan static void jffs2_i_init_once(void *foo)
491da177e4SLinus Torvalds {
504e571abaSDavid Woodhouse 	struct jffs2_inode_info *f = foo;
511da177e4SLinus Torvalds 
524e571abaSDavid Woodhouse 	mutex_init(&f->sem);
534e571abaSDavid Woodhouse 	inode_init_once(&f->vfs_inode);
541da177e4SLinus Torvalds }
551da177e4SLinus Torvalds 
561da177e4SLinus Torvalds static int jffs2_sync_fs(struct super_block *sb, int wait)
571da177e4SLinus Torvalds {
581da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
591da177e4SLinus Torvalds 
60ced22070SDavid Woodhouse 	mutex_lock(&c->alloc_sem);
611da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
62ced22070SDavid Woodhouse 	mutex_unlock(&c->alloc_sem);
631da177e4SLinus Torvalds 	return 0;
641da177e4SLinus Torvalds }
651da177e4SLinus Torvalds 
665f556aabSDavid Woodhouse static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino,
675f556aabSDavid Woodhouse 					 uint32_t generation)
685f556aabSDavid Woodhouse {
695f556aabSDavid Woodhouse 	/* We don't care about i_generation. We'll destroy the flash
705f556aabSDavid Woodhouse 	   before we start re-using inode numbers anyway. And even
715f556aabSDavid Woodhouse 	   if that wasn't true, we'd have other problems...*/
725f556aabSDavid Woodhouse 	return jffs2_iget(sb, ino);
735f556aabSDavid Woodhouse }
745f556aabSDavid Woodhouse 
755f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
765f556aabSDavid Woodhouse 					 int fh_len, int fh_type)
775f556aabSDavid Woodhouse {
785f556aabSDavid Woodhouse         return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
795f556aabSDavid Woodhouse                                     jffs2_nfs_get_inode);
805f556aabSDavid Woodhouse }
815f556aabSDavid Woodhouse 
825f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid,
835f556aabSDavid Woodhouse 					 int fh_len, int fh_type)
845f556aabSDavid Woodhouse {
855f556aabSDavid Woodhouse         return generic_fh_to_parent(sb, fid, fh_len, fh_type,
865f556aabSDavid Woodhouse                                     jffs2_nfs_get_inode);
875f556aabSDavid Woodhouse }
885f556aabSDavid Woodhouse 
895f556aabSDavid Woodhouse static struct dentry *jffs2_get_parent(struct dentry *child)
905f556aabSDavid Woodhouse {
915f556aabSDavid Woodhouse 	struct jffs2_inode_info *f;
925f556aabSDavid Woodhouse 	uint32_t pino;
935f556aabSDavid Woodhouse 
945f556aabSDavid Woodhouse 	BUG_ON(!S_ISDIR(child->d_inode->i_mode));
955f556aabSDavid Woodhouse 
965f556aabSDavid Woodhouse 	f = JFFS2_INODE_INFO(child->d_inode);
975f556aabSDavid Woodhouse 
985f556aabSDavid Woodhouse 	pino = f->inocache->pino_nlink;
995f556aabSDavid Woodhouse 
1005f556aabSDavid Woodhouse 	JFFS2_DEBUG("Parent of directory ino #%u is #%u\n",
1015f556aabSDavid Woodhouse 		    f->inocache->ino, pino);
1025f556aabSDavid Woodhouse 
1035f556aabSDavid Woodhouse 	return d_obtain_alias(jffs2_iget(child->d_inode->i_sb, pino));
1045f556aabSDavid Woodhouse }
1055f556aabSDavid Woodhouse 
1065f556aabSDavid Woodhouse static struct export_operations jffs2_export_ops = {
1075f556aabSDavid Woodhouse 	.get_parent = jffs2_get_parent,
1085f556aabSDavid Woodhouse 	.fh_to_dentry = jffs2_fh_to_dentry,
1095f556aabSDavid Woodhouse 	.fh_to_parent = jffs2_fh_to_parent,
1105f556aabSDavid Woodhouse };
1115f556aabSDavid Woodhouse 
112ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jffs2_super_operations =
1131da177e4SLinus Torvalds {
1141da177e4SLinus Torvalds 	.alloc_inode =	jffs2_alloc_inode,
1151da177e4SLinus Torvalds 	.destroy_inode =jffs2_destroy_inode,
1161da177e4SLinus Torvalds 	.put_super =	jffs2_put_super,
1171da177e4SLinus Torvalds 	.write_super =	jffs2_write_super,
1181da177e4SLinus Torvalds 	.statfs =	jffs2_statfs,
1191da177e4SLinus Torvalds 	.remount_fs =	jffs2_remount_fs,
1201da177e4SLinus Torvalds 	.clear_inode =	jffs2_clear_inode,
1211da177e4SLinus Torvalds 	.dirty_inode =	jffs2_dirty_inode,
1221da177e4SLinus Torvalds 	.sync_fs =	jffs2_sync_fs,
1231da177e4SLinus Torvalds };
1241da177e4SLinus Torvalds 
125acaebfd8SDavid Howells /*
126acaebfd8SDavid Howells  * fill in the superblock
127acaebfd8SDavid Howells  */
128acaebfd8SDavid Howells static int jffs2_fill_super(struct super_block *sb, void *data, int silent)
1291da177e4SLinus Torvalds {
1301da177e4SLinus Torvalds 	struct jffs2_sb_info *c;
131acaebfd8SDavid Howells 
132acaebfd8SDavid Howells 	D1(printk(KERN_DEBUG "jffs2_get_sb_mtd():"
133acaebfd8SDavid Howells 		  " New superblock for device %d (\"%s\")\n",
134acaebfd8SDavid Howells 		  sb->s_mtd->index, sb->s_mtd->name));
1351da177e4SLinus Torvalds 
136f8314dc6SPanagiotis Issaris 	c = kzalloc(sizeof(*c), GFP_KERNEL);
1371da177e4SLinus Torvalds 	if (!c)
138454e2398SDavid Howells 		return -ENOMEM;
1391da177e4SLinus Torvalds 
140acaebfd8SDavid Howells 	c->mtd = sb->s_mtd;
141acaebfd8SDavid Howells 	c->os_priv = sb;
142acaebfd8SDavid Howells 	sb->s_fs_info = c;
1431da177e4SLinus Torvalds 
144acaebfd8SDavid Howells 	/* Initialize JFFS2 superblock locks, the further initialization will
145acaebfd8SDavid Howells 	 * be done later */
146ced22070SDavid Woodhouse 	mutex_init(&c->alloc_sem);
147ced22070SDavid Woodhouse 	mutex_init(&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;
1545f556aabSDavid Woodhouse 	sb->s_export_op = &jffs2_export_ops;
155acaebfd8SDavid Howells 	sb->s_flags = sb->s_flags | MS_NOATIME;
156aa98d7cfSKaiGai Kohei 	sb->s_xattr = jffs2_xattr_handlers;
157aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL
158aa98d7cfSKaiGai Kohei 	sb->s_flags |= MS_POSIXACL;
159aa98d7cfSKaiGai Kohei #endif
160acaebfd8SDavid Howells 	return jffs2_do_fill_super(sb, data, silent);
1611da177e4SLinus Torvalds }
1621da177e4SLinus Torvalds 
163454e2398SDavid Howells static int jffs2_get_sb(struct file_system_type *fs_type,
1641da177e4SLinus Torvalds 			int flags, const char *dev_name,
165454e2398SDavid Howells 			void *data, struct vfsmount *mnt)
1661da177e4SLinus Torvalds {
167acaebfd8SDavid Howells 	return get_sb_mtd(fs_type, flags, dev_name, data, jffs2_fill_super,
168acaebfd8SDavid Howells 			  mnt);
1691da177e4SLinus Torvalds }
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds static void jffs2_put_super (struct super_block *sb)
1721da177e4SLinus Torvalds {
1731da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
1761da177e4SLinus Torvalds 
177ced22070SDavid Woodhouse 	mutex_lock(&c->alloc_sem);
1781da177e4SLinus Torvalds 	jffs2_flush_wbuf_pad(c);
179ced22070SDavid Woodhouse 	mutex_unlock(&c->alloc_sem);
180e631ddbaSFerenc Havasi 
181e631ddbaSFerenc Havasi 	jffs2_sum_exit(c);
182e631ddbaSFerenc Havasi 
1831da177e4SLinus Torvalds 	jffs2_free_ino_caches(c);
1841da177e4SLinus Torvalds 	jffs2_free_raw_node_refs(c);
1854ce1f562SFerenc Havasi 	if (jffs2_blocks_use_vmalloc(c))
1861da177e4SLinus Torvalds 		vfree(c->blocks);
1871da177e4SLinus Torvalds 	else
1881da177e4SLinus Torvalds 		kfree(c->blocks);
1891da177e4SLinus Torvalds 	jffs2_flash_cleanup(c);
1901da177e4SLinus Torvalds 	kfree(c->inocache_list);
191aa98d7cfSKaiGai Kohei 	jffs2_clear_xattr_subsystem(c);
1921da177e4SLinus Torvalds 	if (c->mtd->sync)
1931da177e4SLinus Torvalds 		c->mtd->sync(c->mtd);
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds 	D1(printk(KERN_DEBUG "jffs2_put_super returning\n"));
1961da177e4SLinus Torvalds }
1971da177e4SLinus Torvalds 
1981da177e4SLinus Torvalds static void jffs2_kill_sb(struct super_block *sb)
1991da177e4SLinus Torvalds {
2001da177e4SLinus Torvalds 	struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
201a69dde91SArtem B. Bityuckiy 	if (!(sb->s_flags & MS_RDONLY))
202a69dde91SArtem B. Bityuckiy 		jffs2_stop_garbage_collect_thread(c);
203acaebfd8SDavid Howells 	kill_mtd_super(sb);
2041da177e4SLinus Torvalds 	kfree(c);
2051da177e4SLinus Torvalds }
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds static struct file_system_type jffs2_fs_type = {
2081da177e4SLinus Torvalds 	.owner =	THIS_MODULE,
2091da177e4SLinus Torvalds 	.name =		"jffs2",
2101da177e4SLinus Torvalds 	.get_sb =	jffs2_get_sb,
2111da177e4SLinus Torvalds 	.kill_sb =	jffs2_kill_sb,
2121da177e4SLinus Torvalds };
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds static int __init init_jffs2_fs(void)
2151da177e4SLinus Torvalds {
2161da177e4SLinus Torvalds 	int ret;
2171da177e4SLinus Torvalds 
2183e68fbb5SDavid Woodhouse 	/* Paranoia checks for on-medium structures. If we ask GCC
2193e68fbb5SDavid Woodhouse 	   to pack them with __attribute__((packed)) then it _also_
2203e68fbb5SDavid Woodhouse 	   assumes that they're not aligned -- so it emits crappy
2213e68fbb5SDavid Woodhouse 	   code on some architectures. Ideally we want an attribute
2223e68fbb5SDavid Woodhouse 	   which means just 'no padding', without the alignment
2233e68fbb5SDavid Woodhouse 	   thing. But GCC doesn't have that -- we have to just
2243e68fbb5SDavid Woodhouse 	   hope the structs are the right sizes, instead. */
2252ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
2262ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
2272ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
2282ecd05aeSAlexey Dobriyan 	BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
2293e68fbb5SDavid Woodhouse 
2301da177e4SLinus Torvalds 	printk(KERN_INFO "JFFS2 version 2.2."
2312f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
2321da177e4SLinus Torvalds 	       " (NAND)"
2331da177e4SLinus Torvalds #endif
234e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY
235e631ddbaSFerenc Havasi 	       " (SUMMARY) "
236e631ddbaSFerenc Havasi #endif
237c00c310eSDavid Woodhouse 	       " © 2001-2006 Red Hat, Inc.\n");
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds 	jffs2_inode_cachep = kmem_cache_create("jffs2_i",
2401da177e4SLinus Torvalds 					     sizeof(struct jffs2_inode_info),
241fffb60f9SPaul Jackson 					     0, (SLAB_RECLAIM_ACCOUNT|
242fffb60f9SPaul Jackson 						SLAB_MEM_SPREAD),
24320c2df83SPaul Mundt 					     jffs2_i_init_once);
2441da177e4SLinus Torvalds 	if (!jffs2_inode_cachep) {
2451da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n");
2461da177e4SLinus Torvalds 		return -ENOMEM;
2471da177e4SLinus Torvalds 	}
2481da177e4SLinus Torvalds 	ret = jffs2_compressors_init();
2491da177e4SLinus Torvalds 	if (ret) {
2501da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n");
2511da177e4SLinus Torvalds 		goto out;
2521da177e4SLinus Torvalds 	}
2531da177e4SLinus Torvalds 	ret = jffs2_create_slab_caches();
2541da177e4SLinus Torvalds 	if (ret) {
2551da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n");
2561da177e4SLinus Torvalds 		goto out_compressors;
2571da177e4SLinus Torvalds 	}
2581da177e4SLinus Torvalds 	ret = register_filesystem(&jffs2_fs_type);
2591da177e4SLinus Torvalds 	if (ret) {
2601da177e4SLinus Torvalds 		printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n");
2611da177e4SLinus Torvalds 		goto out_slab;
2621da177e4SLinus Torvalds 	}
2631da177e4SLinus Torvalds 	return 0;
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds  out_slab:
2661da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
2671da177e4SLinus Torvalds  out_compressors:
2681da177e4SLinus Torvalds 	jffs2_compressors_exit();
2691da177e4SLinus Torvalds  out:
2701da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
2711da177e4SLinus Torvalds 	return ret;
2721da177e4SLinus Torvalds }
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void)
2751da177e4SLinus Torvalds {
2761da177e4SLinus Torvalds 	unregister_filesystem(&jffs2_fs_type);
2771da177e4SLinus Torvalds 	jffs2_destroy_slab_caches();
2781da177e4SLinus Torvalds 	jffs2_compressors_exit();
2791da177e4SLinus Torvalds 	kmem_cache_destroy(jffs2_inode_cachep);
2801da177e4SLinus Torvalds }
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds module_init(init_jffs2_fs);
2831da177e4SLinus Torvalds module_exit(exit_jffs2_fs);
2841da177e4SLinus Torvalds 
2851da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journalling Flash File System, v2");
2861da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc.");
2871da177e4SLinus Torvalds MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for
2881da177e4SLinus Torvalds 		       // the sake of this tag. It's Free Software.
289