162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * JFFS2 -- Journalling Flash File System, Version 2. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright © 2001-2007 Red Hat, Inc. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Created by David Woodhouse <dwmw2@infradead.org> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * For licensing information, see the file 'LICENCE' in this directory. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/init.h> 1762306a36Sopenharmony_ci#include <linux/jffs2.h> 1862306a36Sopenharmony_ci#include "nodelist.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* These are initialised to NULL in the kernel startup code. 2162306a36Sopenharmony_ci If you're porting to other operating systems, beware */ 2262306a36Sopenharmony_cistatic struct kmem_cache *full_dnode_slab; 2362306a36Sopenharmony_cistatic struct kmem_cache *raw_dirent_slab; 2462306a36Sopenharmony_cistatic struct kmem_cache *raw_inode_slab; 2562306a36Sopenharmony_cistatic struct kmem_cache *tmp_dnode_info_slab; 2662306a36Sopenharmony_cistatic struct kmem_cache *raw_node_ref_slab; 2762306a36Sopenharmony_cistatic struct kmem_cache *node_frag_slab; 2862306a36Sopenharmony_cistatic struct kmem_cache *inode_cache_slab; 2962306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR 3062306a36Sopenharmony_cistatic struct kmem_cache *xattr_datum_cache; 3162306a36Sopenharmony_cistatic struct kmem_cache *xattr_ref_cache; 3262306a36Sopenharmony_ci#endif 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ciint __init jffs2_create_slab_caches(void) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci full_dnode_slab = kmem_cache_create("jffs2_full_dnode", 3762306a36Sopenharmony_ci sizeof(struct jffs2_full_dnode), 3862306a36Sopenharmony_ci 0, 0, NULL); 3962306a36Sopenharmony_ci if (!full_dnode_slab) 4062306a36Sopenharmony_ci goto err; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", 4362306a36Sopenharmony_ci sizeof(struct jffs2_raw_dirent), 4462306a36Sopenharmony_ci 0, SLAB_HWCACHE_ALIGN, NULL); 4562306a36Sopenharmony_ci if (!raw_dirent_slab) 4662306a36Sopenharmony_ci goto err; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci raw_inode_slab = kmem_cache_create("jffs2_raw_inode", 4962306a36Sopenharmony_ci sizeof(struct jffs2_raw_inode), 5062306a36Sopenharmony_ci 0, SLAB_HWCACHE_ALIGN, NULL); 5162306a36Sopenharmony_ci if (!raw_inode_slab) 5262306a36Sopenharmony_ci goto err; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", 5562306a36Sopenharmony_ci sizeof(struct jffs2_tmp_dnode_info), 5662306a36Sopenharmony_ci 0, 0, NULL); 5762306a36Sopenharmony_ci if (!tmp_dnode_info_slab) 5862306a36Sopenharmony_ci goto err; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci raw_node_ref_slab = kmem_cache_create("jffs2_refblock", 6162306a36Sopenharmony_ci sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK + 1), 6262306a36Sopenharmony_ci 0, 0, NULL); 6362306a36Sopenharmony_ci if (!raw_node_ref_slab) 6462306a36Sopenharmony_ci goto err; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci node_frag_slab = kmem_cache_create("jffs2_node_frag", 6762306a36Sopenharmony_ci sizeof(struct jffs2_node_frag), 6862306a36Sopenharmony_ci 0, 0, NULL); 6962306a36Sopenharmony_ci if (!node_frag_slab) 7062306a36Sopenharmony_ci goto err; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci inode_cache_slab = kmem_cache_create("jffs2_inode_cache", 7362306a36Sopenharmony_ci sizeof(struct jffs2_inode_cache), 7462306a36Sopenharmony_ci 0, 0, NULL); 7562306a36Sopenharmony_ci if (!inode_cache_slab) 7662306a36Sopenharmony_ci goto err; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR 7962306a36Sopenharmony_ci xattr_datum_cache = kmem_cache_create("jffs2_xattr_datum", 8062306a36Sopenharmony_ci sizeof(struct jffs2_xattr_datum), 8162306a36Sopenharmony_ci 0, 0, NULL); 8262306a36Sopenharmony_ci if (!xattr_datum_cache) 8362306a36Sopenharmony_ci goto err; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci xattr_ref_cache = kmem_cache_create("jffs2_xattr_ref", 8662306a36Sopenharmony_ci sizeof(struct jffs2_xattr_ref), 8762306a36Sopenharmony_ci 0, 0, NULL); 8862306a36Sopenharmony_ci if (!xattr_ref_cache) 8962306a36Sopenharmony_ci goto err; 9062306a36Sopenharmony_ci#endif 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci err: 9462306a36Sopenharmony_ci jffs2_destroy_slab_caches(); 9562306a36Sopenharmony_ci return -ENOMEM; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_civoid jffs2_destroy_slab_caches(void) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci kmem_cache_destroy(full_dnode_slab); 10162306a36Sopenharmony_ci kmem_cache_destroy(raw_dirent_slab); 10262306a36Sopenharmony_ci kmem_cache_destroy(raw_inode_slab); 10362306a36Sopenharmony_ci kmem_cache_destroy(tmp_dnode_info_slab); 10462306a36Sopenharmony_ci kmem_cache_destroy(raw_node_ref_slab); 10562306a36Sopenharmony_ci kmem_cache_destroy(node_frag_slab); 10662306a36Sopenharmony_ci kmem_cache_destroy(inode_cache_slab); 10762306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR 10862306a36Sopenharmony_ci kmem_cache_destroy(xattr_datum_cache); 10962306a36Sopenharmony_ci kmem_cache_destroy(xattr_ref_cache); 11062306a36Sopenharmony_ci#endif 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistruct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct jffs2_full_dirent *ret; 11662306a36Sopenharmony_ci ret = kmalloc(sizeof(struct jffs2_full_dirent) + namesize, GFP_KERNEL); 11762306a36Sopenharmony_ci dbg_memalloc("%p\n", ret); 11862306a36Sopenharmony_ci return ret; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_civoid jffs2_free_full_dirent(struct jffs2_full_dirent *x) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci dbg_memalloc("%p\n", x); 12462306a36Sopenharmony_ci kfree(x); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistruct jffs2_full_dnode *jffs2_alloc_full_dnode(void) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct jffs2_full_dnode *ret; 13062306a36Sopenharmony_ci ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); 13162306a36Sopenharmony_ci dbg_memalloc("%p\n", ret); 13262306a36Sopenharmony_ci return ret; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_civoid jffs2_free_full_dnode(struct jffs2_full_dnode *x) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci dbg_memalloc("%p\n", x); 13862306a36Sopenharmony_ci kmem_cache_free(full_dnode_slab, x); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistruct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct jffs2_raw_dirent *ret; 14462306a36Sopenharmony_ci ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); 14562306a36Sopenharmony_ci dbg_memalloc("%p\n", ret); 14662306a36Sopenharmony_ci return ret; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_civoid jffs2_free_raw_dirent(struct jffs2_raw_dirent *x) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci dbg_memalloc("%p\n", x); 15262306a36Sopenharmony_ci kmem_cache_free(raw_dirent_slab, x); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistruct jffs2_raw_inode *jffs2_alloc_raw_inode(void) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct jffs2_raw_inode *ret; 15862306a36Sopenharmony_ci ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); 15962306a36Sopenharmony_ci dbg_memalloc("%p\n", ret); 16062306a36Sopenharmony_ci return ret; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_civoid jffs2_free_raw_inode(struct jffs2_raw_inode *x) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci dbg_memalloc("%p\n", x); 16662306a36Sopenharmony_ci kmem_cache_free(raw_inode_slab, x); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistruct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct jffs2_tmp_dnode_info *ret; 17262306a36Sopenharmony_ci ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); 17362306a36Sopenharmony_ci dbg_memalloc("%p\n", 17462306a36Sopenharmony_ci ret); 17562306a36Sopenharmony_ci return ret; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_civoid jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci dbg_memalloc("%p\n", x); 18162306a36Sopenharmony_ci kmem_cache_free(tmp_dnode_info_slab, x); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic struct jffs2_raw_node_ref *jffs2_alloc_refblock(void) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct jffs2_raw_node_ref *ret; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); 18962306a36Sopenharmony_ci if (ret) { 19062306a36Sopenharmony_ci int i = 0; 19162306a36Sopenharmony_ci for (i=0; i < REFS_PER_BLOCK; i++) { 19262306a36Sopenharmony_ci ret[i].flash_offset = REF_EMPTY_NODE; 19362306a36Sopenharmony_ci ret[i].next_in_ino = NULL; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci ret[i].flash_offset = REF_LINK_NODE; 19662306a36Sopenharmony_ci ret[i].next_in_ino = NULL; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci return ret; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ciint jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, 20262306a36Sopenharmony_ci struct jffs2_eraseblock *jeb, int nr) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci struct jffs2_raw_node_ref **p, *ref; 20562306a36Sopenharmony_ci int i = nr; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci dbg_memalloc("%d\n", nr); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci p = &jeb->last_node; 21062306a36Sopenharmony_ci ref = *p; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci dbg_memalloc("Reserving %d refs for block @0x%08x\n", nr, jeb->offset); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* If jeb->last_node is really a valid node then skip over it */ 21562306a36Sopenharmony_ci if (ref && ref->flash_offset != REF_EMPTY_NODE) 21662306a36Sopenharmony_ci ref++; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci while (i) { 21962306a36Sopenharmony_ci if (!ref) { 22062306a36Sopenharmony_ci dbg_memalloc("Allocating new refblock linked from %p\n", p); 22162306a36Sopenharmony_ci ref = *p = jffs2_alloc_refblock(); 22262306a36Sopenharmony_ci if (!ref) 22362306a36Sopenharmony_ci return -ENOMEM; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci if (ref->flash_offset == REF_LINK_NODE) { 22662306a36Sopenharmony_ci p = &ref->next_in_ino; 22762306a36Sopenharmony_ci ref = *p; 22862306a36Sopenharmony_ci continue; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci i--; 23162306a36Sopenharmony_ci ref++; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci jeb->allocated_refs = nr; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci dbg_memalloc("Reserved %d refs for block @0x%08x, last_node is %p (%08x,%p)\n", 23662306a36Sopenharmony_ci nr, jeb->offset, jeb->last_node, jeb->last_node->flash_offset, 23762306a36Sopenharmony_ci jeb->last_node->next_in_ino); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return 0; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_civoid jffs2_free_refblock(struct jffs2_raw_node_ref *x) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci dbg_memalloc("%p\n", x); 24562306a36Sopenharmony_ci kmem_cache_free(raw_node_ref_slab, x); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistruct jffs2_node_frag *jffs2_alloc_node_frag(void) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct jffs2_node_frag *ret; 25162306a36Sopenharmony_ci ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL); 25262306a36Sopenharmony_ci dbg_memalloc("%p\n", ret); 25362306a36Sopenharmony_ci return ret; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_civoid jffs2_free_node_frag(struct jffs2_node_frag *x) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci dbg_memalloc("%p\n", x); 25962306a36Sopenharmony_ci kmem_cache_free(node_frag_slab, x); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistruct jffs2_inode_cache *jffs2_alloc_inode_cache(void) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct jffs2_inode_cache *ret; 26562306a36Sopenharmony_ci ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL); 26662306a36Sopenharmony_ci dbg_memalloc("%p\n", ret); 26762306a36Sopenharmony_ci return ret; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_civoid jffs2_free_inode_cache(struct jffs2_inode_cache *x) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci dbg_memalloc("%p\n", x); 27362306a36Sopenharmony_ci kmem_cache_free(inode_cache_slab, x); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci#ifdef CONFIG_JFFS2_FS_XATTR 27762306a36Sopenharmony_cistruct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci struct jffs2_xattr_datum *xd; 28062306a36Sopenharmony_ci xd = kmem_cache_zalloc(xattr_datum_cache, GFP_KERNEL); 28162306a36Sopenharmony_ci dbg_memalloc("%p\n", xd); 28262306a36Sopenharmony_ci if (!xd) 28362306a36Sopenharmony_ci return NULL; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci xd->class = RAWNODE_CLASS_XATTR_DATUM; 28662306a36Sopenharmony_ci xd->node = (void *)xd; 28762306a36Sopenharmony_ci INIT_LIST_HEAD(&xd->xindex); 28862306a36Sopenharmony_ci return xd; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_civoid jffs2_free_xattr_datum(struct jffs2_xattr_datum *xd) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci dbg_memalloc("%p\n", xd); 29462306a36Sopenharmony_ci kmem_cache_free(xattr_datum_cache, xd); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistruct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct jffs2_xattr_ref *ref; 30062306a36Sopenharmony_ci ref = kmem_cache_zalloc(xattr_ref_cache, GFP_KERNEL); 30162306a36Sopenharmony_ci dbg_memalloc("%p\n", ref); 30262306a36Sopenharmony_ci if (!ref) 30362306a36Sopenharmony_ci return NULL; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci ref->class = RAWNODE_CLASS_XATTR_REF; 30662306a36Sopenharmony_ci ref->node = (void *)ref; 30762306a36Sopenharmony_ci return ref; 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_civoid jffs2_free_xattr_ref(struct jffs2_xattr_ref *ref) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci dbg_memalloc("%p\n", ref); 31362306a36Sopenharmony_ci kmem_cache_free(xattr_ref_cache, ref); 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci#endif 316