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