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 43*fa0d7e3dSNick Piggin static void jffs2_i_callback(struct rcu_head *head) 44*fa0d7e3dSNick Piggin { 45*fa0d7e3dSNick Piggin struct inode *inode = container_of(head, struct inode, i_rcu); 46*fa0d7e3dSNick Piggin INIT_LIST_HEAD(&inode->i_dentry); 47*fa0d7e3dSNick Piggin kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode)); 48*fa0d7e3dSNick Piggin } 49*fa0d7e3dSNick Piggin 501da177e4SLinus Torvalds static void jffs2_destroy_inode(struct inode *inode) 511da177e4SLinus Torvalds { 52*fa0d7e3dSNick Piggin call_rcu(&inode->i_rcu, jffs2_i_callback); 531da177e4SLinus Torvalds } 541da177e4SLinus Torvalds 5551cc5068SAlexey Dobriyan static void jffs2_i_init_once(void *foo) 561da177e4SLinus Torvalds { 574e571abaSDavid Woodhouse struct jffs2_inode_info *f = foo; 581da177e4SLinus Torvalds 594e571abaSDavid Woodhouse mutex_init(&f->sem); 604e571abaSDavid Woodhouse inode_init_once(&f->vfs_inode); 611da177e4SLinus Torvalds } 621da177e4SLinus Torvalds 6301ba6875SChristoph Hellwig static void jffs2_write_super(struct super_block *sb) 6401ba6875SChristoph Hellwig { 6501ba6875SChristoph Hellwig struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 66ebc1ac16SChristoph Hellwig 67ebc1ac16SChristoph Hellwig lock_super(sb); 6801ba6875SChristoph Hellwig sb->s_dirt = 0; 6901ba6875SChristoph Hellwig 70ebc1ac16SChristoph Hellwig if (!(sb->s_flags & MS_RDONLY)) { 7101ba6875SChristoph Hellwig D1(printk(KERN_DEBUG "jffs2_write_super()\n")); 7201ba6875SChristoph Hellwig jffs2_flush_wbuf_gc(c, 0); 7301ba6875SChristoph Hellwig } 7401ba6875SChristoph Hellwig 75ebc1ac16SChristoph Hellwig unlock_super(sb); 76ebc1ac16SChristoph Hellwig } 77ebc1ac16SChristoph Hellwig 781da177e4SLinus Torvalds static int jffs2_sync_fs(struct super_block *sb, int wait) 791da177e4SLinus Torvalds { 801da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 811da177e4SLinus Torvalds 82d579ed00SChristoph Hellwig jffs2_write_super(sb); 83d579ed00SChristoph Hellwig 84ced22070SDavid Woodhouse mutex_lock(&c->alloc_sem); 851da177e4SLinus Torvalds jffs2_flush_wbuf_pad(c); 86ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 871da177e4SLinus Torvalds return 0; 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds 905f556aabSDavid Woodhouse static struct inode *jffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, 915f556aabSDavid Woodhouse uint32_t generation) 925f556aabSDavid Woodhouse { 935f556aabSDavid Woodhouse /* We don't care about i_generation. We'll destroy the flash 945f556aabSDavid Woodhouse before we start re-using inode numbers anyway. And even 955f556aabSDavid Woodhouse if that wasn't true, we'd have other problems...*/ 965f556aabSDavid Woodhouse return jffs2_iget(sb, ino); 975f556aabSDavid Woodhouse } 985f556aabSDavid Woodhouse 995f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, 1005f556aabSDavid Woodhouse int fh_len, int fh_type) 1015f556aabSDavid Woodhouse { 1025f556aabSDavid Woodhouse return generic_fh_to_dentry(sb, fid, fh_len, fh_type, 1035f556aabSDavid Woodhouse jffs2_nfs_get_inode); 1045f556aabSDavid Woodhouse } 1055f556aabSDavid Woodhouse 1065f556aabSDavid Woodhouse static struct dentry *jffs2_fh_to_parent(struct super_block *sb, struct fid *fid, 1075f556aabSDavid Woodhouse int fh_len, int fh_type) 1085f556aabSDavid Woodhouse { 1095f556aabSDavid Woodhouse return generic_fh_to_parent(sb, fid, fh_len, fh_type, 1105f556aabSDavid Woodhouse jffs2_nfs_get_inode); 1115f556aabSDavid Woodhouse } 1125f556aabSDavid Woodhouse 1135f556aabSDavid Woodhouse static struct dentry *jffs2_get_parent(struct dentry *child) 1145f556aabSDavid Woodhouse { 1155f556aabSDavid Woodhouse struct jffs2_inode_info *f; 1165f556aabSDavid Woodhouse uint32_t pino; 1175f556aabSDavid Woodhouse 1185f556aabSDavid Woodhouse BUG_ON(!S_ISDIR(child->d_inode->i_mode)); 1195f556aabSDavid Woodhouse 1205f556aabSDavid Woodhouse f = JFFS2_INODE_INFO(child->d_inode); 1215f556aabSDavid Woodhouse 1225f556aabSDavid Woodhouse pino = f->inocache->pino_nlink; 1235f556aabSDavid Woodhouse 1245f556aabSDavid Woodhouse JFFS2_DEBUG("Parent of directory ino #%u is #%u\n", 1255f556aabSDavid Woodhouse f->inocache->ino, pino); 1265f556aabSDavid Woodhouse 1275f556aabSDavid Woodhouse return d_obtain_alias(jffs2_iget(child->d_inode->i_sb, pino)); 1285f556aabSDavid Woodhouse } 1295f556aabSDavid Woodhouse 130ac4cfdd6SAlexey Dobriyan static const struct export_operations jffs2_export_ops = { 1315f556aabSDavid Woodhouse .get_parent = jffs2_get_parent, 1325f556aabSDavid Woodhouse .fh_to_dentry = jffs2_fh_to_dentry, 1335f556aabSDavid Woodhouse .fh_to_parent = jffs2_fh_to_parent, 1345f556aabSDavid Woodhouse }; 1355f556aabSDavid Woodhouse 136ee9b6d61SJosef 'Jeff' Sipek static const struct super_operations jffs2_super_operations = 1371da177e4SLinus Torvalds { 1381da177e4SLinus Torvalds .alloc_inode = jffs2_alloc_inode, 1391da177e4SLinus Torvalds .destroy_inode =jffs2_destroy_inode, 1401da177e4SLinus Torvalds .put_super = jffs2_put_super, 1411da177e4SLinus Torvalds .write_super = jffs2_write_super, 1421da177e4SLinus Torvalds .statfs = jffs2_statfs, 1431da177e4SLinus Torvalds .remount_fs = jffs2_remount_fs, 144b57922d9SAl Viro .evict_inode = jffs2_evict_inode, 1451da177e4SLinus Torvalds .dirty_inode = jffs2_dirty_inode, 1461da177e4SLinus Torvalds .sync_fs = jffs2_sync_fs, 1471da177e4SLinus Torvalds }; 1481da177e4SLinus Torvalds 149acaebfd8SDavid Howells /* 150acaebfd8SDavid Howells * fill in the superblock 151acaebfd8SDavid Howells */ 152acaebfd8SDavid Howells static int jffs2_fill_super(struct super_block *sb, void *data, int silent) 1531da177e4SLinus Torvalds { 1541da177e4SLinus Torvalds struct jffs2_sb_info *c; 155db719222SJan Blunck int ret; 156db719222SJan Blunck 157acaebfd8SDavid Howells D1(printk(KERN_DEBUG "jffs2_get_sb_mtd():" 158acaebfd8SDavid Howells " New superblock for device %d (\"%s\")\n", 159acaebfd8SDavid Howells sb->s_mtd->index, sb->s_mtd->name)); 1601da177e4SLinus Torvalds 161f8314dc6SPanagiotis Issaris c = kzalloc(sizeof(*c), GFP_KERNEL); 1621a028dd2SArnd Bergmann if (!c) 163454e2398SDavid Howells return -ENOMEM; 1641da177e4SLinus Torvalds 165acaebfd8SDavid Howells c->mtd = sb->s_mtd; 166acaebfd8SDavid Howells c->os_priv = sb; 167acaebfd8SDavid Howells sb->s_fs_info = c; 1681da177e4SLinus Torvalds 169acaebfd8SDavid Howells /* Initialize JFFS2 superblock locks, the further initialization will 170acaebfd8SDavid Howells * be done later */ 171ced22070SDavid Woodhouse mutex_init(&c->alloc_sem); 172ced22070SDavid Woodhouse mutex_init(&c->erase_free_sem); 173b6220598SArtem B. Bityuckiy init_waitqueue_head(&c->erase_wait); 174b6220598SArtem B. Bityuckiy init_waitqueue_head(&c->inocache_wq); 175b6220598SArtem B. Bityuckiy spin_lock_init(&c->erase_completion_lock); 176b6220598SArtem B. Bityuckiy spin_lock_init(&c->inocache_lock); 177b6220598SArtem B. Bityuckiy 1781da177e4SLinus Torvalds sb->s_op = &jffs2_super_operations; 1795f556aabSDavid Woodhouse sb->s_export_op = &jffs2_export_ops; 180acaebfd8SDavid Howells sb->s_flags = sb->s_flags | MS_NOATIME; 181aa98d7cfSKaiGai Kohei sb->s_xattr = jffs2_xattr_handlers; 182aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_POSIX_ACL 183aa98d7cfSKaiGai Kohei sb->s_flags |= MS_POSIXACL; 184aa98d7cfSKaiGai Kohei #endif 185db719222SJan Blunck ret = jffs2_do_fill_super(sb, data, silent); 186db719222SJan Blunck return ret; 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds 189848b83a5SAl Viro static struct dentry *jffs2_mount(struct file_system_type *fs_type, 1901da177e4SLinus Torvalds int flags, const char *dev_name, 191848b83a5SAl Viro void *data) 1921da177e4SLinus Torvalds { 193848b83a5SAl Viro return mount_mtd(fs_type, flags, dev_name, data, jffs2_fill_super); 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds static void jffs2_put_super (struct super_block *sb) 1971da177e4SLinus Torvalds { 1981da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); 2011da177e4SLinus Torvalds 2028c85e125SChristoph Hellwig if (sb->s_dirt) 2038c85e125SChristoph Hellwig jffs2_write_super(sb); 2048c85e125SChristoph Hellwig 205ced22070SDavid Woodhouse mutex_lock(&c->alloc_sem); 2061da177e4SLinus Torvalds jffs2_flush_wbuf_pad(c); 207ced22070SDavid Woodhouse mutex_unlock(&c->alloc_sem); 208e631ddbaSFerenc Havasi 209e631ddbaSFerenc Havasi jffs2_sum_exit(c); 210e631ddbaSFerenc Havasi 2111da177e4SLinus Torvalds jffs2_free_ino_caches(c); 2121da177e4SLinus Torvalds jffs2_free_raw_node_refs(c); 2134ce1f562SFerenc Havasi if (jffs2_blocks_use_vmalloc(c)) 2141da177e4SLinus Torvalds vfree(c->blocks); 2151da177e4SLinus Torvalds else 2161da177e4SLinus Torvalds kfree(c->blocks); 2171da177e4SLinus Torvalds jffs2_flash_cleanup(c); 2181da177e4SLinus Torvalds kfree(c->inocache_list); 219aa98d7cfSKaiGai Kohei jffs2_clear_xattr_subsystem(c); 2201da177e4SLinus Torvalds if (c->mtd->sync) 2211da177e4SLinus Torvalds c->mtd->sync(c->mtd); 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds D1(printk(KERN_DEBUG "jffs2_put_super returning\n")); 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds static void jffs2_kill_sb(struct super_block *sb) 2271da177e4SLinus Torvalds { 2281da177e4SLinus Torvalds struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); 229a69dde91SArtem B. Bityuckiy if (!(sb->s_flags & MS_RDONLY)) 230a69dde91SArtem B. Bityuckiy jffs2_stop_garbage_collect_thread(c); 231acaebfd8SDavid Howells kill_mtd_super(sb); 2321da177e4SLinus Torvalds kfree(c); 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds static struct file_system_type jffs2_fs_type = { 2361da177e4SLinus Torvalds .owner = THIS_MODULE, 2371da177e4SLinus Torvalds .name = "jffs2", 238848b83a5SAl Viro .mount = jffs2_mount, 2391da177e4SLinus Torvalds .kill_sb = jffs2_kill_sb, 2401da177e4SLinus Torvalds }; 2411da177e4SLinus Torvalds 2421da177e4SLinus Torvalds static int __init init_jffs2_fs(void) 2431da177e4SLinus Torvalds { 2441da177e4SLinus Torvalds int ret; 2451da177e4SLinus Torvalds 2463e68fbb5SDavid Woodhouse /* Paranoia checks for on-medium structures. If we ask GCC 2473e68fbb5SDavid Woodhouse to pack them with __attribute__((packed)) then it _also_ 2483e68fbb5SDavid Woodhouse assumes that they're not aligned -- so it emits crappy 2493e68fbb5SDavid Woodhouse code on some architectures. Ideally we want an attribute 2503e68fbb5SDavid Woodhouse which means just 'no padding', without the alignment 2513e68fbb5SDavid Woodhouse thing. But GCC doesn't have that -- we have to just 2523e68fbb5SDavid Woodhouse hope the structs are the right sizes, instead. */ 2532ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12); 2542ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40); 2552ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68); 2562ecd05aeSAlexey Dobriyan BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32); 2573e68fbb5SDavid Woodhouse 2581da177e4SLinus Torvalds printk(KERN_INFO "JFFS2 version 2.2." 2592f82ce1eSAndrew Victor #ifdef CONFIG_JFFS2_FS_WRITEBUFFER 2601da177e4SLinus Torvalds " (NAND)" 2611da177e4SLinus Torvalds #endif 262e631ddbaSFerenc Havasi #ifdef CONFIG_JFFS2_SUMMARY 263e631ddbaSFerenc Havasi " (SUMMARY) " 264e631ddbaSFerenc Havasi #endif 265c00c310eSDavid Woodhouse " © 2001-2006 Red Hat, Inc.\n"); 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds jffs2_inode_cachep = kmem_cache_create("jffs2_i", 2681da177e4SLinus Torvalds sizeof(struct jffs2_inode_info), 269fffb60f9SPaul Jackson 0, (SLAB_RECLAIM_ACCOUNT| 270fffb60f9SPaul Jackson SLAB_MEM_SPREAD), 27120c2df83SPaul Mundt jffs2_i_init_once); 2721da177e4SLinus Torvalds if (!jffs2_inode_cachep) { 2731da177e4SLinus Torvalds printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n"); 2741da177e4SLinus Torvalds return -ENOMEM; 2751da177e4SLinus Torvalds } 2761da177e4SLinus Torvalds ret = jffs2_compressors_init(); 2771da177e4SLinus Torvalds if (ret) { 2781da177e4SLinus Torvalds printk(KERN_ERR "JFFS2 error: Failed to initialise compressors\n"); 2791da177e4SLinus Torvalds goto out; 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds ret = jffs2_create_slab_caches(); 2821da177e4SLinus Torvalds if (ret) { 2831da177e4SLinus Torvalds printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n"); 2841da177e4SLinus Torvalds goto out_compressors; 2851da177e4SLinus Torvalds } 2861da177e4SLinus Torvalds ret = register_filesystem(&jffs2_fs_type); 2871da177e4SLinus Torvalds if (ret) { 2881da177e4SLinus Torvalds printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n"); 2891da177e4SLinus Torvalds goto out_slab; 2901da177e4SLinus Torvalds } 2911da177e4SLinus Torvalds return 0; 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds out_slab: 2941da177e4SLinus Torvalds jffs2_destroy_slab_caches(); 2951da177e4SLinus Torvalds out_compressors: 2961da177e4SLinus Torvalds jffs2_compressors_exit(); 2971da177e4SLinus Torvalds out: 2981da177e4SLinus Torvalds kmem_cache_destroy(jffs2_inode_cachep); 2991da177e4SLinus Torvalds return ret; 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds static void __exit exit_jffs2_fs(void) 3031da177e4SLinus Torvalds { 3041da177e4SLinus Torvalds unregister_filesystem(&jffs2_fs_type); 3051da177e4SLinus Torvalds jffs2_destroy_slab_caches(); 3061da177e4SLinus Torvalds jffs2_compressors_exit(); 3071da177e4SLinus Torvalds kmem_cache_destroy(jffs2_inode_cachep); 3081da177e4SLinus Torvalds } 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds module_init(init_jffs2_fs); 3111da177e4SLinus Torvalds module_exit(exit_jffs2_fs); 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds MODULE_DESCRIPTION("The Journalling Flash File System, v2"); 3141da177e4SLinus Torvalds MODULE_AUTHOR("Red Hat, Inc."); 3151da177e4SLinus Torvalds MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for 3161da177e4SLinus Torvalds // the sake of this tag. It's Free Software. 317