11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * JFFS2 -- Journalling Flash File System, Version 2. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001-2003 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 * 10182ec4eeSThomas Gleixner * $Id: malloc.c,v 1.31 2005/11/07 11:14:40 gleixner Exp $ 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include <linux/kernel.h> 151da177e4SLinus Torvalds #include <linux/slab.h> 161da177e4SLinus Torvalds #include <linux/init.h> 171da177e4SLinus Torvalds #include <linux/jffs2.h> 181da177e4SLinus Torvalds #include "nodelist.h" 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds /* These are initialised to NULL in the kernel startup code. 211da177e4SLinus Torvalds If you're porting to other operating systems, beware */ 22e18b890bSChristoph Lameter static struct kmem_cache *full_dnode_slab; 23e18b890bSChristoph Lameter static struct kmem_cache *raw_dirent_slab; 24e18b890bSChristoph Lameter static struct kmem_cache *raw_inode_slab; 25e18b890bSChristoph Lameter static struct kmem_cache *tmp_dnode_info_slab; 26e18b890bSChristoph Lameter static struct kmem_cache *raw_node_ref_slab; 27e18b890bSChristoph Lameter static struct kmem_cache *node_frag_slab; 28e18b890bSChristoph Lameter static struct kmem_cache *inode_cache_slab; 29aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_XATTR 30e18b890bSChristoph Lameter static struct kmem_cache *xattr_datum_cache; 31e18b890bSChristoph Lameter static struct kmem_cache *xattr_ref_cache; 32aa98d7cfSKaiGai Kohei #endif 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds int __init jffs2_create_slab_caches(void) 351da177e4SLinus Torvalds { 361da177e4SLinus Torvalds full_dnode_slab = kmem_cache_create("jffs2_full_dnode", 371da177e4SLinus Torvalds sizeof(struct jffs2_full_dnode), 38f538c96bSArtem B. Bityutskiy 0, 0, NULL, NULL); 391da177e4SLinus Torvalds if (!full_dnode_slab) 401da177e4SLinus Torvalds goto err; 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", 431da177e4SLinus Torvalds sizeof(struct jffs2_raw_dirent), 44f538c96bSArtem B. Bityutskiy 0, 0, NULL, NULL); 451da177e4SLinus Torvalds if (!raw_dirent_slab) 461da177e4SLinus Torvalds goto err; 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds raw_inode_slab = kmem_cache_create("jffs2_raw_inode", 491da177e4SLinus Torvalds sizeof(struct jffs2_raw_inode), 50f538c96bSArtem B. Bityutskiy 0, 0, NULL, NULL); 511da177e4SLinus Torvalds if (!raw_inode_slab) 521da177e4SLinus Torvalds goto err; 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", 551da177e4SLinus Torvalds sizeof(struct jffs2_tmp_dnode_info), 56f538c96bSArtem B. Bityutskiy 0, 0, NULL, NULL); 571da177e4SLinus Torvalds if (!tmp_dnode_info_slab) 581da177e4SLinus Torvalds goto err; 591da177e4SLinus Torvalds 609bfeb691SDavid Woodhouse raw_node_ref_slab = kmem_cache_create("jffs2_refblock", 619bfeb691SDavid Woodhouse sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK + 1), 62f538c96bSArtem B. Bityutskiy 0, 0, NULL, NULL); 631da177e4SLinus Torvalds if (!raw_node_ref_slab) 641da177e4SLinus Torvalds goto err; 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds node_frag_slab = kmem_cache_create("jffs2_node_frag", 671da177e4SLinus Torvalds sizeof(struct jffs2_node_frag), 68f538c96bSArtem B. Bityutskiy 0, 0, NULL, NULL); 691da177e4SLinus Torvalds if (!node_frag_slab) 701da177e4SLinus Torvalds goto err; 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds inode_cache_slab = kmem_cache_create("jffs2_inode_cache", 731da177e4SLinus Torvalds sizeof(struct jffs2_inode_cache), 74f538c96bSArtem B. Bityutskiy 0, 0, NULL, NULL); 75aa98d7cfSKaiGai Kohei if (!inode_cache_slab) 76aa98d7cfSKaiGai Kohei goto err; 77aa98d7cfSKaiGai Kohei 78aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_XATTR 79aa98d7cfSKaiGai Kohei xattr_datum_cache = kmem_cache_create("jffs2_xattr_datum", 80aa98d7cfSKaiGai Kohei sizeof(struct jffs2_xattr_datum), 81aa98d7cfSKaiGai Kohei 0, 0, NULL, NULL); 82aa98d7cfSKaiGai Kohei if (!xattr_datum_cache) 83aa98d7cfSKaiGai Kohei goto err; 84aa98d7cfSKaiGai Kohei 85aa98d7cfSKaiGai Kohei xattr_ref_cache = kmem_cache_create("jffs2_xattr_ref", 86aa98d7cfSKaiGai Kohei sizeof(struct jffs2_xattr_ref), 87aa98d7cfSKaiGai Kohei 0, 0, NULL, NULL); 88aa98d7cfSKaiGai Kohei if (!xattr_ref_cache) 89aa98d7cfSKaiGai Kohei goto err; 90aa98d7cfSKaiGai Kohei #endif 91aa98d7cfSKaiGai Kohei 921da177e4SLinus Torvalds return 0; 931da177e4SLinus Torvalds err: 941da177e4SLinus Torvalds jffs2_destroy_slab_caches(); 951da177e4SLinus Torvalds return -ENOMEM; 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds void jffs2_destroy_slab_caches(void) 991da177e4SLinus Torvalds { 1001da177e4SLinus Torvalds if(full_dnode_slab) 1011da177e4SLinus Torvalds kmem_cache_destroy(full_dnode_slab); 1021da177e4SLinus Torvalds if(raw_dirent_slab) 1031da177e4SLinus Torvalds kmem_cache_destroy(raw_dirent_slab); 1041da177e4SLinus Torvalds if(raw_inode_slab) 1051da177e4SLinus Torvalds kmem_cache_destroy(raw_inode_slab); 1061da177e4SLinus Torvalds if(tmp_dnode_info_slab) 1071da177e4SLinus Torvalds kmem_cache_destroy(tmp_dnode_info_slab); 1081da177e4SLinus Torvalds if(raw_node_ref_slab) 1091da177e4SLinus Torvalds kmem_cache_destroy(raw_node_ref_slab); 1101da177e4SLinus Torvalds if(node_frag_slab) 1111da177e4SLinus Torvalds kmem_cache_destroy(node_frag_slab); 1121da177e4SLinus Torvalds if(inode_cache_slab) 1131da177e4SLinus Torvalds kmem_cache_destroy(inode_cache_slab); 114aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_XATTR 115aa98d7cfSKaiGai Kohei if (xattr_datum_cache) 116aa98d7cfSKaiGai Kohei kmem_cache_destroy(xattr_datum_cache); 117aa98d7cfSKaiGai Kohei if (xattr_ref_cache) 118aa98d7cfSKaiGai Kohei kmem_cache_destroy(xattr_ref_cache); 119aa98d7cfSKaiGai Kohei #endif 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize) 1231da177e4SLinus Torvalds { 124f538c96bSArtem B. Bityutskiy struct jffs2_full_dirent *ret; 125f538c96bSArtem B. Bityutskiy ret = kmalloc(sizeof(struct jffs2_full_dirent) + namesize, GFP_KERNEL); 126733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", ret); 127f538c96bSArtem B. Bityutskiy return ret; 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds void jffs2_free_full_dirent(struct jffs2_full_dirent *x) 1311da177e4SLinus Torvalds { 132733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 1331da177e4SLinus Torvalds kfree(x); 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) 1371da177e4SLinus Torvalds { 138f538c96bSArtem B. Bityutskiy struct jffs2_full_dnode *ret; 139f538c96bSArtem B. Bityutskiy ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); 140733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", ret); 1411da177e4SLinus Torvalds return ret; 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds void jffs2_free_full_dnode(struct jffs2_full_dnode *x) 1451da177e4SLinus Torvalds { 146733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 1471da177e4SLinus Torvalds kmem_cache_free(full_dnode_slab, x); 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) 1511da177e4SLinus Torvalds { 152f538c96bSArtem B. Bityutskiy struct jffs2_raw_dirent *ret; 153f538c96bSArtem B. Bityutskiy ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); 154733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", ret); 1551da177e4SLinus Torvalds return ret; 1561da177e4SLinus Torvalds } 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x) 1591da177e4SLinus Torvalds { 160733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 1611da177e4SLinus Torvalds kmem_cache_free(raw_dirent_slab, x); 1621da177e4SLinus Torvalds } 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) 1651da177e4SLinus Torvalds { 166f538c96bSArtem B. Bityutskiy struct jffs2_raw_inode *ret; 167f538c96bSArtem B. Bityutskiy ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); 168733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", ret); 1691da177e4SLinus Torvalds return ret; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds void jffs2_free_raw_inode(struct jffs2_raw_inode *x) 1731da177e4SLinus Torvalds { 174733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 1751da177e4SLinus Torvalds kmem_cache_free(raw_inode_slab, x); 1761da177e4SLinus Torvalds } 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) 1791da177e4SLinus Torvalds { 180f538c96bSArtem B. Bityutskiy struct jffs2_tmp_dnode_info *ret; 181f538c96bSArtem B. Bityutskiy ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); 182733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", 183f538c96bSArtem B. Bityutskiy ret); 1841da177e4SLinus Torvalds return ret; 1851da177e4SLinus Torvalds } 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) 1881da177e4SLinus Torvalds { 189733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 1901da177e4SLinus Torvalds kmem_cache_free(tmp_dnode_info_slab, x); 1911da177e4SLinus Torvalds } 1921da177e4SLinus Torvalds 193c05d52c7SAdrian Bunk static struct jffs2_raw_node_ref *jffs2_alloc_refblock(void) 1941da177e4SLinus Torvalds { 195f538c96bSArtem B. Bityutskiy struct jffs2_raw_node_ref *ret; 1969bfeb691SDavid Woodhouse 197f538c96bSArtem B. Bityutskiy ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); 1989bfeb691SDavid Woodhouse if (ret) { 1999bfeb691SDavid Woodhouse int i = 0; 2009bfeb691SDavid Woodhouse for (i=0; i < REFS_PER_BLOCK; i++) { 2019bfeb691SDavid Woodhouse ret[i].flash_offset = REF_EMPTY_NODE; 2029bfeb691SDavid Woodhouse ret[i].next_in_ino = NULL; 2039bfeb691SDavid Woodhouse } 2049bfeb691SDavid Woodhouse ret[i].flash_offset = REF_LINK_NODE; 2059bfeb691SDavid Woodhouse ret[i].next_in_ino = NULL; 2069bfeb691SDavid Woodhouse } 2071da177e4SLinus Torvalds return ret; 2081da177e4SLinus Torvalds } 2091da177e4SLinus Torvalds 2109bfeb691SDavid Woodhouse int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, 2119bfeb691SDavid Woodhouse struct jffs2_eraseblock *jeb, int nr) 2129bfeb691SDavid Woodhouse { 2139bfeb691SDavid Woodhouse struct jffs2_raw_node_ref **p, *ref; 2149bfeb691SDavid Woodhouse int i = nr; 2159bfeb691SDavid Woodhouse 2169bfeb691SDavid Woodhouse dbg_memalloc("%d\n", nr); 2179bfeb691SDavid Woodhouse 2189bfeb691SDavid Woodhouse p = &jeb->last_node; 2199bfeb691SDavid Woodhouse ref = *p; 2209bfeb691SDavid Woodhouse 2219bfeb691SDavid Woodhouse dbg_memalloc("Reserving %d refs for block @0x%08x\n", nr, jeb->offset); 2229bfeb691SDavid Woodhouse 2239bfeb691SDavid Woodhouse /* If jeb->last_node is really a valid node then skip over it */ 2249bfeb691SDavid Woodhouse if (ref && ref->flash_offset != REF_EMPTY_NODE) 2259bfeb691SDavid Woodhouse ref++; 2269bfeb691SDavid Woodhouse 2279bfeb691SDavid Woodhouse while (i) { 2289bfeb691SDavid Woodhouse if (!ref) { 2299bfeb691SDavid Woodhouse dbg_memalloc("Allocating new refblock linked from %p\n", p); 2309bfeb691SDavid Woodhouse ref = *p = jffs2_alloc_refblock(); 2319bfeb691SDavid Woodhouse if (!ref) 2329bfeb691SDavid Woodhouse return -ENOMEM; 2339bfeb691SDavid Woodhouse } 2349bfeb691SDavid Woodhouse if (ref->flash_offset == REF_LINK_NODE) { 2359bfeb691SDavid Woodhouse p = &ref->next_in_ino; 2369bfeb691SDavid Woodhouse ref = *p; 2379bfeb691SDavid Woodhouse continue; 2389bfeb691SDavid Woodhouse } 2399bfeb691SDavid Woodhouse i--; 2409bfeb691SDavid Woodhouse ref++; 2419bfeb691SDavid Woodhouse } 2429bfeb691SDavid Woodhouse jeb->allocated_refs = nr; 2439bfeb691SDavid Woodhouse 2449bfeb691SDavid Woodhouse dbg_memalloc("Reserved %d refs for block @0x%08x, last_node is %p (%08x,%p)\n", 2459bfeb691SDavid Woodhouse nr, jeb->offset, jeb->last_node, jeb->last_node->flash_offset, 2469bfeb691SDavid Woodhouse jeb->last_node->next_in_ino); 2479bfeb691SDavid Woodhouse 2489bfeb691SDavid Woodhouse return 0; 2499bfeb691SDavid Woodhouse } 2509bfeb691SDavid Woodhouse 2519bfeb691SDavid Woodhouse void jffs2_free_refblock(struct jffs2_raw_node_ref *x) 2521da177e4SLinus Torvalds { 253733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 2541da177e4SLinus Torvalds kmem_cache_free(raw_node_ref_slab, x); 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds struct jffs2_node_frag *jffs2_alloc_node_frag(void) 2581da177e4SLinus Torvalds { 259f538c96bSArtem B. Bityutskiy struct jffs2_node_frag *ret; 260f538c96bSArtem B. Bityutskiy ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL); 261733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", ret); 2621da177e4SLinus Torvalds return ret; 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds void jffs2_free_node_frag(struct jffs2_node_frag *x) 2661da177e4SLinus Torvalds { 267733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 2681da177e4SLinus Torvalds kmem_cache_free(node_frag_slab, x); 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) 2721da177e4SLinus Torvalds { 273f538c96bSArtem B. Bityutskiy struct jffs2_inode_cache *ret; 274f538c96bSArtem B. Bityutskiy ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL); 275733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", ret); 2761da177e4SLinus Torvalds return ret; 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds void jffs2_free_inode_cache(struct jffs2_inode_cache *x) 2801da177e4SLinus Torvalds { 281733802d9SArtem B. Bityutskiy dbg_memalloc("%p\n", x); 2821da177e4SLinus Torvalds kmem_cache_free(inode_cache_slab, x); 2831da177e4SLinus Torvalds } 284aa98d7cfSKaiGai Kohei 285aa98d7cfSKaiGai Kohei #ifdef CONFIG_JFFS2_FS_XATTR 286aa98d7cfSKaiGai Kohei struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void) 287aa98d7cfSKaiGai Kohei { 288aa98d7cfSKaiGai Kohei struct jffs2_xattr_datum *xd; 289aa98d7cfSKaiGai Kohei xd = kmem_cache_alloc(xattr_datum_cache, GFP_KERNEL); 290aa98d7cfSKaiGai Kohei dbg_memalloc("%p\n", xd); 291aa98d7cfSKaiGai Kohei 292aa98d7cfSKaiGai Kohei memset(xd, 0, sizeof(struct jffs2_xattr_datum)); 293aa98d7cfSKaiGai Kohei xd->class = RAWNODE_CLASS_XATTR_DATUM; 294c9f700f8SKaiGai Kohei xd->node = (void *)xd; 295aa98d7cfSKaiGai Kohei INIT_LIST_HEAD(&xd->xindex); 296aa98d7cfSKaiGai Kohei return xd; 297aa98d7cfSKaiGai Kohei } 298aa98d7cfSKaiGai Kohei 299aa98d7cfSKaiGai Kohei void jffs2_free_xattr_datum(struct jffs2_xattr_datum *xd) 300aa98d7cfSKaiGai Kohei { 301aa98d7cfSKaiGai Kohei dbg_memalloc("%p\n", xd); 302aa98d7cfSKaiGai Kohei kmem_cache_free(xattr_datum_cache, xd); 303aa98d7cfSKaiGai Kohei } 304aa98d7cfSKaiGai Kohei 305aa98d7cfSKaiGai Kohei struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void) 306aa98d7cfSKaiGai Kohei { 307aa98d7cfSKaiGai Kohei struct jffs2_xattr_ref *ref; 308aa98d7cfSKaiGai Kohei ref = kmem_cache_alloc(xattr_ref_cache, GFP_KERNEL); 309aa98d7cfSKaiGai Kohei dbg_memalloc("%p\n", ref); 310aa98d7cfSKaiGai Kohei 311aa98d7cfSKaiGai Kohei memset(ref, 0, sizeof(struct jffs2_xattr_ref)); 312aa98d7cfSKaiGai Kohei ref->class = RAWNODE_CLASS_XATTR_REF; 313c9f700f8SKaiGai Kohei ref->node = (void *)ref; 314aa98d7cfSKaiGai Kohei return ref; 315aa98d7cfSKaiGai Kohei } 316aa98d7cfSKaiGai Kohei 317aa98d7cfSKaiGai Kohei void jffs2_free_xattr_ref(struct jffs2_xattr_ref *ref) 318aa98d7cfSKaiGai Kohei { 319aa98d7cfSKaiGai Kohei dbg_memalloc("%p\n", ref); 320aa98d7cfSKaiGai Kohei kmem_cache_free(xattr_ref_cache, ref); 321aa98d7cfSKaiGai Kohei } 322aa98d7cfSKaiGai Kohei #endif 323