2005-04-17 02:20:36 +04:00
/*
* JFFS2 - - Journalling Flash File System , Version 2.
*
2007-04-25 17:16:47 +04:00
* Copyright © 2001 - 2007 Red Hat , Inc .
2005-04-17 02:20:36 +04:00
*
* Created by David Woodhouse < dwmw2 @ infradead . org >
*
* For licensing information , see the file ' LICENCE ' in this directory .
*
*/
2012-02-16 03:56:45 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/init.h>
# include <linux/jffs2.h>
# include "nodelist.h"
/* These are initialised to NULL in the kernel startup code.
If you ' re porting to other operating systems , beware */
2006-12-07 07:33:20 +03:00
static struct kmem_cache * full_dnode_slab ;
static struct kmem_cache * raw_dirent_slab ;
static struct kmem_cache * raw_inode_slab ;
static struct kmem_cache * tmp_dnode_info_slab ;
static struct kmem_cache * raw_node_ref_slab ;
static struct kmem_cache * node_frag_slab ;
static struct kmem_cache * inode_cache_slab ;
2006-05-13 10:09:47 +04:00
# ifdef CONFIG_JFFS2_FS_XATTR
2006-12-07 07:33:20 +03:00
static struct kmem_cache * xattr_datum_cache ;
static struct kmem_cache * xattr_ref_cache ;
2006-05-13 10:09:47 +04:00
# endif
2005-04-17 02:20:36 +04:00
int __init jffs2_create_slab_caches ( void )
{
2005-11-07 14:16:07 +03:00
full_dnode_slab = kmem_cache_create ( " jffs2_full_dnode " ,
2005-04-17 02:20:36 +04:00
sizeof ( struct jffs2_full_dnode ) ,
2007-07-20 05:11:58 +04:00
0 , 0 , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ! full_dnode_slab )
goto err ;
raw_dirent_slab = kmem_cache_create ( " jffs2_raw_dirent " ,
sizeof ( struct jffs2_raw_dirent ) ,
2009-09-20 03:14:01 +04:00
0 , SLAB_HWCACHE_ALIGN , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ! raw_dirent_slab )
goto err ;
raw_inode_slab = kmem_cache_create ( " jffs2_raw_inode " ,
sizeof ( struct jffs2_raw_inode ) ,
2009-09-20 03:14:01 +04:00
0 , SLAB_HWCACHE_ALIGN , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ! raw_inode_slab )
goto err ;
tmp_dnode_info_slab = kmem_cache_create ( " jffs2_tmp_dnode " ,
sizeof ( struct jffs2_tmp_dnode_info ) ,
2007-07-20 05:11:58 +04:00
0 , 0 , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ! tmp_dnode_info_slab )
goto err ;
2006-05-27 00:19:05 +04:00
raw_node_ref_slab = kmem_cache_create ( " jffs2_refblock " ,
sizeof ( struct jffs2_raw_node_ref ) * ( REFS_PER_BLOCK + 1 ) ,
2007-07-20 05:11:58 +04:00
0 , 0 , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ! raw_node_ref_slab )
goto err ;
node_frag_slab = kmem_cache_create ( " jffs2_node_frag " ,
sizeof ( struct jffs2_node_frag ) ,
2007-07-20 05:11:58 +04:00
0 , 0 , NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ! node_frag_slab )
goto err ;
inode_cache_slab = kmem_cache_create ( " jffs2_inode_cache " ,
sizeof ( struct jffs2_inode_cache ) ,
2007-07-20 05:11:58 +04:00
0 , 0 , NULL ) ;
2006-05-13 10:09:47 +04:00
if ( ! inode_cache_slab )
goto err ;
# ifdef CONFIG_JFFS2_FS_XATTR
xattr_datum_cache = kmem_cache_create ( " jffs2_xattr_datum " ,
sizeof ( struct jffs2_xattr_datum ) ,
2007-07-20 05:11:58 +04:00
0 , 0 , NULL ) ;
2006-05-13 10:09:47 +04:00
if ( ! xattr_datum_cache )
goto err ;
xattr_ref_cache = kmem_cache_create ( " jffs2_xattr_ref " ,
sizeof ( struct jffs2_xattr_ref ) ,
2007-07-20 05:11:58 +04:00
0 , 0 , NULL ) ;
2006-05-13 10:09:47 +04:00
if ( ! xattr_ref_cache )
goto err ;
# endif
return 0 ;
2005-04-17 02:20:36 +04:00
err :
jffs2_destroy_slab_caches ( ) ;
return - ENOMEM ;
}
void jffs2_destroy_slab_caches ( void )
{
if ( full_dnode_slab )
kmem_cache_destroy ( full_dnode_slab ) ;
if ( raw_dirent_slab )
kmem_cache_destroy ( raw_dirent_slab ) ;
if ( raw_inode_slab )
kmem_cache_destroy ( raw_inode_slab ) ;
if ( tmp_dnode_info_slab )
kmem_cache_destroy ( tmp_dnode_info_slab ) ;
if ( raw_node_ref_slab )
kmem_cache_destroy ( raw_node_ref_slab ) ;
if ( node_frag_slab )
kmem_cache_destroy ( node_frag_slab ) ;
if ( inode_cache_slab )
kmem_cache_destroy ( inode_cache_slab ) ;
2006-05-13 10:09:47 +04:00
# ifdef CONFIG_JFFS2_FS_XATTR
if ( xattr_datum_cache )
kmem_cache_destroy ( xattr_datum_cache ) ;
if ( xattr_ref_cache )
kmem_cache_destroy ( xattr_ref_cache ) ;
# endif
2005-04-17 02:20:36 +04:00
}
struct jffs2_full_dirent * jffs2_alloc_full_dirent ( int namesize )
{
2005-07-27 18:16:57 +04:00
struct jffs2_full_dirent * ret ;
ret = kmalloc ( sizeof ( struct jffs2_full_dirent ) + namesize , GFP_KERNEL ) ;
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " , ret ) ;
2005-07-27 18:16:57 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
void jffs2_free_full_dirent ( struct jffs2_full_dirent * x )
{
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " , x ) ;
2005-04-17 02:20:36 +04:00
kfree ( x ) ;
}
struct jffs2_full_dnode * jffs2_alloc_full_dnode ( void )
{
2005-07-27 18:16:57 +04:00
struct jffs2_full_dnode * ret ;
ret = kmem_cache_alloc ( full_dnode_slab , GFP_KERNEL ) ;
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " , ret ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
void jffs2_free_full_dnode ( struct jffs2_full_dnode * x )
{
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " , x ) ;
2005-04-17 02:20:36 +04:00
kmem_cache_free ( full_dnode_slab , x ) ;
}
struct jffs2_raw_dirent * jffs2_alloc_raw_dirent ( void )
{
2005-07-27 18:16:57 +04:00
struct jffs2_raw_dirent * ret ;
ret = kmem_cache_alloc ( raw_dirent_slab , GFP_KERNEL ) ;
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " , ret ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
void jffs2_free_raw_dirent ( struct jffs2_raw_dirent * x )
{
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " , x ) ;
2005-04-17 02:20:36 +04:00
kmem_cache_free ( raw_dirent_slab , x ) ;
}
struct jffs2_raw_inode * jffs2_alloc_raw_inode ( void )
{
2005-07-27 18:16:57 +04:00
struct jffs2_raw_inode * ret ;
ret = kmem_cache_alloc ( raw_inode_slab , GFP_KERNEL ) ;
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " , ret ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
void jffs2_free_raw_inode ( struct jffs2_raw_inode * x )
{
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " , x ) ;
2005-04-17 02:20:36 +04:00
kmem_cache_free ( raw_inode_slab , x ) ;
}
struct jffs2_tmp_dnode_info * jffs2_alloc_tmp_dnode_info ( void )
{
2005-07-27 18:16:57 +04:00
struct jffs2_tmp_dnode_info * ret ;
ret = kmem_cache_alloc ( tmp_dnode_info_slab , GFP_KERNEL ) ;
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " ,
2005-07-27 18:16:57 +04:00
ret ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
void jffs2_free_tmp_dnode_info ( struct jffs2_tmp_dnode_info * x )
{
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " , x ) ;
2005-04-17 02:20:36 +04:00
kmem_cache_free ( tmp_dnode_info_slab , x ) ;
}
2006-06-22 14:03:35 +04:00
static struct jffs2_raw_node_ref * jffs2_alloc_refblock ( void )
2006-05-27 00:19:05 +04:00
{
struct jffs2_raw_node_ref * ret ;
ret = kmem_cache_alloc ( raw_node_ref_slab , GFP_KERNEL ) ;
if ( ret ) {
int i = 0 ;
for ( i = 0 ; i < REFS_PER_BLOCK ; i + + ) {
ret [ i ] . flash_offset = REF_EMPTY_NODE ;
ret [ i ] . next_in_ino = NULL ;
}
ret [ i ] . flash_offset = REF_LINK_NODE ;
ret [ i ] . next_in_ino = NULL ;
}
return ret ;
}
2006-05-25 04:50:35 +04:00
int jffs2_prealloc_raw_node_refs ( struct jffs2_sb_info * c ,
struct jffs2_eraseblock * jeb , int nr )
2006-05-24 05:04:45 +04:00
{
2006-05-27 00:19:05 +04:00
struct jffs2_raw_node_ref * * p , * ref ;
int i = nr ;
2006-05-24 05:04:45 +04:00
dbg_memalloc ( " %d \n " , nr ) ;
2006-05-27 00:19:05 +04:00
p = & jeb - > last_node ;
ref = * p ;
dbg_memalloc ( " Reserving %d refs for block @0x%08x \n " , nr , jeb - > offset ) ;
/* If jeb->last_node is really a valid node then skip over it */
if ( ref & & ref - > flash_offset ! = REF_EMPTY_NODE )
ref + + ;
while ( i ) {
if ( ! ref ) {
dbg_memalloc ( " Allocating new refblock linked from %p \n " , p ) ;
ref = * p = jffs2_alloc_refblock ( ) ;
if ( ! ref )
return - ENOMEM ;
}
if ( ref - > flash_offset = = REF_LINK_NODE ) {
p = & ref - > next_in_ino ;
ref = * p ;
continue ;
}
i - - ;
ref + + ;
2006-05-24 05:04:45 +04:00
}
2006-05-27 00:19:05 +04:00
jeb - > allocated_refs = nr ;
2006-05-24 05:04:45 +04:00
2006-05-27 00:19:05 +04:00
dbg_memalloc ( " Reserved %d refs for block @0x%08x, last_node is %p (%08x,%p) \n " ,
nr , jeb - > offset , jeb - > last_node , jeb - > last_node - > flash_offset ,
jeb - > last_node - > next_in_ino ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-05-27 00:19:05 +04:00
void jffs2_free_refblock ( struct jffs2_raw_node_ref * x )
2005-04-17 02:20:36 +04:00
{
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " , x ) ;
2005-04-17 02:20:36 +04:00
kmem_cache_free ( raw_node_ref_slab , x ) ;
}
struct jffs2_node_frag * jffs2_alloc_node_frag ( void )
{
2005-07-27 18:16:57 +04:00
struct jffs2_node_frag * ret ;
ret = kmem_cache_alloc ( node_frag_slab , GFP_KERNEL ) ;
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " , ret ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
void jffs2_free_node_frag ( struct jffs2_node_frag * x )
{
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " , x ) ;
2005-04-17 02:20:36 +04:00
kmem_cache_free ( node_frag_slab , x ) ;
}
struct jffs2_inode_cache * jffs2_alloc_inode_cache ( void )
{
2005-07-27 18:16:57 +04:00
struct jffs2_inode_cache * ret ;
ret = kmem_cache_alloc ( inode_cache_slab , GFP_KERNEL ) ;
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " , ret ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
void jffs2_free_inode_cache ( struct jffs2_inode_cache * x )
{
2005-09-22 15:25:00 +04:00
dbg_memalloc ( " %p \n " , x ) ;
2005-04-17 02:20:36 +04:00
kmem_cache_free ( inode_cache_slab , x ) ;
}
2006-05-13 10:09:47 +04:00
# ifdef CONFIG_JFFS2_FS_XATTR
struct jffs2_xattr_datum * jffs2_alloc_xattr_datum ( void )
{
struct jffs2_xattr_datum * xd ;
2009-03-04 23:01:35 +03:00
xd = kmem_cache_zalloc ( xattr_datum_cache , GFP_KERNEL ) ;
2006-05-13 10:09:47 +04:00
dbg_memalloc ( " %p \n " , xd ) ;
xd - > class = RAWNODE_CLASS_XATTR_DATUM ;
2006-06-11 05:35:15 +04:00
xd - > node = ( void * ) xd ;
2006-05-13 10:09:47 +04:00
INIT_LIST_HEAD ( & xd - > xindex ) ;
return xd ;
}
void jffs2_free_xattr_datum ( struct jffs2_xattr_datum * xd )
{
dbg_memalloc ( " %p \n " , xd ) ;
kmem_cache_free ( xattr_datum_cache , xd ) ;
}
struct jffs2_xattr_ref * jffs2_alloc_xattr_ref ( void )
{
struct jffs2_xattr_ref * ref ;
2009-03-04 23:01:35 +03:00
ref = kmem_cache_zalloc ( xattr_ref_cache , GFP_KERNEL ) ;
2006-05-13 10:09:47 +04:00
dbg_memalloc ( " %p \n " , ref ) ;
ref - > class = RAWNODE_CLASS_XATTR_REF ;
2006-06-11 05:35:15 +04:00
ref - > node = ( void * ) ref ;
2006-05-13 10:09:47 +04:00
return ref ;
}
void jffs2_free_xattr_ref ( struct jffs2_xattr_ref * ref )
{
dbg_memalloc ( " %p \n " , ref ) ;
kmem_cache_free ( xattr_ref_cache , ref ) ;
}
# endif