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/slab.h> 141da177e4SLinus Torvalds #include <linux/init.h> 151da177e4SLinus Torvalds #include <linux/jffs2.h> 161da177e4SLinus Torvalds #include "nodelist.h" 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds /* These are initialised to NULL in the kernel startup code. 191da177e4SLinus Torvalds If you're porting to other operating systems, beware */ 20e18b890bSChristoph Lameter static struct kmem_cache *full_dnode_slab; 21e18b890bSChristoph Lameter static struct kmem_cache *raw_dirent_slab; 22e18b890bSChristoph Lameter static struct kmem_cache *raw_inode_slab; 23e18b890bSChristoph Lameter static struct kmem_cache *tmp_dnode_info_slab; 24e18b890bSChristoph Lameter static struct kmem_cache *raw_node_ref_slab; 25e18b890bSChristoph Lameter static struct kmem_cache *node_frag_slab; 26e18b890bSChristoph Lameter static struct kmem_cache *inode_cache_slab; 27aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_XATTR 28e18b890bSChristoph Lameter static struct kmem_cache *xattr_datum_cache; 29e18b890bSChristoph Lameter static struct kmem_cache *xattr_ref_cache; 30aa98d7cfSKaiGai Kohei #endif 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds int __init jffs2_create_slab_caches(void) 331da177e4SLinus Torvalds { 341da177e4SLinus Torvalds full_dnode_slab = kmem_cache_create("jffs2_full_dnode", 351da177e4SLinus Torvalds sizeof(struct jffs2_full_dnode), 3620c2df83SPaul Mundt 0, 0, NULL); 371da177e4SLinus Torvalds if (!full_dnode_slab) 381da177e4SLinus Torvalds goto err; 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", 411da177e4SLinus Torvalds sizeof(struct jffs2_raw_dirent), 4220c2df83SPaul Mundt 0, 0, NULL); 431da177e4SLinus Torvalds if (!raw_dirent_slab) 441da177e4SLinus Torvalds goto err; 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds raw_inode_slab = kmem_cache_create("jffs2_raw_inode", 471da177e4SLinus Torvalds sizeof(struct jffs2_raw_inode), 4820c2df83SPaul Mundt 0, 0, NULL); 491da177e4SLinus Torvalds if (!raw_inode_slab) 501da177e4SLinus Torvalds goto err; 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", 531da177e4SLinus Torvalds sizeof(struct jffs2_tmp_dnode_info), 5420c2df83SPaul Mundt 0, 0, NULL); 551da177e4SLinus Torvalds if (!tmp_dnode_info_slab) 561da177e4SLinus Torvalds goto err; 571da177e4SLinus Torvalds 589bfeb691SDavid Woodhouse raw_node_ref_slab = kmem_cache_create("jffs2_refblock", 599bfeb691SDavid Woodhouse sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK + 1), 6020c2df83SPaul Mundt 0, 0, NULL); 611da177e4SLinus Torvalds if (!raw_node_ref_slab) 621da177e4SLinus Torvalds goto err; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds node_frag_slab = kmem_cache_create("jffs2_node_frag", 651da177e4SLinus Torvalds sizeof(struct jffs2_node_frag), 6620c2df83SPaul Mundt 0, 0, NULL); 671da177e4SLinus Torvalds if (!node_frag_slab) 681da177e4SLinus Torvalds goto err; 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds inode_cache_slab = kmem_cache_create("jffs2_inode_cache", 711da177e4SLinus Torvalds sizeof(struct jffs2_inode_cache), 7220c2df83SPaul Mundt 0, 0, NULL); 73aa98d7cfSKaiGai Kohei if (!inode_cache_slab) 74aa98d7cfSKaiGai Kohei goto err; 75aa98d7cfSKaiGai Kohei 76aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_XATTR 77aa98d7cfSKaiGai Kohei xattr_datum_cache = kmem_cache_create("jffs2_xattr_datum", 78aa98d7cfSKaiGai Kohei sizeof(struct jffs2_xattr_datum), 7920c2df83SPaul Mundt 0, 0, NULL); 80aa98d7cfSKaiGai Kohei if (!xattr_datum_cache) 81aa98d7cfSKaiGai Kohei goto err; 82aa98d7cfSKaiGai Kohei 83aa98d7cfSKaiGai Kohei xattr_ref_cache = kmem_cache_create("jffs2_xattr_ref", 84aa98d7cfSKaiGai Kohei sizeof(struct jffs2_xattr_ref), 8520c2df83SPaul Mundt 0, 0, NULL); 86aa98d7cfSKaiGai Kohei if (!xattr_ref_cache) 87aa98d7cfSKaiGai Kohei goto err; 88aa98d7cfSKaiGai Kohei #endif 89aa98d7cfSKaiGai Kohei 901da177e4SLinus Torvalds return 0; 911da177e4SLinus Torvalds err: 921da177e4SLinus Torvalds jffs2_destroy_slab_caches(); 931da177e4SLinus Torvalds return -ENOMEM; 941da177e4SLinus Torvalds } 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds void jffs2_destroy_slab_caches(void) 971da177e4SLinus Torvalds { 981da177e4SLinus Torvalds if(full_dnode_slab) 991da177e4SLinus Torvalds kmem_cache_destroy(full_dnode_slab); 1001da177e4SLinus Torvalds if(raw_dirent_slab) 1011da177e4SLinus Torvalds kmem_cache_destroy(raw_dirent_slab); 1021da177e4SLinus Torvalds if(raw_inode_slab) 1031da177e4SLinus Torvalds kmem_cache_destroy(raw_inode_slab); 1041da177e4SLinus Torvalds if(tmp_dnode_info_slab) 1051da177e4SLinus Torvalds kmem_cache_destroy(tmp_dnode_info_slab); 1061da177e4SLinus Torvalds if(raw_node_ref_slab) 1071da177e4SLinus Torvalds kmem_cache_destroy(raw_node_ref_slab); 1081da177e4SLinus Torvalds if(node_frag_slab) 1091da177e4SLinus Torvalds kmem_cache_destroy(node_frag_slab); 1101da177e4SLinus Torvalds if(inode_cache_slab) 1111da177e4SLinus Torvalds kmem_cache_destroy(inode_cache_slab); 112aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_XATTR 113aa98d7cfSKaiGai Kohei if (xattr_datum_cache) 114aa98d7cfSKaiGai Kohei kmem_cache_destroy(xattr_datum_cache); 115aa98d7cfSKaiGai Kohei if (xattr_ref_cache) 116aa98d7cfSKaiGai Kohei kmem_cache_destroy(xattr_ref_cache); 117aa98d7cfSKaiGai Kohei #endif 1181da177e4SLinus Torvalds } 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize) 1211da177e4SLinus Torvalds { 122f538c96bSArtem B. Bityutskiy struct jffs2_full_dirent *ret; 123f538c96bSArtem B. Bityutskiy ret = kmalloc(sizeof(struct jffs2_full_dirent) + namesize, GFP_KERNEL); 124733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", ret); 125f538c96bSArtem B. Bityutskiy return ret; 1261da177e4SLinus Torvalds } 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds void jffs2_free_full_dirent(struct jffs2_full_dirent *x) 1291da177e4SLinus Torvalds { 130733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 1311da177e4SLinus Torvalds kfree(x); 1321da177e4SLinus Torvalds } 1331da177e4SLinus Torvalds 1341da177e4SLinus Torvalds struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) 1351da177e4SLinus Torvalds { 136f538c96bSArtem B. Bityutskiy struct jffs2_full_dnode *ret; 137f538c96bSArtem B. Bityutskiy ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); 138733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", ret); 1391da177e4SLinus Torvalds return ret; 1401da177e4SLinus Torvalds } 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds void jffs2_free_full_dnode(struct jffs2_full_dnode *x) 1431da177e4SLinus Torvalds { 144733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 1451da177e4SLinus Torvalds kmem_cache_free(full_dnode_slab, x); 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) 1491da177e4SLinus Torvalds { 150f538c96bSArtem B. Bityutskiy struct jffs2_raw_dirent *ret; 151f538c96bSArtem B. Bityutskiy ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); 152733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", ret); 1531da177e4SLinus Torvalds return ret; 1541da177e4SLinus Torvalds } 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x) 1571da177e4SLinus Torvalds { 158733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 1591da177e4SLinus Torvalds kmem_cache_free(raw_dirent_slab, x); 1601da177e4SLinus Torvalds } 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) 1631da177e4SLinus Torvalds { 164f538c96bSArtem B. Bityutskiy struct jffs2_raw_inode *ret; 165f538c96bSArtem B. Bityutskiy ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); 166733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", ret); 1671da177e4SLinus Torvalds return ret; 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds void jffs2_free_raw_inode(struct jffs2_raw_inode *x) 1711da177e4SLinus Torvalds { 172733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 1731da177e4SLinus Torvalds kmem_cache_free(raw_inode_slab, x); 1741da177e4SLinus Torvalds } 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) 1771da177e4SLinus Torvalds { 178f538c96bSArtem B. Bityutskiy struct jffs2_tmp_dnode_info *ret; 179f538c96bSArtem B. Bityutskiy ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); 180733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", 181f538c96bSArtem B. Bityutskiy ret); 1821da177e4SLinus Torvalds return ret; 1831da177e4SLinus Torvalds } 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) 1861da177e4SLinus Torvalds { 187733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 1881da177e4SLinus Torvalds kmem_cache_free(tmp_dnode_info_slab, x); 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds 191c05d52c7SAdrian Bunk static struct jffs2_raw_node_ref *jffs2_alloc_refblock(void) 1921da177e4SLinus Torvalds { 193f538c96bSArtem B. Bityutskiy struct jffs2_raw_node_ref *ret; 1949bfeb691SDavid Woodhouse 195f538c96bSArtem B. Bityutskiy ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); 1969bfeb691SDavid Woodhouse if (ret) { 1979bfeb691SDavid Woodhouse int i = 0; 1989bfeb691SDavid Woodhouse for (i=0; i < REFS_PER_BLOCK; i++) { 1999bfeb691SDavid Woodhouse ret[i].flash_offset = REF_EMPTY_NODE; 2009bfeb691SDavid Woodhouse ret[i].next_in_ino = NULL; 2019bfeb691SDavid Woodhouse } 2029bfeb691SDavid Woodhouse ret[i].flash_offset = REF_LINK_NODE; 2039bfeb691SDavid Woodhouse ret[i].next_in_ino = NULL; 2049bfeb691SDavid Woodhouse } 2051da177e4SLinus Torvalds return ret; 2061da177e4SLinus Torvalds } 2071da177e4SLinus Torvalds 2089bfeb691SDavid Woodhouse int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, 2099bfeb691SDavid Woodhouse struct jffs2_eraseblock *jeb, int nr) 2109bfeb691SDavid Woodhouse { 2119bfeb691SDavid Woodhouse struct jffs2_raw_node_ref **p, *ref; 2129bfeb691SDavid Woodhouse int i = nr; 2139bfeb691SDavid Woodhouse 2149bfeb691SDavid Woodhouse dbg_memalloc("%d\n", nr); 2159bfeb691SDavid Woodhouse 2169bfeb691SDavid Woodhouse p = &jeb->last_node; 2179bfeb691SDavid Woodhouse ref = *p; 2189bfeb691SDavid Woodhouse 2199bfeb691SDavid Woodhouse dbg_memalloc("Reserving %d refs for block @0x%08x\n", nr, jeb->offset); 2209bfeb691SDavid Woodhouse 2219bfeb691SDavid Woodhouse /* If jeb->last_node is really a valid node then skip over it */ 2229bfeb691SDavid Woodhouse if (ref && ref->flash_offset != REF_EMPTY_NODE) 2239bfeb691SDavid Woodhouse ref++; 2249bfeb691SDavid Woodhouse 2259bfeb691SDavid Woodhouse while (i) { 2269bfeb691SDavid Woodhouse if (!ref) { 2279bfeb691SDavid Woodhouse dbg_memalloc("Allocating new refblock linked from %p\n", p); 2289bfeb691SDavid Woodhouse ref = *p = jffs2_alloc_refblock(); 2299bfeb691SDavid Woodhouse if (!ref) 2309bfeb691SDavid Woodhouse return -ENOMEM; 2319bfeb691SDavid Woodhouse } 2329bfeb691SDavid Woodhouse if (ref->flash_offset == REF_LINK_NODE) { 2339bfeb691SDavid Woodhouse p = &ref->next_in_ino; 2349bfeb691SDavid Woodhouse ref = *p; 2359bfeb691SDavid Woodhouse continue; 2369bfeb691SDavid Woodhouse } 2379bfeb691SDavid Woodhouse i--; 2389bfeb691SDavid Woodhouse ref++; 2399bfeb691SDavid Woodhouse } 2409bfeb691SDavid Woodhouse jeb->allocated_refs = nr; 2419bfeb691SDavid Woodhouse 2429bfeb691SDavid Woodhouse dbg_memalloc("Reserved %d refs for block @0x%08x, last_node is %p (%08x,%p)\n", 2439bfeb691SDavid Woodhouse nr, jeb->offset, jeb->last_node, jeb->last_node->flash_offset, 2449bfeb691SDavid Woodhouse jeb->last_node->next_in_ino); 2459bfeb691SDavid Woodhouse 2469bfeb691SDavid Woodhouse return 0; 2479bfeb691SDavid Woodhouse } 2489bfeb691SDavid Woodhouse 2499bfeb691SDavid Woodhouse void jffs2_free_refblock(struct jffs2_raw_node_ref *x) 2501da177e4SLinus Torvalds { 251733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 2521da177e4SLinus Torvalds kmem_cache_free(raw_node_ref_slab, x); 2531da177e4SLinus Torvalds } 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds struct jffs2_node_frag *jffs2_alloc_node_frag(void) 2561da177e4SLinus Torvalds { 257f538c96bSArtem B. Bityutskiy struct jffs2_node_frag *ret; 258f538c96bSArtem B. Bityutskiy ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL); 259733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", ret); 2601da177e4SLinus Torvalds return ret; 2611da177e4SLinus Torvalds } 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds void jffs2_free_node_frag(struct jffs2_node_frag *x) 2641da177e4SLinus Torvalds { 265733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 2661da177e4SLinus Torvalds kmem_cache_free(node_frag_slab, x); 2671da177e4SLinus Torvalds } 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) 2701da177e4SLinus Torvalds { 271f538c96bSArtem B. Bityutskiy struct jffs2_inode_cache *ret; 272f538c96bSArtem B. Bityutskiy ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL); 273733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", ret); 2741da177e4SLinus Torvalds return ret; 2751da177e4SLinus Torvalds } 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds void jffs2_free_inode_cache(struct jffs2_inode_cache *x) 2781da177e4SLinus Torvalds { 279733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 2801da177e4SLinus Torvalds kmem_cache_free(inode_cache_slab, x); 2811da177e4SLinus Torvalds } 282aa98d7cfSKaiGai Kohei 283aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_XATTR 284aa98d7cfSKaiGai Kohei struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void) 285aa98d7cfSKaiGai Kohei { 286aa98d7cfSKaiGai Kohei struct jffs2_xattr_datum *xd; 287aa98d7cfSKaiGai Kohei xd = kmem_cache_alloc(xattr_datum_cache, GFP_KERNEL); 288aa98d7cfSKaiGai Kohei dbg_memalloc("%p\n", xd); 289aa98d7cfSKaiGai Kohei 290aa98d7cfSKaiGai Kohei memset(xd, 0, sizeof(struct jffs2_xattr_datum)); 291aa98d7cfSKaiGai Kohei xd->class = RAWNODE_CLASS_XATTR_DATUM; 292c9f700f8SKaiGai Kohei xd->node = (void *)xd; 293aa98d7cfSKaiGai Kohei INIT_LIST_HEAD(&xd->xindex); 294aa98d7cfSKaiGai Kohei return xd; 295aa98d7cfSKaiGai Kohei } 296aa98d7cfSKaiGai Kohei 297aa98d7cfSKaiGai Kohei void jffs2_free_xattr_datum(struct jffs2_xattr_datum *xd) 298aa98d7cfSKaiGai Kohei { 299aa98d7cfSKaiGai Kohei dbg_memalloc("%p\n", xd); 300aa98d7cfSKaiGai Kohei kmem_cache_free(xattr_datum_cache, xd); 301aa98d7cfSKaiGai Kohei } 302aa98d7cfSKaiGai Kohei 303aa98d7cfSKaiGai Kohei struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void) 304aa98d7cfSKaiGai Kohei { 305aa98d7cfSKaiGai Kohei struct jffs2_xattr_ref *ref; 306aa98d7cfSKaiGai Kohei ref = kmem_cache_alloc(xattr_ref_cache, GFP_KERNEL); 307aa98d7cfSKaiGai Kohei dbg_memalloc("%p\n", ref); 308aa98d7cfSKaiGai Kohei 309aa98d7cfSKaiGai Kohei memset(ref, 0, sizeof(struct jffs2_xattr_ref)); 310aa98d7cfSKaiGai Kohei ref->class = RAWNODE_CLASS_XATTR_REF; 311c9f700f8SKaiGai Kohei ref->node = (void *)ref; 312aa98d7cfSKaiGai Kohei return ref; 313aa98d7cfSKaiGai Kohei } 314aa98d7cfSKaiGai Kohei 315aa98d7cfSKaiGai Kohei void jffs2_free_xattr_ref(struct jffs2_xattr_ref *ref) 316aa98d7cfSKaiGai Kohei { 317aa98d7cfSKaiGai Kohei dbg_memalloc("%p\n", ref); 318aa98d7cfSKaiGai Kohei kmem_cache_free(xattr_ref_cache, ref); 319aa98d7cfSKaiGai Kohei } 320aa98d7cfSKaiGai Kohei #endif 321