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 5021eeb7aaSThomas Gleixner init_MUTEX(&ei->sem); 511da177e4SLinus Torvalds inode_init_once(&ei->vfs_inode); 521da177e4SLinus Torvalds } 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds static int jffs2_sync_fs(struct super_block *sb, int wait) 551da177e4SLinus Torvalds { 561da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds down(&c->alloc_sem); 591da177e4SLinus Torvalds jffs2_flush_wbuf_pad(c); 601da177e4SLinus Torvalds up(&c->alloc_sem); 611da177e4SLinus Torvalds return 0; 621da177e4SLinus Torvalds } 631da177e4SLinus Torvalds 64ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jffs2_super_operations = 651da177e4SLinus Torvalds { 661da177e4SLinus Torvalds .alloc_inode = jffs2_alloc_inode, 671da177e4SLinus Torvalds .destroy_inode =jffs2_destroy_inode, 681da177e4SLinus Torvalds .read_inode = jffs2_read_inode, 691da177e4SLinus Torvalds .put_super = jffs2_put_super, 701da177e4SLinus Torvalds .write_super = jffs2_write_super, 711da177e4SLinus Torvalds .statfs = jffs2_statfs, 721da177e4SLinus Torvalds .remount_fs = jffs2_remount_fs, 731da177e4SLinus Torvalds .clear_inode = jffs2_clear_inode, 741da177e4SLinus Torvalds .dirty_inode = jffs2_dirty_inode, 751da177e4SLinus Torvalds .sync_fs = jffs2_sync_fs, 761da177e4SLinus Torvalds }; 771da177e4SLinus Torvalds 78acaebfd8SDavid Howells /* 79acaebfd8SDavid Howells * fill in the superblock 80acaebfd8SDavid Howells */ 81acaebfd8SDavid Howells static int jffs2_fill_super(struct super_block *sb, void *data, int silent) 821da177e4SLinus Torvalds { 831da177e4SLinus Torvalds struct jffs2_sb_info *c; 84acaebfd8SDavid Howells 85acaebfd8SDavid Howells D1(printk(KERN_DEBUG "jffs2_get_sb_mtd():" 86acaebfd8SDavid Howells " New superblock for device %d (\"%s\")\n", 87acaebfd8SDavid Howells sb->s_mtd->index, sb->s_mtd->name)); 881da177e4SLinus Torvalds 89f8314dc6SPanagiotis Issaris c = kzalloc(sizeof(*c), GFP_KERNEL); 901da177e4SLinus Torvalds if (!c) 91454e2398SDavid Howells return -ENOMEM; 921da177e4SLinus Torvalds 93acaebfd8SDavid Howells c->mtd = sb->s_mtd; 94acaebfd8SDavid Howells c->os_priv = sb; 95acaebfd8SDavid Howells sb->s_fs_info = c; 961da177e4SLinus Torvalds 97acaebfd8SDavid Howells /* Initialize JFFS2 superblock locks, the further initialization will 98acaebfd8SDavid Howells * be done later */ 99b6220598SArtem B. Bityuckiy init_MUTEX(&c->alloc_sem); 100b6220598SArtem B. Bityuckiy init_MUTEX(&c->erase_free_sem); 101b6220598SArtem B. Bityuckiy init_waitqueue_head(&c->erase_wait); 102b6220598SArtem B. Bityuckiy init_waitqueue_head(&c->inocache_wq); 103b6220598SArtem B. Bityuckiy spin_lock_init(&c->erase_completion_lock); 104b6220598SArtem B. Bityuckiy spin_lock_init(&c->inocache_lock); 105b6220598SArtem B. Bityuckiy 1061da177e4SLinus Torvalds sb->s_op = &jffs2_super_operations; 107acaebfd8SDavid Howells sb->s_flags = sb->s_flags | MS_NOATIME; 108aa98d7cfSKaiGai Kohei sb->s_xattr = jffs2_xattr_handlers; 109aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL 110aa98d7cfSKaiGai Kohei sb->s_flags |= MS_POSIXACL; 111aa98d7cfSKaiGai Kohei #endif 112acaebfd8SDavid Howells return jffs2_do_fill_super(sb, data, silent); 1131da177e4SLinus Torvalds } 1141da177e4SLinus Torvalds 115454e2398SDavid Howells static int jffs2_get_sb(struct file_system_type *fs_type, 1161da177e4SLinus Torvalds int flags, const char *dev_name, 117454e2398SDavid Howells void *data, struct vfsmount *mnt) 1181da177e4SLinus Torvalds { 119acaebfd8SDavid Howells return get_sb_mtd(fs_type, flags, dev_name, data, jffs2_fill_super, 120acaebfd8SDavid Howells mnt); 1211da177e4SLinus Torvalds } 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds static void jffs2_put_super (struct super_block *sb) 1241da177e4SLinus Torvalds { 1251da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds down(&c->alloc_sem); 1301da177e4SLinus Torvalds jffs2_flush_wbuf_pad(c); 1311da177e4SLinus Torvalds up(&c->alloc_sem); 132e631ddbaSFerenc Havasi 133e631ddbaSFerenc Havasi jffs2_sum_exit(c); 134e631ddbaSFerenc Havasi 1351da177e4SLinus Torvalds jffs2_free_ino_caches(c); 1361da177e4SLinus Torvalds jffs2_free_raw_node_refs(c); 1374ce1f562SFerenc Havasi if (jffs2_blocks_use_vmalloc(c)) 1381da177e4SLinus Torvalds vfree(c->blocks); 1391da177e4SLinus Torvalds else 1401da177e4SLinus Torvalds kfree(c->blocks); 1411da177e4SLinus Torvalds jffs2_flash_cleanup(c); 1421da177e4SLinus Torvalds kfree(c->inocache_list); 143aa98d7cfSKaiGai Kohei jffs2_clear_xattr_subsystem(c); 1441da177e4SLinus Torvalds if (c->mtd->sync) 1451da177e4SLinus Torvalds c->mtd->sync(c->mtd); 1461da177e4SLinus Torvalds 1471da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_put_super returning\n")); 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds static void jffs2_kill_sb(struct super_block *sb) 1511da177e4SLinus Torvalds { 1521da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 153a69dde91SArtem B. Bityuckiy if (!(sb->s_flags & MS_RDONLY)) 154a69dde91SArtem B. Bityuckiy jffs2_stop_garbage_collect_thread(c); 155acaebfd8SDavid Howells kill_mtd_super(sb); 1561da177e4SLinus Torvalds kfree(c); 1571da177e4SLinus Torvalds } 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds static struct file_system_type jffs2_fs_type = { 1601da177e4SLinus Torvalds .owner = THIS_MODULE, 1611da177e4SLinus Torvalds .name = "jffs2", 1621da177e4SLinus Torvalds .get_sb = jffs2_get_sb, 1631da177e4SLinus Torvalds .kill_sb = jffs2_kill_sb, 1641da177e4SLinus Torvalds }; 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds static int __init init_jffs2_fs(void) 1671da177e4SLinus Torvalds { 1681da177e4SLinus Torvalds int ret; 1691da177e4SLinus Torvalds 1703e68fbb5SDavid Woodhouse /* Paranoia checks for on-medium structures. If we ask GCC 1713e68fbb5SDavid Woodhouse to pack them with __attribute__((packed)) then it _also_ 1723e68fbb5SDavid Woodhouse assumes that they're not aligned -- so it emits crappy 1733e68fbb5SDavid Woodhouse code on some architectures. Ideally we want an attribute 1743e68fbb5SDavid Woodhouse which means just 'no padding', without the alignment 1753e68fbb5SDavid Woodhouse thing. But GCC doesn't have that -- we have to just 1763e68fbb5SDavid Woodhouse hope the structs are the right sizes, instead. */ 1772ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12); 1782ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40); 1792ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); 1802ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); 1813e68fbb5SDavid Woodhouse 1821da177e4SLinus Torvalds printk(KERN_INFO "JFFS2 version 2.2." 1832f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER 1841da177e4SLinus Torvalds " (NAND)" 1851da177e4SLinus Torvalds #endif 186e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY 187e631ddbaSFerenc Havasi " (SUMMARY) " 188e631ddbaSFerenc Havasi #endif 189c00c310eSDavid Woodhouse " © 2001-2006 Red Hat, Inc.\n"); 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds jffs2_inode_cachep = kmem_cache_create("jffs2_i", 1921da177e4SLinus Torvalds sizeof(struct jffs2_inode_info), 193fffb60f9SPaul Jackson 0, (SLAB_RECLAIM_ACCOUNT| 194fffb60f9SPaul Jackson SLAB_MEM_SPREAD), 195*20c2df83SPaul Mundt jffs2_i_init_once); 1961da177e4SLinus Torvalds if (!jffs2_inode_cachep) { 1971da177e4SLinus Torvalds printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n"); 1981da177e4SLinus Torvalds return -ENOMEM; 1991da177e4SLinus Torvalds } 2001da177e4SLinus Torvalds ret = jffs2_compressors_init(); 2011da177e4SLinus Torvalds if (ret) { 2021da177e4SLinus Torvalds printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n"); 2031da177e4SLinus Torvalds goto out; 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds ret = jffs2_create_slab_caches(); 2061da177e4SLinus Torvalds if (ret) { 2071da177e4SLinus Torvalds printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n"); 2081da177e4SLinus Torvalds goto out_compressors; 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds ret = register_filesystem(&jffs2_fs_type); 2111da177e4SLinus Torvalds if (ret) { 2121da177e4SLinus Torvalds printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n"); 2131da177e4SLinus Torvalds goto out_slab; 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds return 0; 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds out_slab: 2181da177e4SLinus Torvalds jffs2_destroy_slab_caches(); 2191da177e4SLinus Torvalds out_compressors: 2201da177e4SLinus Torvalds jffs2_compressors_exit(); 2211da177e4SLinus Torvalds out: 2221da177e4SLinus Torvalds kmem_cache_destroy(jffs2_inode_cachep); 2231da177e4SLinus Torvalds return ret; 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void) 2271da177e4SLinus Torvalds { 2281da177e4SLinus Torvalds unregister_filesystem(&jffs2_fs_type); 2291da177e4SLinus Torvalds jffs2_destroy_slab_caches(); 2301da177e4SLinus Torvalds jffs2_compressors_exit(); 2311da177e4SLinus Torvalds kmem_cache_destroy(jffs2_inode_cachep); 2321da177e4SLinus Torvalds } 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds module_init(init_jffs2_fs); 2351da177e4SLinus Torvalds module_exit(exit_jffs2_fs); 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journalling Flash File System, v2"); 2381da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc."); 2391da177e4SLinus Torvalds MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for 2401da177e4SLinus Torvalds // the sake of this tag. It's Free Software. 241