2009-04-07 06:01:24 +04:00
/*
* btree . c - NILFS B - tree .
*
* Copyright ( C ) 2005 - 2008 Nippon Telegraph and Telephone Corporation .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
2016-05-24 02:23:09 +03:00
* Written by Koji Sato .
2009-04-07 06:01:24 +04:00
*/
# include <linux/slab.h>
# include <linux/string.h>
# include <linux/errno.h>
# include <linux/pagevec.h>
# include "nilfs.h"
# include "page.h"
# include "btnode.h"
# include "btree.h"
# include "alloc.h"
2009-05-24 21:47:14 +04:00
# include "dat.h"
2009-04-07 06:01:24 +04:00
2015-02-28 02:51:56 +03:00
static void __nilfs_btree_init ( struct nilfs_bmap * bmap ) ;
2010-04-02 13:36:34 +04:00
static struct nilfs_btree_path * nilfs_btree_alloc_path ( void )
2009-04-07 06:01:24 +04:00
{
2010-04-02 13:36:34 +04:00
struct nilfs_btree_path * path ;
int level = NILFS_BTREE_LEVEL_DATA ;
2009-04-07 06:01:24 +04:00
2010-04-02 13:36:34 +04:00
path = kmem_cache_alloc ( nilfs_btree_path_cache , GFP_NOFS ) ;
if ( path = = NULL )
goto out ;
2009-04-07 06:01:24 +04:00
2010-04-02 13:36:34 +04:00
for ( ; level < NILFS_BTREE_LEVEL_MAX ; level + + ) {
2009-04-07 06:01:24 +04:00
path [ level ] . bp_bh = NULL ;
path [ level ] . bp_sib_bh = NULL ;
path [ level ] . bp_index = 0 ;
path [ level ] . bp_oldreq . bpr_ptr = NILFS_BMAP_INVALID_PTR ;
path [ level ] . bp_newreq . bpr_ptr = NILFS_BMAP_INVALID_PTR ;
path [ level ] . bp_op = NULL ;
}
2010-04-02 13:36:34 +04:00
out :
return path ;
}
2010-04-02 14:35:00 +04:00
static void nilfs_btree_free_path ( struct nilfs_btree_path * path )
2010-04-02 13:36:34 +04:00
{
2010-04-02 14:35:00 +04:00
int level = NILFS_BTREE_LEVEL_DATA ;
2009-04-07 06:01:24 +04:00
2010-04-02 14:35:00 +04:00
for ( ; level < NILFS_BTREE_LEVEL_MAX ; level + + )
2009-08-14 20:54:59 +04:00
brelse ( path [ level ] . bp_bh ) ;
2010-04-02 14:35:00 +04:00
kmem_cache_free ( nilfs_btree_path_cache , path ) ;
2009-04-07 06:01:24 +04:00
}
/*
* B - tree node operations
*/
2010-07-10 14:09:49 +04:00
static int nilfs_btree_get_new_block ( const struct nilfs_bmap * btree ,
2009-05-21 20:07:13 +04:00
__u64 ptr , struct buffer_head * * bhp )
{
2010-07-10 14:09:49 +04:00
struct address_space * btnc = & NILFS_BMAP_I ( btree ) - > i_btnode_cache ;
2009-11-13 10:25:19 +03:00
struct buffer_head * bh ;
2009-05-21 20:07:13 +04:00
2009-11-13 10:25:19 +03:00
bh = nilfs_btnode_create_block ( btnc , ptr ) ;
if ( ! bh )
return - ENOMEM ;
set_buffer_nilfs_volatile ( bh ) ;
* bhp = bh ;
return 0 ;
2009-05-21 20:07:13 +04:00
}
2009-04-07 06:01:24 +04:00
2010-07-13 18:33:55 +04:00
static int nilfs_btree_node_get_flags ( const struct nilfs_btree_node * node )
2009-04-07 06:01:24 +04:00
{
return node - > bn_flags ;
}
2010-07-13 18:33:55 +04:00
static void
2009-08-14 20:14:10 +04:00
nilfs_btree_node_set_flags ( struct nilfs_btree_node * node , int flags )
2009-04-07 06:01:24 +04:00
{
node - > bn_flags = flags ;
}
2010-07-13 18:33:55 +04:00
static int nilfs_btree_node_root ( const struct nilfs_btree_node * node )
2009-04-07 06:01:24 +04:00
{
2009-08-14 20:14:10 +04:00
return nilfs_btree_node_get_flags ( node ) & NILFS_BTREE_NODE_ROOT ;
2009-04-07 06:01:24 +04:00
}
2010-07-13 18:33:55 +04:00
static int nilfs_btree_node_get_level ( const struct nilfs_btree_node * node )
2009-04-07 06:01:24 +04:00
{
return node - > bn_level ;
}
2010-07-13 18:33:55 +04:00
static void
2009-08-14 20:14:10 +04:00
nilfs_btree_node_set_level ( struct nilfs_btree_node * node , int level )
2009-04-07 06:01:24 +04:00
{
node - > bn_level = level ;
}
2010-07-13 18:33:55 +04:00
static int nilfs_btree_node_get_nchildren ( const struct nilfs_btree_node * node )
2009-04-07 06:01:24 +04:00
{
return le16_to_cpu ( node - > bn_nchildren ) ;
}
2010-07-13 18:33:55 +04:00
static void
2009-08-14 20:14:10 +04:00
nilfs_btree_node_set_nchildren ( struct nilfs_btree_node * node , int nchildren )
2009-04-07 06:01:24 +04:00
{
node - > bn_nchildren = cpu_to_le16 ( nchildren ) ;
}
2010-07-13 18:33:55 +04:00
static int nilfs_btree_node_size ( const struct nilfs_bmap * btree )
2009-04-07 06:01:24 +04:00
{
2010-07-10 14:09:49 +04:00
return 1 < < btree - > b_inode - > i_blkbits ;
2009-04-07 06:01:24 +04:00
}
2010-07-13 18:33:53 +04:00
static int nilfs_btree_nchildren_per_block ( const struct nilfs_bmap * btree )
2009-04-07 06:01:24 +04:00
{
2010-07-13 18:33:54 +04:00
return btree - > b_nchildren_per_block ;
2009-04-07 06:01:24 +04:00
}
2010-07-13 18:33:55 +04:00
static __le64 *
2009-08-14 20:14:10 +04:00
nilfs_btree_node_dkeys ( const struct nilfs_btree_node * node )
2009-04-07 06:01:24 +04:00
{
return ( __le64 * ) ( ( char * ) ( node + 1 ) +
2009-08-14 20:14:10 +04:00
( nilfs_btree_node_root ( node ) ?
2009-04-07 06:01:24 +04:00
0 : NILFS_BTREE_NODE_EXTRA_PAD_SIZE ) ) ;
}
2010-07-13 18:33:55 +04:00
static __le64 *
2010-07-13 18:33:53 +04:00
nilfs_btree_node_dptrs ( const struct nilfs_btree_node * node , int ncmax )
2009-04-07 06:01:24 +04:00
{
2010-07-13 18:33:53 +04:00
return ( __le64 * ) ( nilfs_btree_node_dkeys ( node ) + ncmax ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-13 18:33:55 +04:00
static __u64
2009-08-14 20:14:10 +04:00
nilfs_btree_node_get_key ( const struct nilfs_btree_node * node , int index )
2009-04-07 06:01:24 +04:00
{
2010-07-10 11:50:41 +04:00
return le64_to_cpu ( * ( nilfs_btree_node_dkeys ( node ) + index ) ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-13 18:33:55 +04:00
static void
2009-08-14 20:14:10 +04:00
nilfs_btree_node_set_key ( struct nilfs_btree_node * node , int index , __u64 key )
2009-04-07 06:01:24 +04:00
{
2010-07-10 11:50:41 +04:00
* ( nilfs_btree_node_dkeys ( node ) + index ) = cpu_to_le64 ( key ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-13 18:33:55 +04:00
static __u64
2010-07-13 18:33:53 +04:00
nilfs_btree_node_get_ptr ( const struct nilfs_btree_node * node , int index ,
int ncmax )
2009-04-07 06:01:24 +04:00
{
2010-07-13 18:33:53 +04:00
return le64_to_cpu ( * ( nilfs_btree_node_dptrs ( node , ncmax ) + index ) ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-13 18:33:55 +04:00
static void
2010-07-13 18:33:53 +04:00
nilfs_btree_node_set_ptr ( struct nilfs_btree_node * node , int index , __u64 ptr ,
int ncmax )
2009-04-07 06:01:24 +04:00
{
2010-07-13 18:33:53 +04:00
* ( nilfs_btree_node_dptrs ( node , ncmax ) + index ) = cpu_to_le64 ( ptr ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-13 18:33:53 +04:00
static void nilfs_btree_node_init ( struct nilfs_btree_node * node , int flags ,
int level , int nchildren , int ncmax ,
2009-04-07 06:01:24 +04:00
const __u64 * keys , const __u64 * ptrs )
{
__le64 * dkeys ;
__le64 * dptrs ;
int i ;
2009-08-14 20:14:10 +04:00
nilfs_btree_node_set_flags ( node , flags ) ;
nilfs_btree_node_set_level ( node , level ) ;
nilfs_btree_node_set_nchildren ( node , nchildren ) ;
2009-04-07 06:01:24 +04:00
2009-08-14 20:14:10 +04:00
dkeys = nilfs_btree_node_dkeys ( node ) ;
2010-07-13 18:33:53 +04:00
dptrs = nilfs_btree_node_dptrs ( node , ncmax ) ;
2009-04-07 06:01:24 +04:00
for ( i = 0 ; i < nchildren ; i + + ) {
2010-07-10 11:50:41 +04:00
dkeys [ i ] = cpu_to_le64 ( keys [ i ] ) ;
dptrs [ i ] = cpu_to_le64 ( ptrs [ i ] ) ;
2009-04-07 06:01:24 +04:00
}
}
/* Assume the buffer heads corresponding to left and right are locked. */
2010-07-13 18:33:53 +04:00
static void nilfs_btree_node_move_left ( struct nilfs_btree_node * left ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_node * right ,
2010-07-13 18:33:53 +04:00
int n , int lncmax , int rncmax )
2009-04-07 06:01:24 +04:00
{
__le64 * ldkeys , * rdkeys ;
__le64 * ldptrs , * rdptrs ;
int lnchildren , rnchildren ;
2009-08-14 20:14:10 +04:00
ldkeys = nilfs_btree_node_dkeys ( left ) ;
2010-07-13 18:33:53 +04:00
ldptrs = nilfs_btree_node_dptrs ( left , lncmax ) ;
2009-08-14 20:14:10 +04:00
lnchildren = nilfs_btree_node_get_nchildren ( left ) ;
2009-04-07 06:01:24 +04:00
2009-08-14 20:14:10 +04:00
rdkeys = nilfs_btree_node_dkeys ( right ) ;
2010-07-13 18:33:53 +04:00
rdptrs = nilfs_btree_node_dptrs ( right , rncmax ) ;
2009-08-14 20:14:10 +04:00
rnchildren = nilfs_btree_node_get_nchildren ( right ) ;
2009-04-07 06:01:24 +04:00
memcpy ( ldkeys + lnchildren , rdkeys , n * sizeof ( * rdkeys ) ) ;
memcpy ( ldptrs + lnchildren , rdptrs , n * sizeof ( * rdptrs ) ) ;
memmove ( rdkeys , rdkeys + n , ( rnchildren - n ) * sizeof ( * rdkeys ) ) ;
memmove ( rdptrs , rdptrs + n , ( rnchildren - n ) * sizeof ( * rdptrs ) ) ;
lnchildren + = n ;
rnchildren - = n ;
2009-08-14 20:14:10 +04:00
nilfs_btree_node_set_nchildren ( left , lnchildren ) ;
nilfs_btree_node_set_nchildren ( right , rnchildren ) ;
2009-04-07 06:01:24 +04:00
}
/* Assume that the buffer heads corresponding to left and right are locked. */
2010-07-13 18:33:53 +04:00
static void nilfs_btree_node_move_right ( struct nilfs_btree_node * left ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_node * right ,
2010-07-13 18:33:53 +04:00
int n , int lncmax , int rncmax )
2009-04-07 06:01:24 +04:00
{
__le64 * ldkeys , * rdkeys ;
__le64 * ldptrs , * rdptrs ;
int lnchildren , rnchildren ;
2009-08-14 20:14:10 +04:00
ldkeys = nilfs_btree_node_dkeys ( left ) ;
2010-07-13 18:33:53 +04:00
ldptrs = nilfs_btree_node_dptrs ( left , lncmax ) ;
2009-08-14 20:14:10 +04:00
lnchildren = nilfs_btree_node_get_nchildren ( left ) ;
2009-04-07 06:01:24 +04:00
2009-08-14 20:14:10 +04:00
rdkeys = nilfs_btree_node_dkeys ( right ) ;
2010-07-13 18:33:53 +04:00
rdptrs = nilfs_btree_node_dptrs ( right , rncmax ) ;
2009-08-14 20:14:10 +04:00
rnchildren = nilfs_btree_node_get_nchildren ( right ) ;
2009-04-07 06:01:24 +04:00
memmove ( rdkeys + n , rdkeys , rnchildren * sizeof ( * rdkeys ) ) ;
memmove ( rdptrs + n , rdptrs , rnchildren * sizeof ( * rdptrs ) ) ;
memcpy ( rdkeys , ldkeys + lnchildren - n , n * sizeof ( * rdkeys ) ) ;
memcpy ( rdptrs , ldptrs + lnchildren - n , n * sizeof ( * rdptrs ) ) ;
lnchildren - = n ;
rnchildren + = n ;
2009-08-14 20:14:10 +04:00
nilfs_btree_node_set_nchildren ( left , lnchildren ) ;
nilfs_btree_node_set_nchildren ( right , rnchildren ) ;
2009-04-07 06:01:24 +04:00
}
/* Assume that the buffer head corresponding to node is locked. */
2010-07-13 18:33:53 +04:00
static void nilfs_btree_node_insert ( struct nilfs_btree_node * node , int index ,
__u64 key , __u64 ptr , int ncmax )
2009-04-07 06:01:24 +04:00
{
__le64 * dkeys ;
__le64 * dptrs ;
int nchildren ;
2009-08-14 20:14:10 +04:00
dkeys = nilfs_btree_node_dkeys ( node ) ;
2010-07-13 18:33:53 +04:00
dptrs = nilfs_btree_node_dptrs ( node , ncmax ) ;
2009-08-14 20:14:10 +04:00
nchildren = nilfs_btree_node_get_nchildren ( node ) ;
2009-04-07 06:01:24 +04:00
if ( index < nchildren ) {
memmove ( dkeys + index + 1 , dkeys + index ,
( nchildren - index ) * sizeof ( * dkeys ) ) ;
memmove ( dptrs + index + 1 , dptrs + index ,
( nchildren - index ) * sizeof ( * dptrs ) ) ;
}
2010-07-10 11:50:41 +04:00
dkeys [ index ] = cpu_to_le64 ( key ) ;
dptrs [ index ] = cpu_to_le64 ( ptr ) ;
2009-04-07 06:01:24 +04:00
nchildren + + ;
2009-08-14 20:14:10 +04:00
nilfs_btree_node_set_nchildren ( node , nchildren ) ;
2009-04-07 06:01:24 +04:00
}
/* Assume that the buffer head corresponding to node is locked. */
2010-07-13 18:33:53 +04:00
static void nilfs_btree_node_delete ( struct nilfs_btree_node * node , int index ,
__u64 * keyp , __u64 * ptrp , int ncmax )
2009-04-07 06:01:24 +04:00
{
__u64 key ;
__u64 ptr ;
__le64 * dkeys ;
__le64 * dptrs ;
int nchildren ;
2009-08-14 20:14:10 +04:00
dkeys = nilfs_btree_node_dkeys ( node ) ;
2010-07-13 18:33:53 +04:00
dptrs = nilfs_btree_node_dptrs ( node , ncmax ) ;
2010-07-10 11:50:41 +04:00
key = le64_to_cpu ( dkeys [ index ] ) ;
ptr = le64_to_cpu ( dptrs [ index ] ) ;
2009-08-14 20:14:10 +04:00
nchildren = nilfs_btree_node_get_nchildren ( node ) ;
2009-04-07 06:01:24 +04:00
if ( keyp ! = NULL )
* keyp = key ;
if ( ptrp ! = NULL )
* ptrp = ptr ;
if ( index < nchildren - 1 ) {
memmove ( dkeys + index , dkeys + index + 1 ,
( nchildren - index - 1 ) * sizeof ( * dkeys ) ) ;
memmove ( dptrs + index , dptrs + index + 1 ,
( nchildren - index - 1 ) * sizeof ( * dptrs ) ) ;
}
nchildren - - ;
2009-08-14 20:14:10 +04:00
nilfs_btree_node_set_nchildren ( node , nchildren ) ;
2009-04-07 06:01:24 +04:00
}
2009-08-14 20:14:10 +04:00
static int nilfs_btree_node_lookup ( const struct nilfs_btree_node * node ,
2009-04-07 06:01:24 +04:00
__u64 key , int * indexp )
{
__u64 nkey ;
int index , low , high , s ;
/* binary search */
low = 0 ;
2009-08-14 20:14:10 +04:00
high = nilfs_btree_node_get_nchildren ( node ) - 1 ;
2009-04-07 06:01:24 +04:00
index = 0 ;
s = 0 ;
while ( low < = high ) {
index = ( low + high ) / 2 ;
2009-08-14 20:14:10 +04:00
nkey = nilfs_btree_node_get_key ( node , index ) ;
2009-04-07 06:01:24 +04:00
if ( nkey = = key ) {
s = 0 ;
goto out ;
} else if ( nkey < key ) {
low = index + 1 ;
s = - 1 ;
} else {
high = index - 1 ;
s = 1 ;
}
}
/* adjust index */
2009-08-14 20:14:10 +04:00
if ( nilfs_btree_node_get_level ( node ) > NILFS_BTREE_LEVEL_NODE_MIN ) {
if ( s > 0 & & index > 0 )
2009-04-07 06:01:24 +04:00
index - - ;
} else if ( s < 0 )
index + + ;
out :
* indexp = index ;
return s = = 0 ;
}
2010-07-16 18:52:40 +04:00
/**
* nilfs_btree_node_broken - verify consistency of btree node
* @ node : btree node block to be examined
* @ size : node size ( in bytes )
* @ blocknr : block number
*
* Return Value : If node is broken , 1 is returned . Otherwise , 0 is returned .
*/
static int nilfs_btree_node_broken ( const struct nilfs_btree_node * node ,
size_t size , sector_t blocknr )
{
int level , flags , nchildren ;
int ret = 0 ;
level = nilfs_btree_node_get_level ( node ) ;
flags = nilfs_btree_node_get_flags ( node ) ;
nchildren = nilfs_btree_node_get_nchildren ( node ) ;
if ( unlikely ( level < NILFS_BTREE_LEVEL_NODE_MIN | |
level > = NILFS_BTREE_LEVEL_MAX | |
( flags & NILFS_BTREE_NODE_ROOT ) | |
nchildren < 0 | |
nchildren > NILFS_BTREE_NODE_NCHILDREN_MAX ( size ) ) ) {
printk ( KERN_CRIT " NILFS: bad btree node (blocknr=%llu): "
" level = %d, flags = 0x%x, nchildren = %d \n " ,
( unsigned long long ) blocknr , level , flags , nchildren ) ;
ret = 1 ;
}
return ret ;
}
2015-02-28 02:51:56 +03:00
/**
* nilfs_btree_root_broken - verify consistency of btree root node
* @ node : btree root node to be examined
* @ ino : inode number
*
* Return Value : If node is broken , 1 is returned . Otherwise , 0 is returned .
*/
static int nilfs_btree_root_broken ( const struct nilfs_btree_node * node ,
unsigned long ino )
{
int level , flags , nchildren ;
int ret = 0 ;
level = nilfs_btree_node_get_level ( node ) ;
flags = nilfs_btree_node_get_flags ( node ) ;
nchildren = nilfs_btree_node_get_nchildren ( node ) ;
if ( unlikely ( level < NILFS_BTREE_LEVEL_NODE_MIN | |
2015-05-06 02:24:00 +03:00
level > = NILFS_BTREE_LEVEL_MAX | |
2015-02-28 02:51:56 +03:00
nchildren < 0 | |
nchildren > NILFS_BTREE_ROOT_NCHILDREN_MAX ) ) {
pr_crit ( " NILFS: bad btree root (inode number=%lu): level = %d, flags = 0x%x, nchildren = %d \n " ,
ino , level , flags , nchildren ) ;
ret = 1 ;
}
return ret ;
}
2010-07-16 18:52:40 +04:00
int nilfs_btree_broken_node_block ( struct buffer_head * bh )
{
2010-07-18 05:42:25 +04:00
int ret ;
if ( buffer_nilfs_checked ( bh ) )
return 0 ;
ret = nilfs_btree_node_broken ( ( struct nilfs_btree_node * ) bh - > b_data ,
2010-07-16 18:52:40 +04:00
bh - > b_size , bh - > b_blocknr ) ;
2010-07-18 05:42:25 +04:00
if ( likely ( ! ret ) )
set_buffer_nilfs_checked ( bh ) ;
return ret ;
2010-07-16 18:52:40 +04:00
}
2010-07-13 18:33:55 +04:00
static struct nilfs_btree_node *
2010-07-10 14:09:49 +04:00
nilfs_btree_get_root ( const struct nilfs_bmap * btree )
2009-04-07 06:01:24 +04:00
{
2010-07-10 14:09:49 +04:00
return ( struct nilfs_btree_node * ) btree - > b_u . u_data ;
2009-04-07 06:01:24 +04:00
}
2010-07-13 18:33:55 +04:00
static struct nilfs_btree_node *
2009-08-14 20:14:10 +04:00
nilfs_btree_get_nonroot_node ( const struct nilfs_btree_path * path , int level )
2009-04-07 06:01:24 +04:00
{
return ( struct nilfs_btree_node * ) path [ level ] . bp_bh - > b_data ;
}
2010-07-13 18:33:55 +04:00
static struct nilfs_btree_node *
2009-08-14 20:14:10 +04:00
nilfs_btree_get_sib_node ( const struct nilfs_btree_path * path , int level )
2009-04-07 06:01:24 +04:00
{
return ( struct nilfs_btree_node * ) path [ level ] . bp_sib_bh - > b_data ;
}
2010-07-13 18:33:55 +04:00
static int nilfs_btree_height ( const struct nilfs_bmap * btree )
2009-04-07 06:01:24 +04:00
{
2009-08-14 20:14:10 +04:00
return nilfs_btree_node_get_level ( nilfs_btree_get_root ( btree ) ) + 1 ;
2009-04-07 06:01:24 +04:00
}
2010-07-13 18:33:53 +04:00
static struct nilfs_btree_node *
2010-07-10 14:09:49 +04:00
nilfs_btree_get_node ( const struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
const struct nilfs_btree_path * path ,
2010-07-13 18:33:53 +04:00
int level , int * ncmaxp )
2009-04-07 06:01:24 +04:00
{
2010-07-13 18:33:53 +04:00
struct nilfs_btree_node * node ;
if ( level = = nilfs_btree_height ( btree ) - 1 ) {
node = nilfs_btree_get_root ( btree ) ;
* ncmaxp = NILFS_BTREE_ROOT_NCHILDREN_MAX ;
} else {
node = nilfs_btree_get_nonroot_node ( path , level ) ;
* ncmaxp = nilfs_btree_nchildren_per_block ( btree ) ;
}
return node ;
2009-04-07 06:01:24 +04:00
}
2010-07-13 18:33:55 +04:00
static int
2009-10-10 17:58:10 +04:00
nilfs_btree_bad_node ( struct nilfs_btree_node * node , int level )
{
if ( unlikely ( nilfs_btree_node_get_level ( node ) ! = level ) ) {
dump_stack ( ) ;
printk ( KERN_CRIT " NILFS: btree level mismatch: %d != %d \n " ,
nilfs_btree_node_get_level ( node ) , level ) ;
return 1 ;
}
return 0 ;
}
2010-07-18 05:42:24 +04:00
struct nilfs_btree_readahead_info {
struct nilfs_btree_node * node ; /* parent node */
int max_ra_blocks ; /* max nof blocks to read ahead */
int index ; /* current index on the parent node */
int ncmax ; /* nof children in the parent node */
} ;
static int __nilfs_btree_get_block ( const struct nilfs_bmap * btree , __u64 ptr ,
struct buffer_head * * bhp ,
const struct nilfs_btree_readahead_info * ra )
{
struct address_space * btnc = & NILFS_BMAP_I ( btree ) - > i_btnode_cache ;
struct buffer_head * bh , * ra_bh ;
sector_t submit_ptr = 0 ;
int ret ;
ret = nilfs_btnode_submit_block ( btnc , ptr , 0 , READ , & bh , & submit_ptr ) ;
if ( ret ) {
if ( ret ! = - EEXIST )
return ret ;
goto out_check ;
}
if ( ra ) {
int i , n ;
__u64 ptr2 ;
/* read ahead sibling nodes */
for ( n = ra - > max_ra_blocks , i = ra - > index + 1 ;
n > 0 & & i < ra - > ncmax ; n - - , i + + ) {
ptr2 = nilfs_btree_node_get_ptr ( ra - > node , i , ra - > ncmax ) ;
ret = nilfs_btnode_submit_block ( btnc , ptr2 , 0 , READA ,
& ra_bh , & submit_ptr ) ;
if ( likely ( ! ret | | ret = = - EEXIST ) )
brelse ( ra_bh ) ;
else if ( ret ! = - EBUSY )
break ;
if ( ! buffer_locked ( bh ) )
goto out_no_wait ;
}
}
wait_on_buffer ( bh ) ;
out_no_wait :
if ( ! buffer_uptodate ( bh ) ) {
brelse ( bh ) ;
return - EIO ;
}
out_check :
if ( nilfs_btree_broken_node_block ( bh ) ) {
clear_buffer_uptodate ( bh ) ;
brelse ( bh ) ;
return - EINVAL ;
}
* bhp = bh ;
return 0 ;
}
static int nilfs_btree_get_block ( const struct nilfs_bmap * btree , __u64 ptr ,
struct buffer_head * * bhp )
{
return __nilfs_btree_get_block ( btree , ptr , bhp , NULL ) ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_do_lookup ( const struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
2010-07-18 05:42:26 +04:00
__u64 key , __u64 * ptrp , int minlevel ,
int readahead )
2009-04-07 06:01:24 +04:00
{
struct nilfs_btree_node * node ;
2010-07-18 05:42:26 +04:00
struct nilfs_btree_readahead_info p , * ra ;
2009-04-07 06:01:24 +04:00
__u64 ptr ;
2010-07-13 18:33:52 +04:00
int level , index , found , ncmax , ret ;
2009-04-07 06:01:24 +04:00
node = nilfs_btree_get_root ( btree ) ;
2009-08-14 20:14:10 +04:00
level = nilfs_btree_node_get_level ( node ) ;
if ( level < minlevel | | nilfs_btree_node_get_nchildren ( node ) < = 0 )
2009-04-07 06:01:24 +04:00
return - ENOENT ;
2009-08-14 20:14:10 +04:00
found = nilfs_btree_node_lookup ( node , key , & index ) ;
2010-07-13 18:33:53 +04:00
ptr = nilfs_btree_node_get_ptr ( node , index ,
NILFS_BTREE_ROOT_NCHILDREN_MAX ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_bh = NULL ;
path [ level ] . bp_index = index ;
2010-07-13 18:33:53 +04:00
ncmax = nilfs_btree_nchildren_per_block ( btree ) ;
2010-07-13 18:33:52 +04:00
2010-07-18 05:42:26 +04:00
while ( - - level > = minlevel ) {
ra = NULL ;
if ( level = = NILFS_BTREE_LEVEL_NODE_MIN & & readahead ) {
p . node = nilfs_btree_get_node ( btree , path , level + 1 ,
& p . ncmax ) ;
p . index = index ;
p . max_ra_blocks = 7 ;
ra = & p ;
}
ret = __nilfs_btree_get_block ( btree , ptr , & path [ level ] . bp_bh ,
ra ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
return ret ;
2010-07-18 05:42:26 +04:00
2009-08-14 20:14:10 +04:00
node = nilfs_btree_get_nonroot_node ( path , level ) ;
2009-10-10 17:58:10 +04:00
if ( nilfs_btree_bad_node ( node , level ) )
return - EINVAL ;
2009-04-07 06:01:24 +04:00
if ( ! found )
2009-08-14 20:14:10 +04:00
found = nilfs_btree_node_lookup ( node , key , & index ) ;
2009-04-07 06:01:24 +04:00
else
index = 0 ;
2010-07-13 18:33:52 +04:00
if ( index < ncmax ) {
2010-07-13 18:33:53 +04:00
ptr = nilfs_btree_node_get_ptr ( node , index , ncmax ) ;
2010-07-13 18:33:52 +04:00
} else {
2009-04-07 06:01:55 +04:00
WARN_ON ( found | | level ! = NILFS_BTREE_LEVEL_NODE_MIN ) ;
2009-04-07 06:01:24 +04:00
/* insert */
ptr = NILFS_BMAP_INVALID_PTR ;
}
path [ level ] . bp_index = index ;
}
if ( ! found )
return - ENOENT ;
if ( ptrp ! = NULL )
* ptrp = ptr ;
return 0 ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_do_lookup_last ( const struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
__u64 * keyp , __u64 * ptrp )
{
struct nilfs_btree_node * node ;
__u64 ptr ;
2010-07-13 18:33:53 +04:00
int index , level , ncmax , ret ;
2009-04-07 06:01:24 +04:00
node = nilfs_btree_get_root ( btree ) ;
2009-08-14 20:14:10 +04:00
index = nilfs_btree_node_get_nchildren ( node ) - 1 ;
2009-04-07 06:01:24 +04:00
if ( index < 0 )
return - ENOENT ;
2009-08-14 20:14:10 +04:00
level = nilfs_btree_node_get_level ( node ) ;
2010-07-13 18:33:53 +04:00
ptr = nilfs_btree_node_get_ptr ( node , index ,
NILFS_BTREE_ROOT_NCHILDREN_MAX ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_bh = NULL ;
path [ level ] . bp_index = index ;
2010-07-13 18:33:53 +04:00
ncmax = nilfs_btree_nchildren_per_block ( btree ) ;
2009-04-07 06:01:24 +04:00
for ( level - - ; level > 0 ; level - - ) {
2009-05-21 20:07:13 +04:00
ret = nilfs_btree_get_block ( btree , ptr , & path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
return ret ;
2009-08-14 20:14:10 +04:00
node = nilfs_btree_get_nonroot_node ( path , level ) ;
2009-10-10 17:58:10 +04:00
if ( nilfs_btree_bad_node ( node , level ) )
return - EINVAL ;
2009-08-14 20:14:10 +04:00
index = nilfs_btree_node_get_nchildren ( node ) - 1 ;
2010-07-13 18:33:53 +04:00
ptr = nilfs_btree_node_get_ptr ( node , index , ncmax ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_index = index ;
}
if ( keyp ! = NULL )
2009-08-14 20:14:10 +04:00
* keyp = nilfs_btree_node_get_key ( node , index ) ;
2009-04-07 06:01:24 +04:00
if ( ptrp ! = NULL )
* ptrp = ptr ;
return 0 ;
}
2015-04-16 22:46:36 +03:00
/**
* nilfs_btree_get_next_key - get next valid key from btree path array
* @ btree : bmap struct of btree
* @ path : array of nilfs_btree_path struct
* @ minlevel : start level
* @ nextkey : place to store the next valid key
*
* Return Value : If a next key was found , 0 is returned . Otherwise ,
* - ENOENT is returned .
*/
static int nilfs_btree_get_next_key ( const struct nilfs_bmap * btree ,
const struct nilfs_btree_path * path ,
int minlevel , __u64 * nextkey )
{
struct nilfs_btree_node * node ;
int maxlevel = nilfs_btree_height ( btree ) - 1 ;
int index , next_adj , level ;
/* Next index is already set to bp_index for leaf nodes. */
next_adj = 0 ;
for ( level = minlevel ; level < = maxlevel ; level + + ) {
if ( level = = maxlevel )
node = nilfs_btree_get_root ( btree ) ;
else
node = nilfs_btree_get_nonroot_node ( path , level ) ;
index = path [ level ] . bp_index + next_adj ;
if ( index < nilfs_btree_node_get_nchildren ( node ) ) {
/* Next key is in this node */
* nextkey = nilfs_btree_node_get_key ( node , index ) ;
return 0 ;
}
/* For non-leaf nodes, next index is stored at bp_index + 1. */
next_adj = 1 ;
}
return - ENOENT ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_lookup ( const struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
__u64 key , int level , __u64 * ptrp )
{
struct nilfs_btree_path * path ;
int ret ;
2009-08-14 20:14:10 +04:00
path = nilfs_btree_alloc_path ( ) ;
2009-04-07 06:01:24 +04:00
if ( path = = NULL )
return - ENOMEM ;
2010-07-18 05:42:26 +04:00
ret = nilfs_btree_do_lookup ( btree , path , key , ptrp , level , 0 ) ;
2009-04-07 06:01:24 +04:00
2009-08-14 20:14:10 +04:00
nilfs_btree_free_path ( path ) ;
2009-04-07 06:01:24 +04:00
return ret ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_lookup_contig ( const struct nilfs_bmap * btree ,
2009-05-24 21:47:14 +04:00
__u64 key , __u64 * ptrp , unsigned maxblocks )
{
struct nilfs_btree_path * path ;
struct nilfs_btree_node * node ;
struct inode * dat = NULL ;
__u64 ptr , ptr2 ;
sector_t blocknr ;
int level = NILFS_BTREE_LEVEL_NODE_MIN ;
2010-07-13 18:33:53 +04:00
int ret , cnt , index , maxlevel , ncmax ;
2010-07-18 05:42:26 +04:00
struct nilfs_btree_readahead_info p ;
2009-05-24 21:47:14 +04:00
2009-08-14 20:14:10 +04:00
path = nilfs_btree_alloc_path ( ) ;
2009-05-24 21:47:14 +04:00
if ( path = = NULL )
return - ENOMEM ;
2010-04-02 13:36:34 +04:00
2010-07-18 05:42:26 +04:00
ret = nilfs_btree_do_lookup ( btree , path , key , & ptr , level , 1 ) ;
2009-05-24 21:47:14 +04:00
if ( ret < 0 )
goto out ;
2010-07-10 14:09:49 +04:00
if ( NILFS_BMAP_USE_VBN ( btree ) ) {
dat = nilfs_bmap_get_dat ( btree ) ;
2009-05-24 21:47:14 +04:00
ret = nilfs_dat_translate ( dat , ptr , & blocknr ) ;
if ( ret < 0 )
goto out ;
ptr = blocknr ;
}
cnt = 1 ;
if ( cnt = = maxblocks )
goto end ;
maxlevel = nilfs_btree_height ( btree ) - 1 ;
2010-07-13 18:33:53 +04:00
node = nilfs_btree_get_node ( btree , path , level , & ncmax ) ;
2009-05-24 21:47:14 +04:00
index = path [ level ] . bp_index + 1 ;
for ( ; ; ) {
2009-08-14 20:14:10 +04:00
while ( index < nilfs_btree_node_get_nchildren ( node ) ) {
if ( nilfs_btree_node_get_key ( node , index ) ! =
2009-05-24 21:47:14 +04:00
key + cnt )
goto end ;
2010-07-13 18:33:53 +04:00
ptr2 = nilfs_btree_node_get_ptr ( node , index , ncmax ) ;
2009-05-24 21:47:14 +04:00
if ( dat ) {
ret = nilfs_dat_translate ( dat , ptr2 , & blocknr ) ;
if ( ret < 0 )
goto out ;
ptr2 = blocknr ;
}
if ( ptr2 ! = ptr + cnt | | + + cnt = = maxblocks )
goto end ;
index + + ;
continue ;
}
if ( level = = maxlevel )
break ;
/* look-up right sibling node */
2010-07-18 05:42:26 +04:00
p . node = nilfs_btree_get_node ( btree , path , level + 1 , & p . ncmax ) ;
p . index = path [ level + 1 ] . bp_index + 1 ;
p . max_ra_blocks = 7 ;
if ( p . index > = nilfs_btree_node_get_nchildren ( p . node ) | |
nilfs_btree_node_get_key ( p . node , p . index ) ! = key + cnt )
2009-05-24 21:47:14 +04:00
break ;
2010-07-18 05:42:26 +04:00
ptr2 = nilfs_btree_node_get_ptr ( p . node , p . index , p . ncmax ) ;
path [ level + 1 ] . bp_index = p . index ;
2009-05-24 21:47:14 +04:00
brelse ( path [ level ] . bp_bh ) ;
path [ level ] . bp_bh = NULL ;
2010-07-18 05:42:26 +04:00
ret = __nilfs_btree_get_block ( btree , ptr2 , & path [ level ] . bp_bh ,
& p ) ;
2009-05-24 21:47:14 +04:00
if ( ret < 0 )
goto out ;
2009-08-14 20:14:10 +04:00
node = nilfs_btree_get_nonroot_node ( path , level ) ;
2010-07-13 18:33:53 +04:00
ncmax = nilfs_btree_nchildren_per_block ( btree ) ;
2009-05-24 21:47:14 +04:00
index = 0 ;
path [ level ] . bp_index = index ;
}
end :
* ptrp = ptr ;
ret = cnt ;
out :
2009-08-14 20:14:10 +04:00
nilfs_btree_free_path ( path ) ;
2009-05-24 21:47:14 +04:00
return ret ;
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_promote_key ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level , __u64 key )
{
if ( level < nilfs_btree_height ( btree ) - 1 ) {
do {
nilfs_btree_node_set_key (
2009-08-14 20:14:10 +04:00
nilfs_btree_get_nonroot_node ( path , level ) ,
2009-04-07 06:01:24 +04:00
path [ level ] . bp_index , key ) ;
if ( ! buffer_dirty ( path [ level ] . bp_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
} while ( ( path [ level ] . bp_index = = 0 ) & &
( + + level < nilfs_btree_height ( btree ) - 1 ) ) ;
}
/* root */
if ( level = = nilfs_btree_height ( btree ) - 1 ) {
2009-08-14 20:14:10 +04:00
nilfs_btree_node_set_key ( nilfs_btree_get_root ( btree ) ,
2009-04-07 06:01:24 +04:00
path [ level ] . bp_index , key ) ;
}
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_do_insert ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level , __u64 * keyp , __u64 * ptrp )
{
struct nilfs_btree_node * node ;
2010-07-13 18:33:53 +04:00
int ncblk ;
2009-04-07 06:01:24 +04:00
if ( level < nilfs_btree_height ( btree ) - 1 ) {
2009-08-14 20:14:10 +04:00
node = nilfs_btree_get_nonroot_node ( path , level ) ;
2010-07-13 18:33:53 +04:00
ncblk = nilfs_btree_nchildren_per_block ( btree ) ;
nilfs_btree_node_insert ( node , path [ level ] . bp_index ,
* keyp , * ptrp , ncblk ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
if ( path [ level ] . bp_index = = 0 )
nilfs_btree_promote_key ( btree , path , level + 1 ,
2009-08-14 20:14:10 +04:00
nilfs_btree_node_get_key ( node ,
0 ) ) ;
2009-04-07 06:01:24 +04:00
} else {
node = nilfs_btree_get_root ( btree ) ;
2010-07-13 18:33:53 +04:00
nilfs_btree_node_insert ( node , path [ level ] . bp_index ,
* keyp , * ptrp ,
NILFS_BTREE_ROOT_NCHILDREN_MAX ) ;
2009-04-07 06:01:24 +04:00
}
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_carry_left ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level , __u64 * keyp , __u64 * ptrp )
{
struct nilfs_btree_node * node , * left ;
2010-07-13 18:33:53 +04:00
int nchildren , lnchildren , n , move , ncblk ;
2009-04-07 06:01:24 +04:00
2009-08-14 20:14:10 +04:00
node = nilfs_btree_get_nonroot_node ( path , level ) ;
left = nilfs_btree_get_sib_node ( path , level ) ;
nchildren = nilfs_btree_node_get_nchildren ( node ) ;
lnchildren = nilfs_btree_node_get_nchildren ( left ) ;
2010-07-13 18:33:53 +04:00
ncblk = nilfs_btree_nchildren_per_block ( btree ) ;
2009-04-07 06:01:24 +04:00
move = 0 ;
n = ( nchildren + lnchildren + 1 ) / 2 - lnchildren ;
if ( n > path [ level ] . bp_index ) {
/* move insert point */
n - - ;
move = 1 ;
}
2010-07-13 18:33:53 +04:00
nilfs_btree_node_move_left ( left , node , n , ncblk , ncblk ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_sib_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_sib_bh ) ;
2009-04-07 06:01:24 +04:00
nilfs_btree_promote_key ( btree , path , level + 1 ,
2009-08-14 20:14:10 +04:00
nilfs_btree_node_get_key ( node , 0 ) ) ;
2009-04-07 06:01:24 +04:00
if ( move ) {
2009-05-21 19:33:13 +04:00
brelse ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_bh = path [ level ] . bp_sib_bh ;
path [ level ] . bp_sib_bh = NULL ;
path [ level ] . bp_index + = lnchildren ;
path [ level + 1 ] . bp_index - - ;
} else {
2009-05-21 19:33:13 +04:00
brelse ( path [ level ] . bp_sib_bh ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_sib_bh = NULL ;
path [ level ] . bp_index - = n ;
}
nilfs_btree_do_insert ( btree , path , level , keyp , ptrp ) ;
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_carry_right ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level , __u64 * keyp , __u64 * ptrp )
{
struct nilfs_btree_node * node , * right ;
2010-07-13 18:33:53 +04:00
int nchildren , rnchildren , n , move , ncblk ;
2009-04-07 06:01:24 +04:00
2009-08-14 20:14:10 +04:00
node = nilfs_btree_get_nonroot_node ( path , level ) ;
right = nilfs_btree_get_sib_node ( path , level ) ;
nchildren = nilfs_btree_node_get_nchildren ( node ) ;
rnchildren = nilfs_btree_node_get_nchildren ( right ) ;
2010-07-13 18:33:53 +04:00
ncblk = nilfs_btree_nchildren_per_block ( btree ) ;
2009-04-07 06:01:24 +04:00
move = 0 ;
n = ( nchildren + rnchildren + 1 ) / 2 - rnchildren ;
if ( n > nchildren - path [ level ] . bp_index ) {
/* move insert point */
n - - ;
move = 1 ;
}
2010-07-13 18:33:53 +04:00
nilfs_btree_node_move_right ( node , right , n , ncblk , ncblk ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_sib_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_sib_bh ) ;
2009-04-07 06:01:24 +04:00
path [ level + 1 ] . bp_index + + ;
nilfs_btree_promote_key ( btree , path , level + 1 ,
2009-08-14 20:14:10 +04:00
nilfs_btree_node_get_key ( right , 0 ) ) ;
2009-04-07 06:01:24 +04:00
path [ level + 1 ] . bp_index - - ;
if ( move ) {
2009-05-21 19:33:13 +04:00
brelse ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_bh = path [ level ] . bp_sib_bh ;
path [ level ] . bp_sib_bh = NULL ;
2009-08-14 20:14:10 +04:00
path [ level ] . bp_index - = nilfs_btree_node_get_nchildren ( node ) ;
2009-04-07 06:01:24 +04:00
path [ level + 1 ] . bp_index + + ;
} else {
2009-05-21 19:33:13 +04:00
brelse ( path [ level ] . bp_sib_bh ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_sib_bh = NULL ;
}
nilfs_btree_do_insert ( btree , path , level , keyp , ptrp ) ;
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_split ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level , __u64 * keyp , __u64 * ptrp )
{
struct nilfs_btree_node * node , * right ;
2010-07-13 18:33:53 +04:00
int nchildren , n , move , ncblk ;
2009-04-07 06:01:24 +04:00
2009-08-14 20:14:10 +04:00
node = nilfs_btree_get_nonroot_node ( path , level ) ;
right = nilfs_btree_get_sib_node ( path , level ) ;
nchildren = nilfs_btree_node_get_nchildren ( node ) ;
2010-07-13 18:33:53 +04:00
ncblk = nilfs_btree_nchildren_per_block ( btree ) ;
2009-04-07 06:01:24 +04:00
move = 0 ;
n = ( nchildren + 1 ) / 2 ;
if ( n > nchildren - path [ level ] . bp_index ) {
n - - ;
move = 1 ;
}
2010-07-13 18:33:53 +04:00
nilfs_btree_node_move_right ( node , right , n , ncblk , ncblk ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_sib_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_sib_bh ) ;
2009-04-07 06:01:24 +04:00
if ( move ) {
2009-08-14 20:14:10 +04:00
path [ level ] . bp_index - = nilfs_btree_node_get_nchildren ( node ) ;
2010-07-13 18:33:53 +04:00
nilfs_btree_node_insert ( right , path [ level ] . bp_index ,
* keyp , * ptrp , ncblk ) ;
2009-04-07 06:01:24 +04:00
2009-08-14 20:14:10 +04:00
* keyp = nilfs_btree_node_get_key ( right , 0 ) ;
2009-04-07 06:01:24 +04:00
* ptrp = path [ level ] . bp_newreq . bpr_ptr ;
2009-05-21 19:33:13 +04:00
brelse ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_bh = path [ level ] . bp_sib_bh ;
path [ level ] . bp_sib_bh = NULL ;
} else {
nilfs_btree_do_insert ( btree , path , level , keyp , ptrp ) ;
2009-08-14 20:14:10 +04:00
* keyp = nilfs_btree_node_get_key ( right , 0 ) ;
2009-04-07 06:01:24 +04:00
* ptrp = path [ level ] . bp_newreq . bpr_ptr ;
2009-05-21 19:33:13 +04:00
brelse ( path [ level ] . bp_sib_bh ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_sib_bh = NULL ;
}
path [ level + 1 ] . bp_index + + ;
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_grow ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level , __u64 * keyp , __u64 * ptrp )
{
struct nilfs_btree_node * root , * child ;
2010-07-13 18:33:53 +04:00
int n , ncblk ;
2009-04-07 06:01:24 +04:00
root = nilfs_btree_get_root ( btree ) ;
2009-08-14 20:14:10 +04:00
child = nilfs_btree_get_sib_node ( path , level ) ;
2010-07-13 18:33:53 +04:00
ncblk = nilfs_btree_nchildren_per_block ( btree ) ;
2009-04-07 06:01:24 +04:00
2009-08-14 20:14:10 +04:00
n = nilfs_btree_node_get_nchildren ( root ) ;
2009-04-07 06:01:24 +04:00
2010-07-13 18:33:53 +04:00
nilfs_btree_node_move_right ( root , child , n ,
NILFS_BTREE_ROOT_NCHILDREN_MAX , ncblk ) ;
2009-08-14 20:14:10 +04:00
nilfs_btree_node_set_level ( root , level + 1 ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_sib_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_sib_bh ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_bh = path [ level ] . bp_sib_bh ;
path [ level ] . bp_sib_bh = NULL ;
nilfs_btree_do_insert ( btree , path , level , keyp , ptrp ) ;
2009-08-14 20:14:10 +04:00
* keyp = nilfs_btree_node_get_key ( child , 0 ) ;
2009-04-07 06:01:24 +04:00
* ptrp = path [ level ] . bp_newreq . bpr_ptr ;
}
2010-07-10 14:09:49 +04:00
static __u64 nilfs_btree_find_near ( const struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
const struct nilfs_btree_path * path )
{
struct nilfs_btree_node * node ;
2010-07-13 18:33:53 +04:00
int level , ncmax ;
2009-04-07 06:01:24 +04:00
if ( path = = NULL )
return NILFS_BMAP_INVALID_PTR ;
/* left sibling */
level = NILFS_BTREE_LEVEL_NODE_MIN ;
if ( path [ level ] . bp_index > 0 ) {
2010-07-13 18:33:53 +04:00
node = nilfs_btree_get_node ( btree , path , level , & ncmax ) ;
return nilfs_btree_node_get_ptr ( node ,
path [ level ] . bp_index - 1 ,
ncmax ) ;
2009-04-07 06:01:24 +04:00
}
/* parent */
level = NILFS_BTREE_LEVEL_NODE_MIN + 1 ;
if ( level < = nilfs_btree_height ( btree ) - 1 ) {
2010-07-13 18:33:53 +04:00
node = nilfs_btree_get_node ( btree , path , level , & ncmax ) ;
return nilfs_btree_node_get_ptr ( node , path [ level ] . bp_index ,
ncmax ) ;
2009-04-07 06:01:24 +04:00
}
return NILFS_BMAP_INVALID_PTR ;
}
2010-07-10 14:09:49 +04:00
static __u64 nilfs_btree_find_target_v ( const struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
const struct nilfs_btree_path * path ,
__u64 key )
{
__u64 ptr ;
2010-07-10 14:09:49 +04:00
ptr = nilfs_bmap_find_target_seq ( btree , key ) ;
2009-04-07 06:01:24 +04:00
if ( ptr ! = NILFS_BMAP_INVALID_PTR )
/* sequential access */
return ptr ;
else {
ptr = nilfs_btree_find_near ( btree , path ) ;
if ( ptr ! = NILFS_BMAP_INVALID_PTR )
/* near */
return ptr ;
}
/* block group */
2010-07-10 14:09:49 +04:00
return nilfs_bmap_find_target_in_group ( btree ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_prepare_insert ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int * levelp , __u64 key , __u64 ptr ,
struct nilfs_bmap_stats * stats )
{
struct buffer_head * bh ;
struct nilfs_btree_node * node , * parent , * sib ;
__u64 sibptr ;
2010-07-13 18:33:53 +04:00
int pindex , level , ncmax , ncblk , ret ;
2009-08-15 10:34:33 +04:00
struct inode * dat = NULL ;
2009-04-07 06:01:24 +04:00
stats - > bs_nblocks = 0 ;
level = NILFS_BTREE_LEVEL_DATA ;
/* allocate a new ptr for data block */
2010-07-10 14:09:49 +04:00
if ( NILFS_BMAP_USE_VBN ( btree ) ) {
2009-04-07 06:01:24 +04:00
path [ level ] . bp_newreq . bpr_ptr =
2009-05-24 13:07:59 +04:00
nilfs_btree_find_target_v ( btree , path , key ) ;
2010-07-10 14:09:49 +04:00
dat = nilfs_bmap_get_dat ( btree ) ;
2009-08-15 10:34:33 +04:00
}
2009-04-07 06:01:24 +04:00
2010-07-10 14:09:49 +04:00
ret = nilfs_bmap_prepare_alloc_ptr ( btree , & path [ level ] . bp_newreq , dat ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto err_out_data ;
2010-07-13 18:33:53 +04:00
ncblk = nilfs_btree_nchildren_per_block ( btree ) ;
2010-07-13 18:33:52 +04:00
2009-04-07 06:01:24 +04:00
for ( level = NILFS_BTREE_LEVEL_NODE_MIN ;
level < nilfs_btree_height ( btree ) - 1 ;
level + + ) {
2009-08-14 20:14:10 +04:00
node = nilfs_btree_get_nonroot_node ( path , level ) ;
2010-07-13 18:33:53 +04:00
if ( nilfs_btree_node_get_nchildren ( node ) < ncblk ) {
2009-04-07 06:01:24 +04:00
path [ level ] . bp_op = nilfs_btree_do_insert ;
stats - > bs_nblocks + + ;
goto out ;
}
2010-07-13 18:33:53 +04:00
parent = nilfs_btree_get_node ( btree , path , level + 1 , & ncmax ) ;
2009-04-07 06:01:24 +04:00
pindex = path [ level + 1 ] . bp_index ;
/* left sibling */
if ( pindex > 0 ) {
2010-07-13 18:33:53 +04:00
sibptr = nilfs_btree_node_get_ptr ( parent , pindex - 1 ,
ncmax ) ;
2009-05-21 20:07:13 +04:00
ret = nilfs_btree_get_block ( btree , sibptr , & bh ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto err_out_child_node ;
sib = ( struct nilfs_btree_node * ) bh - > b_data ;
2010-07-13 18:33:53 +04:00
if ( nilfs_btree_node_get_nchildren ( sib ) < ncblk ) {
2009-04-07 06:01:24 +04:00
path [ level ] . bp_sib_bh = bh ;
path [ level ] . bp_op = nilfs_btree_carry_left ;
stats - > bs_nblocks + + ;
goto out ;
2010-07-13 18:33:53 +04:00
} else {
2009-05-21 19:33:13 +04:00
brelse ( bh ) ;
2010-07-13 18:33:53 +04:00
}
2009-04-07 06:01:24 +04:00
}
/* right sibling */
2010-07-13 18:33:53 +04:00
if ( pindex < nilfs_btree_node_get_nchildren ( parent ) - 1 ) {
sibptr = nilfs_btree_node_get_ptr ( parent , pindex + 1 ,
ncmax ) ;
2009-05-21 20:07:13 +04:00
ret = nilfs_btree_get_block ( btree , sibptr , & bh ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto err_out_child_node ;
sib = ( struct nilfs_btree_node * ) bh - > b_data ;
2010-07-13 18:33:53 +04:00
if ( nilfs_btree_node_get_nchildren ( sib ) < ncblk ) {
2009-04-07 06:01:24 +04:00
path [ level ] . bp_sib_bh = bh ;
path [ level ] . bp_op = nilfs_btree_carry_right ;
stats - > bs_nblocks + + ;
goto out ;
2010-07-13 18:33:53 +04:00
} else {
2009-05-21 19:33:13 +04:00
brelse ( bh ) ;
2010-07-13 18:33:53 +04:00
}
2009-04-07 06:01:24 +04:00
}
/* split */
path [ level ] . bp_newreq . bpr_ptr =
path [ level - 1 ] . bp_newreq . bpr_ptr + 1 ;
2010-07-10 14:09:49 +04:00
ret = nilfs_bmap_prepare_alloc_ptr ( btree ,
2009-08-15 10:34:33 +04:00
& path [ level ] . bp_newreq , dat ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto err_out_child_node ;
2009-05-21 20:07:13 +04:00
ret = nilfs_btree_get_new_block ( btree ,
path [ level ] . bp_newreq . bpr_ptr ,
& bh ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto err_out_curr_node ;
stats - > bs_nblocks + + ;
2010-07-13 18:33:53 +04:00
sib = ( struct nilfs_btree_node * ) bh - > b_data ;
nilfs_btree_node_init ( sib , 0 , level , 0 , ncblk , NULL , NULL ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_sib_bh = bh ;
path [ level ] . bp_op = nilfs_btree_split ;
}
/* root */
node = nilfs_btree_get_root ( btree ) ;
2009-08-14 20:14:10 +04:00
if ( nilfs_btree_node_get_nchildren ( node ) <
2010-07-13 18:33:52 +04:00
NILFS_BTREE_ROOT_NCHILDREN_MAX ) {
2009-04-07 06:01:24 +04:00
path [ level ] . bp_op = nilfs_btree_do_insert ;
stats - > bs_nblocks + + ;
goto out ;
}
/* grow */
path [ level ] . bp_newreq . bpr_ptr = path [ level - 1 ] . bp_newreq . bpr_ptr + 1 ;
2010-07-10 14:09:49 +04:00
ret = nilfs_bmap_prepare_alloc_ptr ( btree , & path [ level ] . bp_newreq , dat ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto err_out_child_node ;
2009-05-21 20:07:13 +04:00
ret = nilfs_btree_get_new_block ( btree , path [ level ] . bp_newreq . bpr_ptr ,
& bh ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto err_out_curr_node ;
2010-07-13 18:33:53 +04:00
nilfs_btree_node_init ( ( struct nilfs_btree_node * ) bh - > b_data ,
0 , level , 0 , ncblk , NULL , NULL ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_sib_bh = bh ;
path [ level ] . bp_op = nilfs_btree_grow ;
level + + ;
path [ level ] . bp_op = nilfs_btree_do_insert ;
/* a newly-created node block and a data block are added */
stats - > bs_nblocks + = 2 ;
/* success */
out :
* levelp = level ;
return ret ;
/* error */
err_out_curr_node :
2010-07-10 14:09:49 +04:00
nilfs_bmap_abort_alloc_ptr ( btree , & path [ level ] . bp_newreq , dat ) ;
2009-04-07 06:01:24 +04:00
err_out_child_node :
for ( level - - ; level > NILFS_BTREE_LEVEL_DATA ; level - - ) {
2009-05-21 19:38:56 +04:00
nilfs_btnode_delete ( path [ level ] . bp_sib_bh ) ;
2010-07-10 14:09:49 +04:00
nilfs_bmap_abort_alloc_ptr ( btree , & path [ level ] . bp_newreq , dat ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-10 14:09:49 +04:00
nilfs_bmap_abort_alloc_ptr ( btree , & path [ level ] . bp_newreq , dat ) ;
2009-04-07 06:01:24 +04:00
err_out_data :
* levelp = level ;
stats - > bs_nblocks = 0 ;
return ret ;
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_commit_insert ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int maxlevel , __u64 key , __u64 ptr )
{
2009-08-15 10:34:33 +04:00
struct inode * dat = NULL ;
2009-04-07 06:01:24 +04:00
int level ;
set_buffer_nilfs_volatile ( ( struct buffer_head * ) ( ( unsigned long ) ptr ) ) ;
ptr = path [ NILFS_BTREE_LEVEL_DATA ] . bp_newreq . bpr_ptr ;
2010-07-10 14:09:49 +04:00
if ( NILFS_BMAP_USE_VBN ( btree ) ) {
2010-07-10 17:21:54 +04:00
nilfs_bmap_set_target_v ( btree , key , ptr ) ;
2010-07-10 14:09:49 +04:00
dat = nilfs_bmap_get_dat ( btree ) ;
2009-08-15 10:34:33 +04:00
}
2009-04-07 06:01:24 +04:00
for ( level = NILFS_BTREE_LEVEL_NODE_MIN ; level < = maxlevel ; level + + ) {
2010-07-10 14:09:49 +04:00
nilfs_bmap_commit_alloc_ptr ( btree ,
2009-08-15 10:34:33 +04:00
& path [ level - 1 ] . bp_newreq , dat ) ;
2009-04-07 06:01:49 +04:00
path [ level ] . bp_op ( btree , path , level , & key , & ptr ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-10 14:09:49 +04:00
if ( ! nilfs_bmap_dirty ( btree ) )
nilfs_bmap_set_dirty ( btree ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_insert ( struct nilfs_bmap * btree , __u64 key , __u64 ptr )
2009-04-07 06:01:24 +04:00
{
struct nilfs_btree_path * path ;
struct nilfs_bmap_stats stats ;
int level , ret ;
2009-08-14 20:14:10 +04:00
path = nilfs_btree_alloc_path ( ) ;
2009-04-07 06:01:24 +04:00
if ( path = = NULL )
return - ENOMEM ;
ret = nilfs_btree_do_lookup ( btree , path , key , NULL ,
2010-07-18 05:42:26 +04:00
NILFS_BTREE_LEVEL_NODE_MIN , 0 ) ;
2009-04-07 06:01:24 +04:00
if ( ret ! = - ENOENT ) {
if ( ret = = 0 )
ret = - EEXIST ;
goto out ;
}
ret = nilfs_btree_prepare_insert ( btree , path , & level , key , ptr , & stats ) ;
if ( ret < 0 )
goto out ;
nilfs_btree_commit_insert ( btree , path , level , key , ptr ) ;
2011-03-04 18:19:32 +03:00
nilfs_inode_add_blocks ( btree - > b_inode , stats . bs_nblocks ) ;
2009-04-07 06:01:24 +04:00
out :
2009-08-14 20:14:10 +04:00
nilfs_btree_free_path ( path ) ;
2009-04-07 06:01:24 +04:00
return ret ;
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_do_delete ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level , __u64 * keyp , __u64 * ptrp )
{
struct nilfs_btree_node * node ;
2010-07-13 18:33:53 +04:00
int ncblk ;
2009-04-07 06:01:24 +04:00
if ( level < nilfs_btree_height ( btree ) - 1 ) {
2009-08-14 20:14:10 +04:00
node = nilfs_btree_get_nonroot_node ( path , level ) ;
2010-07-13 18:33:53 +04:00
ncblk = nilfs_btree_nchildren_per_block ( btree ) ;
nilfs_btree_node_delete ( node , path [ level ] . bp_index ,
keyp , ptrp , ncblk ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
if ( path [ level ] . bp_index = = 0 )
nilfs_btree_promote_key ( btree , path , level + 1 ,
2009-08-14 20:14:10 +04:00
nilfs_btree_node_get_key ( node , 0 ) ) ;
2009-04-07 06:01:24 +04:00
} else {
node = nilfs_btree_get_root ( btree ) ;
2010-07-13 18:33:53 +04:00
nilfs_btree_node_delete ( node , path [ level ] . bp_index ,
keyp , ptrp ,
NILFS_BTREE_ROOT_NCHILDREN_MAX ) ;
2009-04-07 06:01:24 +04:00
}
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_borrow_left ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level , __u64 * keyp , __u64 * ptrp )
{
struct nilfs_btree_node * node , * left ;
2010-07-13 18:33:53 +04:00
int nchildren , lnchildren , n , ncblk ;
2009-04-07 06:01:24 +04:00
nilfs_btree_do_delete ( btree , path , level , keyp , ptrp ) ;
2009-08-14 20:14:10 +04:00
node = nilfs_btree_get_nonroot_node ( path , level ) ;
left = nilfs_btree_get_sib_node ( path , level ) ;
nchildren = nilfs_btree_node_get_nchildren ( node ) ;
lnchildren = nilfs_btree_node_get_nchildren ( left ) ;
2010-07-13 18:33:53 +04:00
ncblk = nilfs_btree_nchildren_per_block ( btree ) ;
2009-04-07 06:01:24 +04:00
n = ( nchildren + lnchildren ) / 2 - nchildren ;
2010-07-13 18:33:53 +04:00
nilfs_btree_node_move_right ( left , node , n , ncblk , ncblk ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_sib_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_sib_bh ) ;
2009-04-07 06:01:24 +04:00
nilfs_btree_promote_key ( btree , path , level + 1 ,
2009-08-14 20:14:10 +04:00
nilfs_btree_node_get_key ( node , 0 ) ) ;
2009-04-07 06:01:24 +04:00
2009-05-21 19:33:13 +04:00
brelse ( path [ level ] . bp_sib_bh ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_sib_bh = NULL ;
path [ level ] . bp_index + = n ;
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_borrow_right ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level , __u64 * keyp , __u64 * ptrp )
{
struct nilfs_btree_node * node , * right ;
2010-07-13 18:33:53 +04:00
int nchildren , rnchildren , n , ncblk ;
2009-04-07 06:01:24 +04:00
nilfs_btree_do_delete ( btree , path , level , keyp , ptrp ) ;
2009-08-14 20:14:10 +04:00
node = nilfs_btree_get_nonroot_node ( path , level ) ;
right = nilfs_btree_get_sib_node ( path , level ) ;
nchildren = nilfs_btree_node_get_nchildren ( node ) ;
rnchildren = nilfs_btree_node_get_nchildren ( right ) ;
2010-07-13 18:33:53 +04:00
ncblk = nilfs_btree_nchildren_per_block ( btree ) ;
2009-04-07 06:01:24 +04:00
n = ( nchildren + rnchildren ) / 2 - nchildren ;
2010-07-13 18:33:53 +04:00
nilfs_btree_node_move_left ( node , right , n , ncblk , ncblk ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_sib_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_sib_bh ) ;
2009-04-07 06:01:24 +04:00
path [ level + 1 ] . bp_index + + ;
nilfs_btree_promote_key ( btree , path , level + 1 ,
2009-08-14 20:14:10 +04:00
nilfs_btree_node_get_key ( right , 0 ) ) ;
2009-04-07 06:01:24 +04:00
path [ level + 1 ] . bp_index - - ;
2009-05-21 19:33:13 +04:00
brelse ( path [ level ] . bp_sib_bh ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_sib_bh = NULL ;
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_concat_left ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level , __u64 * keyp , __u64 * ptrp )
{
struct nilfs_btree_node * node , * left ;
2010-07-13 18:33:53 +04:00
int n , ncblk ;
2009-04-07 06:01:24 +04:00
nilfs_btree_do_delete ( btree , path , level , keyp , ptrp ) ;
2009-08-14 20:14:10 +04:00
node = nilfs_btree_get_nonroot_node ( path , level ) ;
left = nilfs_btree_get_sib_node ( path , level ) ;
2010-07-13 18:33:53 +04:00
ncblk = nilfs_btree_nchildren_per_block ( btree ) ;
2009-04-07 06:01:24 +04:00
2009-08-14 20:14:10 +04:00
n = nilfs_btree_node_get_nchildren ( node ) ;
2009-04-07 06:01:24 +04:00
2010-07-13 18:33:53 +04:00
nilfs_btree_node_move_left ( left , node , n , ncblk , ncblk ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_sib_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_sib_bh ) ;
2009-04-07 06:01:24 +04:00
2009-05-21 19:38:56 +04:00
nilfs_btnode_delete ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_bh = path [ level ] . bp_sib_bh ;
path [ level ] . bp_sib_bh = NULL ;
2009-08-14 20:14:10 +04:00
path [ level ] . bp_index + = nilfs_btree_node_get_nchildren ( left ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_concat_right ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level , __u64 * keyp , __u64 * ptrp )
{
struct nilfs_btree_node * node , * right ;
2010-07-13 18:33:53 +04:00
int n , ncblk ;
2009-04-07 06:01:24 +04:00
nilfs_btree_do_delete ( btree , path , level , keyp , ptrp ) ;
2009-08-14 20:14:10 +04:00
node = nilfs_btree_get_nonroot_node ( path , level ) ;
right = nilfs_btree_get_sib_node ( path , level ) ;
2010-07-13 18:33:53 +04:00
ncblk = nilfs_btree_nchildren_per_block ( btree ) ;
2009-04-07 06:01:24 +04:00
2009-08-14 20:14:10 +04:00
n = nilfs_btree_node_get_nchildren ( right ) ;
2009-04-07 06:01:24 +04:00
2010-07-13 18:33:53 +04:00
nilfs_btree_node_move_left ( node , right , n , ncblk , ncblk ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( path [ level ] . bp_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
2009-05-21 19:38:56 +04:00
nilfs_btnode_delete ( path [ level ] . bp_sib_bh ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_sib_bh = NULL ;
path [ level + 1 ] . bp_index + + ;
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_shrink ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level , __u64 * keyp , __u64 * ptrp )
{
struct nilfs_btree_node * root , * child ;
2010-07-13 18:33:53 +04:00
int n , ncblk ;
2009-04-07 06:01:24 +04:00
nilfs_btree_do_delete ( btree , path , level , keyp , ptrp ) ;
root = nilfs_btree_get_root ( btree ) ;
2009-08-14 20:14:10 +04:00
child = nilfs_btree_get_nonroot_node ( path , level ) ;
2010-07-13 18:33:53 +04:00
ncblk = nilfs_btree_nchildren_per_block ( btree ) ;
2009-04-07 06:01:24 +04:00
2010-07-13 18:33:53 +04:00
nilfs_btree_node_delete ( root , 0 , NULL , NULL ,
NILFS_BTREE_ROOT_NCHILDREN_MAX ) ;
2009-08-14 20:14:10 +04:00
nilfs_btree_node_set_level ( root , level ) ;
n = nilfs_btree_node_get_nchildren ( child ) ;
2010-07-13 18:33:53 +04:00
nilfs_btree_node_move_left ( root , child , n ,
NILFS_BTREE_ROOT_NCHILDREN_MAX , ncblk ) ;
2009-04-07 06:01:24 +04:00
2009-05-21 19:38:56 +04:00
nilfs_btnode_delete ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_bh = NULL ;
}
2011-05-25 18:00:27 +04:00
static void nilfs_btree_nop ( struct nilfs_bmap * btree ,
struct nilfs_btree_path * path ,
int level , __u64 * keyp , __u64 * ptrp )
{
}
2009-04-07 06:01:24 +04:00
2010-07-10 14:09:49 +04:00
static int nilfs_btree_prepare_delete ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int * levelp ,
2009-08-15 10:34:33 +04:00
struct nilfs_bmap_stats * stats ,
struct inode * dat )
2009-04-07 06:01:24 +04:00
{
struct buffer_head * bh ;
struct nilfs_btree_node * node , * parent , * sib ;
__u64 sibptr ;
2011-05-25 18:00:27 +04:00
int pindex , dindex , level , ncmin , ncmax , ncblk , ret ;
2009-04-07 06:01:24 +04:00
ret = 0 ;
stats - > bs_nblocks = 0 ;
2010-07-13 18:33:52 +04:00
ncmin = NILFS_BTREE_NODE_NCHILDREN_MIN ( nilfs_btree_node_size ( btree ) ) ;
2010-07-13 18:33:53 +04:00
ncblk = nilfs_btree_nchildren_per_block ( btree ) ;
2010-07-13 18:33:52 +04:00
2011-05-25 18:00:27 +04:00
for ( level = NILFS_BTREE_LEVEL_NODE_MIN , dindex = path [ level ] . bp_index ;
2009-04-07 06:01:24 +04:00
level < nilfs_btree_height ( btree ) - 1 ;
level + + ) {
2009-08-14 20:14:10 +04:00
node = nilfs_btree_get_nonroot_node ( path , level ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_oldreq . bpr_ptr =
2011-05-25 18:00:27 +04:00
nilfs_btree_node_get_ptr ( node , dindex , ncblk ) ;
2010-07-10 14:09:49 +04:00
ret = nilfs_bmap_prepare_end_ptr ( btree ,
2009-08-15 10:34:33 +04:00
& path [ level ] . bp_oldreq , dat ) ;
2009-05-23 22:25:44 +04:00
if ( ret < 0 )
goto err_out_child_node ;
2009-04-07 06:01:24 +04:00
2010-07-13 18:33:52 +04:00
if ( nilfs_btree_node_get_nchildren ( node ) > ncmin ) {
2009-04-07 06:01:24 +04:00
path [ level ] . bp_op = nilfs_btree_do_delete ;
stats - > bs_nblocks + + ;
goto out ;
}
2010-07-13 18:33:53 +04:00
parent = nilfs_btree_get_node ( btree , path , level + 1 , & ncmax ) ;
2009-04-07 06:01:24 +04:00
pindex = path [ level + 1 ] . bp_index ;
2011-05-25 18:00:27 +04:00
dindex = pindex ;
2009-04-07 06:01:24 +04:00
if ( pindex > 0 ) {
/* left sibling */
2010-07-13 18:33:53 +04:00
sibptr = nilfs_btree_node_get_ptr ( parent , pindex - 1 ,
ncmax ) ;
2009-05-21 20:07:13 +04:00
ret = nilfs_btree_get_block ( btree , sibptr , & bh ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto err_out_curr_node ;
sib = ( struct nilfs_btree_node * ) bh - > b_data ;
2010-07-13 18:33:52 +04:00
if ( nilfs_btree_node_get_nchildren ( sib ) > ncmin ) {
2009-04-07 06:01:24 +04:00
path [ level ] . bp_sib_bh = bh ;
path [ level ] . bp_op = nilfs_btree_borrow_left ;
stats - > bs_nblocks + + ;
goto out ;
} else {
path [ level ] . bp_sib_bh = bh ;
path [ level ] . bp_op = nilfs_btree_concat_left ;
stats - > bs_nblocks + + ;
/* continue; */
}
} else if ( pindex <
2009-08-14 20:14:10 +04:00
nilfs_btree_node_get_nchildren ( parent ) - 1 ) {
2009-04-07 06:01:24 +04:00
/* right sibling */
2010-07-13 18:33:53 +04:00
sibptr = nilfs_btree_node_get_ptr ( parent , pindex + 1 ,
ncmax ) ;
2009-05-21 20:07:13 +04:00
ret = nilfs_btree_get_block ( btree , sibptr , & bh ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto err_out_curr_node ;
sib = ( struct nilfs_btree_node * ) bh - > b_data ;
2010-07-13 18:33:52 +04:00
if ( nilfs_btree_node_get_nchildren ( sib ) > ncmin ) {
2009-04-07 06:01:24 +04:00
path [ level ] . bp_sib_bh = bh ;
path [ level ] . bp_op = nilfs_btree_borrow_right ;
stats - > bs_nblocks + + ;
goto out ;
} else {
path [ level ] . bp_sib_bh = bh ;
path [ level ] . bp_op = nilfs_btree_concat_right ;
stats - > bs_nblocks + + ;
2011-05-25 18:00:27 +04:00
/*
* When merging right sibling node
* into the current node , pointer to
* the right sibling node must be
* terminated instead . The adjustment
* below is required for that .
*/
dindex = pindex + 1 ;
2009-04-07 06:01:24 +04:00
/* continue; */
}
} else {
/* no siblings */
/* the only child of the root node */
2009-04-07 06:01:55 +04:00
WARN_ON ( level ! = nilfs_btree_height ( btree ) - 2 ) ;
2009-08-14 20:14:10 +04:00
if ( nilfs_btree_node_get_nchildren ( node ) - 1 < =
2009-04-07 06:01:24 +04:00
NILFS_BTREE_ROOT_NCHILDREN_MAX ) {
path [ level ] . bp_op = nilfs_btree_shrink ;
stats - > bs_nblocks + = 2 ;
2011-05-25 18:00:27 +04:00
level + + ;
path [ level ] . bp_op = nilfs_btree_nop ;
goto shrink_root_child ;
2009-04-07 06:01:24 +04:00
} else {
path [ level ] . bp_op = nilfs_btree_do_delete ;
stats - > bs_nblocks + + ;
2011-05-25 18:00:27 +04:00
goto out ;
2009-04-07 06:01:24 +04:00
}
}
}
2011-05-25 18:00:27 +04:00
/* child of the root node is deleted */
path [ level ] . bp_op = nilfs_btree_do_delete ;
stats - > bs_nblocks + + ;
shrink_root_child :
2009-04-07 06:01:24 +04:00
node = nilfs_btree_get_root ( btree ) ;
path [ level ] . bp_oldreq . bpr_ptr =
2011-05-25 18:00:27 +04:00
nilfs_btree_node_get_ptr ( node , dindex ,
2010-07-13 18:33:53 +04:00
NILFS_BTREE_ROOT_NCHILDREN_MAX ) ;
2009-05-23 22:25:44 +04:00
2010-07-10 14:09:49 +04:00
ret = nilfs_bmap_prepare_end_ptr ( btree , & path [ level ] . bp_oldreq , dat ) ;
2009-05-23 22:25:44 +04:00
if ( ret < 0 )
goto err_out_child_node ;
2009-04-07 06:01:24 +04:00
/* success */
out :
* levelp = level ;
return ret ;
/* error */
err_out_curr_node :
2010-07-10 14:09:49 +04:00
nilfs_bmap_abort_end_ptr ( btree , & path [ level ] . bp_oldreq , dat ) ;
2009-04-07 06:01:24 +04:00
err_out_child_node :
for ( level - - ; level > = NILFS_BTREE_LEVEL_NODE_MIN ; level - - ) {
2009-05-21 19:33:13 +04:00
brelse ( path [ level ] . bp_sib_bh ) ;
2010-07-10 14:09:49 +04:00
nilfs_bmap_abort_end_ptr ( btree , & path [ level ] . bp_oldreq , dat ) ;
2009-04-07 06:01:24 +04:00
}
* levelp = level ;
stats - > bs_nblocks = 0 ;
return ret ;
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_commit_delete ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
2009-08-15 10:34:33 +04:00
int maxlevel , struct inode * dat )
2009-04-07 06:01:24 +04:00
{
int level ;
for ( level = NILFS_BTREE_LEVEL_NODE_MIN ; level < = maxlevel ; level + + ) {
2010-07-10 14:09:49 +04:00
nilfs_bmap_commit_end_ptr ( btree , & path [ level ] . bp_oldreq , dat ) ;
2009-04-07 06:01:49 +04:00
path [ level ] . bp_op ( btree , path , level , NULL , NULL ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-10 14:09:49 +04:00
if ( ! nilfs_bmap_dirty ( btree ) )
nilfs_bmap_set_dirty ( btree ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_delete ( struct nilfs_bmap * btree , __u64 key )
2009-04-07 06:01:24 +04:00
{
struct nilfs_btree_path * path ;
struct nilfs_bmap_stats stats ;
2009-08-15 10:34:33 +04:00
struct inode * dat ;
2009-04-07 06:01:24 +04:00
int level , ret ;
2009-08-14 20:14:10 +04:00
path = nilfs_btree_alloc_path ( ) ;
2009-04-07 06:01:24 +04:00
if ( path = = NULL )
return - ENOMEM ;
2010-04-02 13:36:34 +04:00
2009-04-07 06:01:24 +04:00
ret = nilfs_btree_do_lookup ( btree , path , key , NULL ,
2010-07-18 05:42:26 +04:00
NILFS_BTREE_LEVEL_NODE_MIN , 0 ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto out ;
2009-08-15 10:34:33 +04:00
2010-07-10 14:09:49 +04:00
dat = NILFS_BMAP_USE_VBN ( btree ) ? nilfs_bmap_get_dat ( btree ) : NULL ;
2009-08-15 10:34:33 +04:00
ret = nilfs_btree_prepare_delete ( btree , path , & level , & stats , dat ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto out ;
2009-08-15 10:34:33 +04:00
nilfs_btree_commit_delete ( btree , path , level , dat ) ;
2011-03-04 18:19:32 +03:00
nilfs_inode_sub_blocks ( btree - > b_inode , stats . bs_nblocks ) ;
2009-04-07 06:01:24 +04:00
out :
2009-08-14 20:14:10 +04:00
nilfs_btree_free_path ( path ) ;
2009-04-07 06:01:24 +04:00
return ret ;
}
2015-04-16 22:46:36 +03:00
static int nilfs_btree_seek_key ( const struct nilfs_bmap * btree , __u64 start ,
__u64 * keyp )
{
struct nilfs_btree_path * path ;
const int minlevel = NILFS_BTREE_LEVEL_NODE_MIN ;
int ret ;
path = nilfs_btree_alloc_path ( ) ;
if ( ! path )
return - ENOMEM ;
ret = nilfs_btree_do_lookup ( btree , path , start , NULL , minlevel , 0 ) ;
if ( ! ret )
* keyp = start ;
else if ( ret = = - ENOENT )
ret = nilfs_btree_get_next_key ( btree , path , minlevel , keyp ) ;
nilfs_btree_free_path ( path ) ;
return ret ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_last_key ( const struct nilfs_bmap * btree , __u64 * keyp )
2009-04-07 06:01:24 +04:00
{
struct nilfs_btree_path * path ;
int ret ;
2009-08-14 20:14:10 +04:00
path = nilfs_btree_alloc_path ( ) ;
2009-04-07 06:01:24 +04:00
if ( path = = NULL )
return - ENOMEM ;
ret = nilfs_btree_do_lookup_last ( btree , path , keyp , NULL ) ;
2009-08-14 20:14:10 +04:00
nilfs_btree_free_path ( path ) ;
2009-04-07 06:01:24 +04:00
return ret ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_check_delete ( struct nilfs_bmap * btree , __u64 key )
2009-04-07 06:01:24 +04:00
{
struct buffer_head * bh ;
struct nilfs_btree_node * root , * node ;
__u64 maxkey , nextmaxkey ;
__u64 ptr ;
int nchildren , ret ;
root = nilfs_btree_get_root ( btree ) ;
switch ( nilfs_btree_height ( btree ) ) {
case 2 :
bh = NULL ;
node = root ;
break ;
case 3 :
2009-08-14 20:14:10 +04:00
nchildren = nilfs_btree_node_get_nchildren ( root ) ;
2009-04-07 06:01:24 +04:00
if ( nchildren > 1 )
return 0 ;
2010-07-13 18:33:53 +04:00
ptr = nilfs_btree_node_get_ptr ( root , nchildren - 1 ,
NILFS_BTREE_ROOT_NCHILDREN_MAX ) ;
2009-05-21 20:07:13 +04:00
ret = nilfs_btree_get_block ( btree , ptr , & bh ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
return ret ;
node = ( struct nilfs_btree_node * ) bh - > b_data ;
break ;
default :
return 0 ;
}
2009-08-14 20:14:10 +04:00
nchildren = nilfs_btree_node_get_nchildren ( node ) ;
maxkey = nilfs_btree_node_get_key ( node , nchildren - 1 ) ;
2009-04-07 06:01:24 +04:00
nextmaxkey = ( nchildren > 1 ) ?
2009-08-14 20:14:10 +04:00
nilfs_btree_node_get_key ( node , nchildren - 2 ) : 0 ;
2009-04-07 06:01:24 +04:00
if ( bh ! = NULL )
2009-05-21 19:33:13 +04:00
brelse ( bh ) ;
2009-04-07 06:01:24 +04:00
2009-05-23 19:09:44 +04:00
return ( maxkey = = key ) & & ( nextmaxkey < NILFS_BMAP_LARGE_LOW ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_gather_data ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
__u64 * keys , __u64 * ptrs , int nitems )
{
struct buffer_head * bh ;
struct nilfs_btree_node * node , * root ;
__le64 * dkeys ;
__le64 * dptrs ;
__u64 ptr ;
2010-07-13 18:33:53 +04:00
int nchildren , ncmax , i , ret ;
2009-04-07 06:01:24 +04:00
root = nilfs_btree_get_root ( btree ) ;
switch ( nilfs_btree_height ( btree ) ) {
case 2 :
bh = NULL ;
node = root ;
2010-07-13 18:33:53 +04:00
ncmax = NILFS_BTREE_ROOT_NCHILDREN_MAX ;
2009-04-07 06:01:24 +04:00
break ;
case 3 :
2009-08-14 20:14:10 +04:00
nchildren = nilfs_btree_node_get_nchildren ( root ) ;
2009-04-07 06:01:55 +04:00
WARN_ON ( nchildren > 1 ) ;
2010-07-13 18:33:53 +04:00
ptr = nilfs_btree_node_get_ptr ( root , nchildren - 1 ,
NILFS_BTREE_ROOT_NCHILDREN_MAX ) ;
2009-05-21 20:07:13 +04:00
ret = nilfs_btree_get_block ( btree , ptr , & bh ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
return ret ;
node = ( struct nilfs_btree_node * ) bh - > b_data ;
2010-07-13 18:33:53 +04:00
ncmax = nilfs_btree_nchildren_per_block ( btree ) ;
2009-04-07 06:01:24 +04:00
break ;
default :
node = NULL ;
2009-04-07 06:01:55 +04:00
return - EINVAL ;
2009-04-07 06:01:24 +04:00
}
2009-08-14 20:14:10 +04:00
nchildren = nilfs_btree_node_get_nchildren ( node ) ;
2009-04-07 06:01:24 +04:00
if ( nchildren < nitems )
nitems = nchildren ;
2009-08-14 20:14:10 +04:00
dkeys = nilfs_btree_node_dkeys ( node ) ;
2010-07-13 18:33:53 +04:00
dptrs = nilfs_btree_node_dptrs ( node , ncmax ) ;
2009-04-07 06:01:24 +04:00
for ( i = 0 ; i < nitems ; i + + ) {
2010-07-10 11:50:41 +04:00
keys [ i ] = le64_to_cpu ( dkeys [ i ] ) ;
ptrs [ i ] = le64_to_cpu ( dptrs [ i ] ) ;
2009-04-07 06:01:24 +04:00
}
if ( bh ! = NULL )
2009-05-21 19:33:13 +04:00
brelse ( bh ) ;
2009-04-07 06:01:24 +04:00
return nitems ;
}
static int
2010-07-10 14:09:49 +04:00
nilfs_btree_prepare_convert_and_insert ( struct nilfs_bmap * btree , __u64 key ,
2009-04-07 06:01:24 +04:00
union nilfs_bmap_ptr_req * dreq ,
union nilfs_bmap_ptr_req * nreq ,
struct buffer_head * * bhp ,
struct nilfs_bmap_stats * stats )
{
struct buffer_head * bh ;
2009-08-15 10:34:33 +04:00
struct inode * dat = NULL ;
2009-04-07 06:01:24 +04:00
int ret ;
stats - > bs_nblocks = 0 ;
/* for data */
/* cannot find near ptr */
2010-07-10 14:09:49 +04:00
if ( NILFS_BMAP_USE_VBN ( btree ) ) {
2009-05-24 13:07:59 +04:00
dreq - > bpr_ptr = nilfs_btree_find_target_v ( btree , NULL , key ) ;
2010-07-10 14:09:49 +04:00
dat = nilfs_bmap_get_dat ( btree ) ;
2009-08-15 10:34:33 +04:00
}
2009-05-24 13:07:59 +04:00
2010-07-10 14:09:49 +04:00
ret = nilfs_bmap_prepare_alloc_ptr ( btree , dreq , dat ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
return ret ;
* bhp = NULL ;
stats - > bs_nblocks + + ;
if ( nreq ! = NULL ) {
nreq - > bpr_ptr = dreq - > bpr_ptr + 1 ;
2010-07-10 14:09:49 +04:00
ret = nilfs_bmap_prepare_alloc_ptr ( btree , nreq , dat ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto err_out_dreq ;
2009-05-21 20:07:13 +04:00
ret = nilfs_btree_get_new_block ( btree , nreq - > bpr_ptr , & bh ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto err_out_nreq ;
* bhp = bh ;
stats - > bs_nblocks + + ;
}
/* success */
return 0 ;
/* error */
err_out_nreq :
2010-07-10 14:09:49 +04:00
nilfs_bmap_abort_alloc_ptr ( btree , nreq , dat ) ;
2009-04-07 06:01:24 +04:00
err_out_dreq :
2010-07-10 14:09:49 +04:00
nilfs_bmap_abort_alloc_ptr ( btree , dreq , dat ) ;
2009-04-07 06:01:24 +04:00
stats - > bs_nblocks = 0 ;
return ret ;
}
static void
2010-07-10 14:09:49 +04:00
nilfs_btree_commit_convert_and_insert ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
__u64 key , __u64 ptr ,
const __u64 * keys , const __u64 * ptrs ,
2009-05-23 19:09:44 +04:00
int n ,
2009-04-07 06:01:24 +04:00
union nilfs_bmap_ptr_req * dreq ,
union nilfs_bmap_ptr_req * nreq ,
struct buffer_head * bh )
{
struct nilfs_btree_node * node ;
2009-08-15 10:34:33 +04:00
struct inode * dat ;
2009-04-07 06:01:24 +04:00
__u64 tmpptr ;
2010-07-13 18:33:53 +04:00
int ncblk ;
2009-04-07 06:01:24 +04:00
/* free resources */
2010-07-10 14:09:49 +04:00
if ( btree - > b_ops - > bop_clear ! = NULL )
btree - > b_ops - > bop_clear ( btree ) ;
2009-04-07 06:01:24 +04:00
/* ptr must be a pointer to a buffer head. */
set_buffer_nilfs_volatile ( ( struct buffer_head * ) ( ( unsigned long ) ptr ) ) ;
/* convert and insert */
2010-07-10 14:09:49 +04:00
dat = NILFS_BMAP_USE_VBN ( btree ) ? nilfs_bmap_get_dat ( btree ) : NULL ;
2015-02-28 02:51:56 +03:00
__nilfs_btree_init ( btree ) ;
2009-04-07 06:01:24 +04:00
if ( nreq ! = NULL ) {
2010-07-10 14:09:49 +04:00
nilfs_bmap_commit_alloc_ptr ( btree , dreq , dat ) ;
nilfs_bmap_commit_alloc_ptr ( btree , nreq , dat ) ;
2009-04-07 06:01:24 +04:00
/* create child node at level 1 */
node = ( struct nilfs_btree_node * ) bh - > b_data ;
2010-07-13 18:33:53 +04:00
ncblk = nilfs_btree_nchildren_per_block ( btree ) ;
nilfs_btree_node_init ( node , 0 , 1 , n , ncblk , keys , ptrs ) ;
nilfs_btree_node_insert ( node , n , key , dreq - > bpr_ptr , ncblk ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_dirty ( bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( bh ) ;
2010-07-10 14:09:49 +04:00
if ( ! nilfs_bmap_dirty ( btree ) )
nilfs_bmap_set_dirty ( btree ) ;
2009-04-07 06:01:24 +04:00
2009-05-21 19:33:13 +04:00
brelse ( bh ) ;
2009-04-07 06:01:24 +04:00
/* create root node at level 2 */
node = nilfs_btree_get_root ( btree ) ;
tmpptr = nreq - > bpr_ptr ;
2010-07-13 18:33:53 +04:00
nilfs_btree_node_init ( node , NILFS_BTREE_NODE_ROOT , 2 , 1 ,
NILFS_BTREE_ROOT_NCHILDREN_MAX ,
& keys [ 0 ] , & tmpptr ) ;
2009-04-07 06:01:24 +04:00
} else {
2010-07-10 14:09:49 +04:00
nilfs_bmap_commit_alloc_ptr ( btree , dreq , dat ) ;
2009-04-07 06:01:24 +04:00
/* create root node at level 1 */
node = nilfs_btree_get_root ( btree ) ;
2010-07-13 18:33:53 +04:00
nilfs_btree_node_init ( node , NILFS_BTREE_NODE_ROOT , 1 , n ,
NILFS_BTREE_ROOT_NCHILDREN_MAX ,
keys , ptrs ) ;
nilfs_btree_node_insert ( node , n , key , dreq - > bpr_ptr ,
NILFS_BTREE_ROOT_NCHILDREN_MAX ) ;
2010-07-10 14:09:49 +04:00
if ( ! nilfs_bmap_dirty ( btree ) )
nilfs_bmap_set_dirty ( btree ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-10 14:09:49 +04:00
if ( NILFS_BMAP_USE_VBN ( btree ) )
2010-07-10 17:21:54 +04:00
nilfs_bmap_set_target_v ( btree , key , dreq - > bpr_ptr ) ;
2009-04-07 06:01:24 +04:00
}
/**
* nilfs_btree_convert_and_insert -
* @ bmap :
* @ key :
* @ ptr :
* @ keys :
* @ ptrs :
* @ n :
*/
2010-07-10 14:09:49 +04:00
int nilfs_btree_convert_and_insert ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
__u64 key , __u64 ptr ,
2009-05-23 19:09:44 +04:00
const __u64 * keys , const __u64 * ptrs , int n )
2009-04-07 06:01:24 +04:00
{
2015-11-07 03:32:16 +03:00
struct buffer_head * bh = NULL ;
2009-04-07 06:01:24 +04:00
union nilfs_bmap_ptr_req dreq , nreq , * di , * ni ;
struct nilfs_bmap_stats stats ;
int ret ;
if ( n + 1 < = NILFS_BTREE_ROOT_NCHILDREN_MAX ) {
di = & dreq ;
ni = NULL ;
} else if ( ( n + 1 ) < = NILFS_BTREE_NODE_NCHILDREN_MAX (
2010-07-10 14:09:49 +04:00
1 < < btree - > b_inode - > i_blkbits ) ) {
2009-04-07 06:01:24 +04:00
di = & dreq ;
ni = & nreq ;
} else {
di = NULL ;
ni = NULL ;
BUG ( ) ;
}
2010-07-10 14:09:49 +04:00
ret = nilfs_btree_prepare_convert_and_insert ( btree , key , di , ni , & bh ,
2009-04-07 06:01:24 +04:00
& stats ) ;
if ( ret < 0 )
return ret ;
2010-07-10 14:09:49 +04:00
nilfs_btree_commit_convert_and_insert ( btree , key , ptr , keys , ptrs , n ,
2009-05-23 19:09:44 +04:00
di , ni , bh ) ;
2011-03-04 18:19:32 +03:00
nilfs_inode_add_blocks ( btree - > b_inode , stats . bs_nblocks ) ;
2009-04-07 06:01:24 +04:00
return 0 ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_propagate_p ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level ,
struct buffer_head * bh )
{
while ( ( + + level < nilfs_btree_height ( btree ) - 1 ) & &
! buffer_dirty ( path [ level ] . bp_bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( path [ level ] . bp_bh ) ;
2009-04-07 06:01:24 +04:00
return 0 ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_prepare_update_v ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
2009-08-15 10:34:33 +04:00
int level , struct inode * dat )
2009-04-07 06:01:24 +04:00
{
struct nilfs_btree_node * parent ;
2010-07-13 18:33:53 +04:00
int ncmax , ret ;
2009-04-07 06:01:24 +04:00
2010-07-13 18:33:53 +04:00
parent = nilfs_btree_get_node ( btree , path , level + 1 , & ncmax ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_oldreq . bpr_ptr =
2010-07-13 18:33:53 +04:00
nilfs_btree_node_get_ptr ( parent , path [ level + 1 ] . bp_index ,
ncmax ) ;
2009-04-07 06:01:24 +04:00
path [ level ] . bp_newreq . bpr_ptr = path [ level ] . bp_oldreq . bpr_ptr + 1 ;
2009-08-15 10:34:33 +04:00
ret = nilfs_dat_prepare_update ( dat , & path [ level ] . bp_oldreq . bpr_req ,
& path [ level ] . bp_newreq . bpr_req ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
return ret ;
if ( buffer_nilfs_node ( path [ level ] . bp_bh ) ) {
path [ level ] . bp_ctxt . oldkey = path [ level ] . bp_oldreq . bpr_ptr ;
path [ level ] . bp_ctxt . newkey = path [ level ] . bp_newreq . bpr_ptr ;
path [ level ] . bp_ctxt . bh = path [ level ] . bp_bh ;
ret = nilfs_btnode_prepare_change_key (
2010-07-10 14:09:49 +04:00
& NILFS_BMAP_I ( btree ) - > i_btnode_cache ,
2009-04-07 06:01:24 +04:00
& path [ level ] . bp_ctxt ) ;
if ( ret < 0 ) {
2009-08-15 10:34:33 +04:00
nilfs_dat_abort_update ( dat ,
& path [ level ] . bp_oldreq . bpr_req ,
& path [ level ] . bp_newreq . bpr_req ) ;
2009-04-07 06:01:24 +04:00
return ret ;
}
}
return 0 ;
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_commit_update_v ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
2009-08-15 10:34:33 +04:00
int level , struct inode * dat )
2009-04-07 06:01:24 +04:00
{
struct nilfs_btree_node * parent ;
2010-07-13 18:33:53 +04:00
int ncmax ;
2009-04-07 06:01:24 +04:00
2009-08-15 10:34:33 +04:00
nilfs_dat_commit_update ( dat , & path [ level ] . bp_oldreq . bpr_req ,
& path [ level ] . bp_newreq . bpr_req ,
2010-07-10 14:09:49 +04:00
btree - > b_ptr_type = = NILFS_BMAP_PTR_VS ) ;
2009-04-07 06:01:24 +04:00
if ( buffer_nilfs_node ( path [ level ] . bp_bh ) ) {
nilfs_btnode_commit_change_key (
2010-07-10 14:09:49 +04:00
& NILFS_BMAP_I ( btree ) - > i_btnode_cache ,
2009-04-07 06:01:24 +04:00
& path [ level ] . bp_ctxt ) ;
path [ level ] . bp_bh = path [ level ] . bp_ctxt . bh ;
}
set_buffer_nilfs_volatile ( path [ level ] . bp_bh ) ;
2010-07-13 18:33:53 +04:00
parent = nilfs_btree_get_node ( btree , path , level + 1 , & ncmax ) ;
nilfs_btree_node_set_ptr ( parent , path [ level + 1 ] . bp_index ,
path [ level ] . bp_newreq . bpr_ptr , ncmax ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_abort_update_v ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
2009-08-15 10:34:33 +04:00
int level , struct inode * dat )
2009-04-07 06:01:24 +04:00
{
2009-08-15 10:34:33 +04:00
nilfs_dat_abort_update ( dat , & path [ level ] . bp_oldreq . bpr_req ,
& path [ level ] . bp_newreq . bpr_req ) ;
2009-04-07 06:01:24 +04:00
if ( buffer_nilfs_node ( path [ level ] . bp_bh ) )
nilfs_btnode_abort_change_key (
2010-07-10 14:09:49 +04:00
& NILFS_BMAP_I ( btree ) - > i_btnode_cache ,
2009-04-07 06:01:24 +04:00
& path [ level ] . bp_ctxt ) ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_prepare_propagate_v ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
2009-08-15 10:34:33 +04:00
int minlevel , int * maxlevelp ,
struct inode * dat )
2009-04-07 06:01:24 +04:00
{
int level , ret ;
level = minlevel ;
if ( ! buffer_nilfs_volatile ( path [ level ] . bp_bh ) ) {
2009-08-15 10:34:33 +04:00
ret = nilfs_btree_prepare_update_v ( btree , path , level , dat ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
return ret ;
}
while ( ( + + level < nilfs_btree_height ( btree ) - 1 ) & &
! buffer_dirty ( path [ level ] . bp_bh ) ) {
2009-04-07 06:01:55 +04:00
WARN_ON ( buffer_nilfs_volatile ( path [ level ] . bp_bh ) ) ;
2009-08-15 10:34:33 +04:00
ret = nilfs_btree_prepare_update_v ( btree , path , level , dat ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto out ;
}
/* success */
* maxlevelp = level - 1 ;
return 0 ;
/* error */
out :
while ( - - level > minlevel )
2009-08-15 10:34:33 +04:00
nilfs_btree_abort_update_v ( btree , path , level , dat ) ;
2009-04-07 06:01:24 +04:00
if ( ! buffer_nilfs_volatile ( path [ level ] . bp_bh ) )
2009-08-15 10:34:33 +04:00
nilfs_btree_abort_update_v ( btree , path , level , dat ) ;
2009-04-07 06:01:24 +04:00
return ret ;
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_commit_propagate_v ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
2009-08-15 10:34:33 +04:00
int minlevel , int maxlevel ,
struct buffer_head * bh ,
struct inode * dat )
2009-04-07 06:01:24 +04:00
{
int level ;
if ( ! buffer_nilfs_volatile ( path [ minlevel ] . bp_bh ) )
2009-08-15 10:34:33 +04:00
nilfs_btree_commit_update_v ( btree , path , minlevel , dat ) ;
2009-04-07 06:01:24 +04:00
for ( level = minlevel + 1 ; level < = maxlevel ; level + + )
2009-08-15 10:34:33 +04:00
nilfs_btree_commit_update_v ( btree , path , level , dat ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_propagate_v ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
2009-08-15 10:34:33 +04:00
int level , struct buffer_head * bh )
2009-04-07 06:01:24 +04:00
{
2010-04-02 14:40:39 +04:00
int maxlevel = 0 , ret ;
2009-04-07 06:01:24 +04:00
struct nilfs_btree_node * parent ;
2010-07-10 14:09:49 +04:00
struct inode * dat = nilfs_bmap_get_dat ( btree ) ;
2009-04-07 06:01:24 +04:00
__u64 ptr ;
2010-07-13 18:33:53 +04:00
int ncmax ;
2009-04-07 06:01:24 +04:00
get_bh ( bh ) ;
path [ level ] . bp_bh = bh ;
2009-08-15 10:34:33 +04:00
ret = nilfs_btree_prepare_propagate_v ( btree , path , level , & maxlevel ,
dat ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto out ;
if ( buffer_nilfs_volatile ( path [ level ] . bp_bh ) ) {
2010-07-13 18:33:53 +04:00
parent = nilfs_btree_get_node ( btree , path , level + 1 , & ncmax ) ;
ptr = nilfs_btree_node_get_ptr ( parent ,
path [ level + 1 ] . bp_index ,
ncmax ) ;
2009-08-15 10:34:33 +04:00
ret = nilfs_dat_mark_dirty ( dat , ptr ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
goto out ;
}
2009-08-15 10:34:33 +04:00
nilfs_btree_commit_propagate_v ( btree , path , level , maxlevel , bh , dat ) ;
2009-04-07 06:01:24 +04:00
out :
brelse ( path [ level ] . bp_bh ) ;
path [ level ] . bp_bh = NULL ;
return ret ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_propagate ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct buffer_head * bh )
{
struct nilfs_btree_path * path ;
struct nilfs_btree_node * node ;
__u64 key ;
int level , ret ;
2009-04-07 06:01:55 +04:00
WARN_ON ( ! buffer_dirty ( bh ) ) ;
2009-04-07 06:01:24 +04:00
2009-08-14 20:14:10 +04:00
path = nilfs_btree_alloc_path ( ) ;
2009-04-07 06:01:24 +04:00
if ( path = = NULL )
return - ENOMEM ;
if ( buffer_nilfs_node ( bh ) ) {
node = ( struct nilfs_btree_node * ) bh - > b_data ;
2009-08-14 20:14:10 +04:00
key = nilfs_btree_node_get_key ( node , 0 ) ;
level = nilfs_btree_node_get_level ( node ) ;
2009-04-07 06:01:24 +04:00
} else {
2010-07-10 14:09:49 +04:00
key = nilfs_bmap_data_get_key ( btree , bh ) ;
2009-04-07 06:01:24 +04:00
level = NILFS_BTREE_LEVEL_DATA ;
}
2010-07-18 05:42:26 +04:00
ret = nilfs_btree_do_lookup ( btree , path , key , NULL , level + 1 , 0 ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 ) {
2009-04-07 06:01:55 +04:00
if ( unlikely ( ret = = - ENOENT ) )
2009-04-07 06:01:24 +04:00
printk ( KERN_CRIT " %s: key = %llu, level == %d \n " ,
__func__ , ( unsigned long long ) key , level ) ;
goto out ;
}
2010-07-10 14:09:49 +04:00
ret = NILFS_BMAP_USE_VBN ( btree ) ?
2009-05-24 13:07:59 +04:00
nilfs_btree_propagate_v ( btree , path , level , bh ) :
nilfs_btree_propagate_p ( btree , path , level , bh ) ;
2009-04-07 06:01:24 +04:00
out :
2009-08-14 20:14:10 +04:00
nilfs_btree_free_path ( path ) ;
2009-04-07 06:01:24 +04:00
return ret ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_propagate_gc ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct buffer_head * bh )
{
2010-07-10 14:09:49 +04:00
return nilfs_dat_mark_dirty ( nilfs_bmap_get_dat ( btree ) , bh - > b_blocknr ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_add_dirty_buffer ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct list_head * lists ,
struct buffer_head * bh )
{
struct list_head * head ;
struct buffer_head * cbh ;
struct nilfs_btree_node * node , * cnode ;
__u64 key , ckey ;
int level ;
get_bh ( bh ) ;
node = ( struct nilfs_btree_node * ) bh - > b_data ;
2009-08-14 20:14:10 +04:00
key = nilfs_btree_node_get_key ( node , 0 ) ;
level = nilfs_btree_node_get_level ( node ) ;
2010-07-07 12:19:54 +04:00
if ( level < NILFS_BTREE_LEVEL_NODE_MIN | |
level > = NILFS_BTREE_LEVEL_MAX ) {
dump_stack ( ) ;
printk ( KERN_WARNING
" %s: invalid btree level: %d (key=%llu, ino=%lu, "
" blocknr=%llu) \n " ,
__func__ , level , ( unsigned long long ) key ,
2010-07-10 14:09:49 +04:00
NILFS_BMAP_I ( btree ) - > vfs_inode . i_ino ,
2010-07-07 12:19:54 +04:00
( unsigned long long ) bh - > b_blocknr ) ;
return ;
}
2009-04-07 06:01:24 +04:00
list_for_each ( head , & lists [ level ] ) {
cbh = list_entry ( head , struct buffer_head , b_assoc_buffers ) ;
cnode = ( struct nilfs_btree_node * ) cbh - > b_data ;
2009-08-14 20:14:10 +04:00
ckey = nilfs_btree_node_get_key ( cnode , 0 ) ;
2009-04-07 06:01:24 +04:00
if ( key < ckey )
break ;
}
list_add_tail ( & bh - > b_assoc_buffers , head ) ;
}
2010-07-10 14:09:49 +04:00
static void nilfs_btree_lookup_dirty_buffers ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct list_head * listp )
{
2010-07-10 14:09:49 +04:00
struct address_space * btcache = & NILFS_BMAP_I ( btree ) - > i_btnode_cache ;
2009-04-07 06:01:24 +04:00
struct list_head lists [ NILFS_BTREE_LEVEL_MAX ] ;
struct pagevec pvec ;
struct buffer_head * bh , * head ;
pgoff_t index = 0 ;
int level , i ;
for ( level = NILFS_BTREE_LEVEL_NODE_MIN ;
level < NILFS_BTREE_LEVEL_MAX ;
level + + )
INIT_LIST_HEAD ( & lists [ level ] ) ;
pagevec_init ( & pvec , 0 ) ;
while ( pagevec_lookup_tag ( & pvec , btcache , & index , PAGECACHE_TAG_DIRTY ,
PAGEVEC_SIZE ) ) {
for ( i = 0 ; i < pagevec_count ( & pvec ) ; i + + ) {
bh = head = page_buffers ( pvec . pages [ i ] ) ;
do {
if ( buffer_dirty ( bh ) )
nilfs_btree_add_dirty_buffer ( btree ,
lists , bh ) ;
} while ( ( bh = bh - > b_this_page ) ! = head ) ;
}
pagevec_release ( & pvec ) ;
cond_resched ( ) ;
}
for ( level = NILFS_BTREE_LEVEL_NODE_MIN ;
level < NILFS_BTREE_LEVEL_MAX ;
level + + )
2009-11-28 20:39:11 +03:00
list_splice_tail ( & lists [ level ] , listp ) ;
2009-04-07 06:01:24 +04:00
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_assign_p ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level ,
struct buffer_head * * bh ,
sector_t blocknr ,
union nilfs_binfo * binfo )
{
struct nilfs_btree_node * parent ;
__u64 key ;
__u64 ptr ;
2010-07-13 18:33:53 +04:00
int ncmax , ret ;
2009-04-07 06:01:24 +04:00
2010-07-13 18:33:53 +04:00
parent = nilfs_btree_get_node ( btree , path , level + 1 , & ncmax ) ;
ptr = nilfs_btree_node_get_ptr ( parent , path [ level + 1 ] . bp_index ,
ncmax ) ;
2009-04-07 06:01:24 +04:00
if ( buffer_nilfs_node ( * bh ) ) {
path [ level ] . bp_ctxt . oldkey = ptr ;
path [ level ] . bp_ctxt . newkey = blocknr ;
path [ level ] . bp_ctxt . bh = * bh ;
ret = nilfs_btnode_prepare_change_key (
2010-07-10 14:09:49 +04:00
& NILFS_BMAP_I ( btree ) - > i_btnode_cache ,
2009-04-07 06:01:24 +04:00
& path [ level ] . bp_ctxt ) ;
if ( ret < 0 )
return ret ;
nilfs_btnode_commit_change_key (
2010-07-10 14:09:49 +04:00
& NILFS_BMAP_I ( btree ) - > i_btnode_cache ,
2009-04-07 06:01:24 +04:00
& path [ level ] . bp_ctxt ) ;
* bh = path [ level ] . bp_ctxt . bh ;
}
2010-07-13 18:33:53 +04:00
nilfs_btree_node_set_ptr ( parent , path [ level + 1 ] . bp_index , blocknr ,
ncmax ) ;
2009-04-07 06:01:24 +04:00
2009-08-14 20:14:10 +04:00
key = nilfs_btree_node_get_key ( parent , path [ level + 1 ] . bp_index ) ;
2009-04-07 06:01:24 +04:00
/* on-disk format */
2010-07-10 11:50:41 +04:00
binfo - > bi_dat . bi_blkoff = cpu_to_le64 ( key ) ;
2009-04-07 06:01:24 +04:00
binfo - > bi_dat . bi_level = level ;
return 0 ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_assign_v ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct nilfs_btree_path * path ,
int level ,
struct buffer_head * * bh ,
sector_t blocknr ,
union nilfs_binfo * binfo )
{
struct nilfs_btree_node * parent ;
2010-07-10 14:09:49 +04:00
struct inode * dat = nilfs_bmap_get_dat ( btree ) ;
2009-04-07 06:01:24 +04:00
__u64 key ;
__u64 ptr ;
union nilfs_bmap_ptr_req req ;
2010-07-13 18:33:53 +04:00
int ncmax , ret ;
2009-04-07 06:01:24 +04:00
2010-07-13 18:33:53 +04:00
parent = nilfs_btree_get_node ( btree , path , level + 1 , & ncmax ) ;
ptr = nilfs_btree_node_get_ptr ( parent , path [ level + 1 ] . bp_index ,
ncmax ) ;
2009-04-07 06:01:24 +04:00
req . bpr_ptr = ptr ;
2009-08-15 10:34:33 +04:00
ret = nilfs_dat_prepare_start ( dat , & req . bpr_req ) ;
if ( ret < 0 )
2009-04-07 06:01:24 +04:00
return ret ;
2009-08-15 10:34:33 +04:00
nilfs_dat_commit_start ( dat , & req . bpr_req , blocknr ) ;
2009-04-07 06:01:24 +04:00
2009-08-14 20:14:10 +04:00
key = nilfs_btree_node_get_key ( parent , path [ level + 1 ] . bp_index ) ;
2009-04-07 06:01:24 +04:00
/* on-disk format */
2010-07-10 11:50:41 +04:00
binfo - > bi_v . bi_vblocknr = cpu_to_le64 ( ptr ) ;
binfo - > bi_v . bi_blkoff = cpu_to_le64 ( key ) ;
2009-04-07 06:01:24 +04:00
return 0 ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_assign ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct buffer_head * * bh ,
sector_t blocknr ,
union nilfs_binfo * binfo )
{
struct nilfs_btree_path * path ;
struct nilfs_btree_node * node ;
__u64 key ;
int level , ret ;
2009-08-14 20:14:10 +04:00
path = nilfs_btree_alloc_path ( ) ;
2009-04-07 06:01:24 +04:00
if ( path = = NULL )
return - ENOMEM ;
if ( buffer_nilfs_node ( * bh ) ) {
node = ( struct nilfs_btree_node * ) ( * bh ) - > b_data ;
2009-08-14 20:14:10 +04:00
key = nilfs_btree_node_get_key ( node , 0 ) ;
level = nilfs_btree_node_get_level ( node ) ;
2009-04-07 06:01:24 +04:00
} else {
2010-07-10 14:09:49 +04:00
key = nilfs_bmap_data_get_key ( btree , * bh ) ;
2009-04-07 06:01:24 +04:00
level = NILFS_BTREE_LEVEL_DATA ;
}
2010-07-18 05:42:26 +04:00
ret = nilfs_btree_do_lookup ( btree , path , key , NULL , level + 1 , 0 ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 ) {
2009-04-07 06:01:55 +04:00
WARN_ON ( ret = = - ENOENT ) ;
2009-04-07 06:01:24 +04:00
goto out ;
}
2010-07-10 14:09:49 +04:00
ret = NILFS_BMAP_USE_VBN ( btree ) ?
2009-05-24 13:07:59 +04:00
nilfs_btree_assign_v ( btree , path , level , bh , blocknr , binfo ) :
nilfs_btree_assign_p ( btree , path , level , bh , blocknr , binfo ) ;
2009-04-07 06:01:24 +04:00
out :
2009-08-14 20:14:10 +04:00
nilfs_btree_free_path ( path ) ;
2009-04-07 06:01:24 +04:00
return ret ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_assign_gc ( struct nilfs_bmap * btree ,
2009-04-07 06:01:24 +04:00
struct buffer_head * * bh ,
sector_t blocknr ,
union nilfs_binfo * binfo )
{
struct nilfs_btree_node * node ;
__u64 key ;
int ret ;
2010-07-10 14:09:49 +04:00
ret = nilfs_dat_move ( nilfs_bmap_get_dat ( btree ) , ( * bh ) - > b_blocknr ,
2009-08-15 10:34:33 +04:00
blocknr ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 )
return ret ;
if ( buffer_nilfs_node ( * bh ) ) {
node = ( struct nilfs_btree_node * ) ( * bh ) - > b_data ;
2009-08-14 20:14:10 +04:00
key = nilfs_btree_node_get_key ( node , 0 ) ;
2009-04-07 06:01:24 +04:00
} else
2010-07-10 14:09:49 +04:00
key = nilfs_bmap_data_get_key ( btree , * bh ) ;
2009-04-07 06:01:24 +04:00
/* on-disk format */
binfo - > bi_v . bi_vblocknr = cpu_to_le64 ( ( * bh ) - > b_blocknr ) ;
2010-07-10 11:50:41 +04:00
binfo - > bi_v . bi_blkoff = cpu_to_le64 ( key ) ;
2009-04-07 06:01:24 +04:00
return 0 ;
}
2010-07-10 14:09:49 +04:00
static int nilfs_btree_mark ( struct nilfs_bmap * btree , __u64 key , int level )
2009-04-07 06:01:24 +04:00
{
struct buffer_head * bh ;
struct nilfs_btree_path * path ;
__u64 ptr ;
int ret ;
2009-08-14 20:14:10 +04:00
path = nilfs_btree_alloc_path ( ) ;
2009-04-07 06:01:24 +04:00
if ( path = = NULL )
return - ENOMEM ;
2010-07-18 05:42:26 +04:00
ret = nilfs_btree_do_lookup ( btree , path , key , & ptr , level + 1 , 0 ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 ) {
2009-04-07 06:01:55 +04:00
WARN_ON ( ret = = - ENOENT ) ;
2009-04-07 06:01:24 +04:00
goto out ;
}
2009-05-21 20:07:13 +04:00
ret = nilfs_btree_get_block ( btree , ptr , & bh ) ;
2009-04-07 06:01:24 +04:00
if ( ret < 0 ) {
2009-04-07 06:01:55 +04:00
WARN_ON ( ret = = - ENOENT ) ;
2009-04-07 06:01:24 +04:00
goto out ;
}
if ( ! buffer_dirty ( bh ) )
2011-05-05 07:56:51 +04:00
mark_buffer_dirty ( bh ) ;
2009-05-21 19:33:13 +04:00
brelse ( bh ) ;
2010-07-10 14:09:49 +04:00
if ( ! nilfs_bmap_dirty ( btree ) )
nilfs_bmap_set_dirty ( btree ) ;
2009-04-07 06:01:24 +04:00
out :
2009-08-14 20:14:10 +04:00
nilfs_btree_free_path ( path ) ;
2009-04-07 06:01:24 +04:00
return ret ;
}
static const struct nilfs_bmap_operations nilfs_btree_ops = {
. bop_lookup = nilfs_btree_lookup ,
2009-05-24 21:47:14 +04:00
. bop_lookup_contig = nilfs_btree_lookup_contig ,
2009-04-07 06:01:24 +04:00
. bop_insert = nilfs_btree_insert ,
. bop_delete = nilfs_btree_delete ,
. bop_clear = NULL ,
. bop_propagate = nilfs_btree_propagate ,
. bop_lookup_dirty_buffers = nilfs_btree_lookup_dirty_buffers ,
. bop_assign = nilfs_btree_assign ,
. bop_mark = nilfs_btree_mark ,
2015-04-16 22:46:36 +03:00
. bop_seek_key = nilfs_btree_seek_key ,
2009-04-07 06:01:24 +04:00
. bop_last_key = nilfs_btree_last_key ,
2015-04-16 22:46:36 +03:00
2009-04-07 06:01:24 +04:00
. bop_check_insert = NULL ,
. bop_check_delete = nilfs_btree_check_delete ,
. bop_gather_data = nilfs_btree_gather_data ,
} ;
static const struct nilfs_bmap_operations nilfs_btree_ops_gc = {
. bop_lookup = NULL ,
2009-05-24 21:47:14 +04:00
. bop_lookup_contig = NULL ,
2009-04-07 06:01:24 +04:00
. bop_insert = NULL ,
. bop_delete = NULL ,
. bop_clear = NULL ,
. bop_propagate = nilfs_btree_propagate_gc ,
. bop_lookup_dirty_buffers = nilfs_btree_lookup_dirty_buffers ,
. bop_assign = nilfs_btree_assign_gc ,
. bop_mark = NULL ,
2015-04-16 22:46:36 +03:00
. bop_seek_key = NULL ,
2009-04-07 06:01:24 +04:00
. bop_last_key = NULL ,
2015-04-16 22:46:36 +03:00
2009-04-07 06:01:24 +04:00
. bop_check_insert = NULL ,
. bop_check_delete = NULL ,
. bop_gather_data = NULL ,
} ;
2015-02-28 02:51:56 +03:00
static void __nilfs_btree_init ( struct nilfs_bmap * bmap )
2009-04-07 06:01:24 +04:00
{
bmap - > b_ops = & nilfs_btree_ops ;
2010-07-13 18:33:54 +04:00
bmap - > b_nchildren_per_block =
NILFS_BTREE_NODE_NCHILDREN_MAX ( nilfs_btree_node_size ( bmap ) ) ;
2015-02-28 02:51:56 +03:00
}
int nilfs_btree_init ( struct nilfs_bmap * bmap )
{
int ret = 0 ;
__nilfs_btree_init ( bmap ) ;
if ( nilfs_btree_root_broken ( nilfs_btree_get_root ( bmap ) ,
bmap - > b_inode - > i_ino ) )
ret = - EIO ;
return ret ;
2009-04-07 06:01:24 +04:00
}
void nilfs_btree_init_gc ( struct nilfs_bmap * bmap )
{
bmap - > b_ops = & nilfs_btree_ops_gc ;
2010-07-13 18:33:54 +04:00
bmap - > b_nchildren_per_block =
NILFS_BTREE_NODE_NCHILDREN_MAX ( nilfs_btree_node_size ( bmap ) ) ;
2009-04-07 06:01:24 +04:00
}