2005-04-17 02:20:36 +04:00
/*
* Copyright 2000 by Hans Reiser , licensing governed by reiserfs / README
*/
/* Now we have all buffers that must be used in balancing of the tree */
/* Further calculations can not cause schedule(), and thus the buffer */
/* tree will be stable until the balancing will be finished */
/* balance the tree according to the analysis made before, */
/* and using buffers obtained after all above. */
/**
* * balance_leaf_when_delete
* * balance_leaf
* * do_balance
* *
* */
# include <asm/uaccess.h>
# include <linux/time.h>
# include <linux/reiserfs_fs.h>
# include <linux/buffer_head.h>
2007-02-12 11:52:09 +03:00
# include <linux/kernel.h>
2005-04-17 02:20:36 +04:00
2009-03-30 22:02:42 +04:00
static inline void buffer_info_init_left ( struct tree_balance * tb ,
struct buffer_info * bi )
{
bi - > tb = tb ;
bi - > bi_bh = tb - > L [ 0 ] ;
bi - > bi_parent = tb - > FL [ 0 ] ;
bi - > bi_position = get_left_neighbor_position ( tb , 0 ) ;
}
static inline void buffer_info_init_right ( struct tree_balance * tb ,
struct buffer_info * bi )
{
bi - > tb = tb ;
bi - > bi_bh = tb - > R [ 0 ] ;
bi - > bi_parent = tb - > FR [ 0 ] ;
bi - > bi_position = get_right_neighbor_position ( tb , 0 ) ;
}
static inline void buffer_info_init_tbS0 ( struct tree_balance * tb ,
struct buffer_info * bi )
{
bi - > tb = tb ;
bi - > bi_bh = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
bi - > bi_parent = PATH_H_PPARENT ( tb - > tb_path , 0 ) ;
bi - > bi_position = PATH_H_POSITION ( tb - > tb_path , 1 ) ;
}
static inline void buffer_info_init_bh ( struct tree_balance * tb ,
struct buffer_info * bi ,
struct buffer_head * bh )
{
bi - > tb = tb ;
bi - > bi_bh = bh ;
bi - > bi_parent = NULL ;
bi - > bi_position = 0 ;
}
2005-07-13 07:21:28 +04:00
inline void do_balance_mark_leaf_dirty ( struct tree_balance * tb ,
struct buffer_head * bh , int flag )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
journal_mark_dirty ( tb - > transaction_handle ,
tb - > transaction_handle - > t_super , bh ) ;
2005-04-17 02:20:36 +04:00
}
# define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty
# define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty
2009-03-30 22:02:44 +04:00
/* summary:
2005-04-17 02:20:36 +04:00
if deleting something ( tb - > insert_size [ 0 ] < 0 )
return ( balance_leaf_when_delete ( ) ) ; ( flag d handled here )
else
if lnum is larger than 0 we put items into the left node
if rnum is larger than 0 we put items into the right node
if snum1 is larger than 0 we put items into the new node s1
2009-03-30 22:02:44 +04:00
if snum2 is larger than 0 we put items into the new node s2
2005-04-17 02:20:36 +04:00
Note that all * num * count new items being created .
It would be easier to read balance_leaf ( ) if each of these summary
lines was a separate procedure rather than being inlined . I think
that there are many passages here and in balance_leaf_when_delete ( ) in
which two calls to one procedure can replace two passages , and it
2009-03-30 22:02:44 +04:00
might save cache space and improve software maintenance costs to do so .
2005-04-17 02:20:36 +04:00
Vladimir made the perceptive comment that we should offload most of
the decision making in this function into fix_nodes / check_balance , and
then create some sort of structure in tb that says what actions should
be performed by do_balance .
- Hans */
/* Balance leaf node in case of delete or cut: insert_size[0] < 0
*
* lnum , rnum can have values > = - 1
* - 1 means that the neighbor must be joined with S
* 0 means that nothing should be done with the neighbor
* > 0 means to shift entirely or partly the specified number of items to the neighbor
*/
2005-07-13 07:21:28 +04:00
static int balance_leaf_when_delete ( struct tree_balance * tb , int flag )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
int item_pos = PATH_LAST_POSITION ( tb - > tb_path ) ;
int pos_in_item = tb - > tb_path - > pos_in_item ;
struct buffer_info bi ;
int n ;
struct item_head * ih ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
RFALSE ( tb - > FR [ 0 ] & & B_LEVEL ( tb - > FR [ 0 ] ) ! = DISK_LEAF_NODE_LEVEL + 1 ,
" vs- 12000: level: wrong FR %z " , tb - > FR [ 0 ] ) ;
RFALSE ( tb - > blknum [ 0 ] > 1 ,
" PAP-12005: tb->blknum == %d, can not be > 1 " , tb - > blknum [ 0 ] ) ;
RFALSE ( ! tb - > blknum [ 0 ] & & ! PATH_H_PPARENT ( tb - > tb_path , 0 ) ,
" PAP-12010: tree can not be empty " ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
ih = B_N_PITEM_HEAD ( tbS0 , item_pos ) ;
2009-03-30 22:02:42 +04:00
buffer_info_init_tbS0 ( tb , & bi ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
/* Delete or truncate the item */
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
switch ( flag ) {
case M_DELETE : /* delete item in S[0] */
RFALSE ( ih_item_len ( ih ) + IH_SIZE ! = - tb - > insert_size [ 0 ] ,
" vs-12013: mode Delete, insert size %d, ih to be deleted %h " ,
- tb - > insert_size [ 0 ] , ih ) ;
leaf_delete_items ( & bi , 0 , item_pos , 1 , - 1 ) ;
if ( ! item_pos & & tb - > CFL [ 0 ] ) {
if ( B_NR_ITEMS ( tbS0 ) ) {
replace_key ( tb , tb - > CFL [ 0 ] , tb - > lkey [ 0 ] , tbS0 ,
0 ) ;
} else {
if ( ! PATH_H_POSITION ( tb - > tb_path , 1 ) )
replace_key ( tb , tb - > CFL [ 0 ] , tb - > lkey [ 0 ] ,
PATH_H_PPARENT ( tb - > tb_path ,
0 ) , 0 ) ;
}
}
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
RFALSE ( ! item_pos & & ! tb - > CFL [ 0 ] ,
" PAP-12020: tb->CFL[0]==%p, tb->L[0]==%p " , tb - > CFL [ 0 ] ,
tb - > L [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
break ;
case M_CUT : { /* cut item in S[0] */
if ( is_direntry_le_ih ( ih ) ) {
/* UFS unlink semantics are such that you can only delete one directory entry at a time. */
/* when we cut a directory tb->insert_size[0] means number of entries to be cut (always 1) */
tb - > insert_size [ 0 ] = - 1 ;
leaf_cut_from_buffer ( & bi , item_pos , pos_in_item ,
- tb - > insert_size [ 0 ] ) ;
RFALSE ( ! item_pos & & ! pos_in_item & & ! tb - > CFL [ 0 ] ,
" PAP-12030: can not change delimiting key. CFL[0]=%p " ,
tb - > CFL [ 0 ] ) ;
if ( ! item_pos & & ! pos_in_item & & tb - > CFL [ 0 ] ) {
replace_key ( tb , tb - > CFL [ 0 ] , tb - > lkey [ 0 ] ,
tbS0 , 0 ) ;
}
} else {
leaf_cut_from_buffer ( & bi , item_pos , pos_in_item ,
- tb - > insert_size [ 0 ] ) ;
RFALSE ( ! ih_item_len ( ih ) ,
" PAP-12035: cut must leave non-zero dynamic length of item " ) ;
}
break ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
default :
print_cur_tb ( " 12040 " ) ;
2009-03-30 22:02:25 +04:00
reiserfs_panic ( tb - > tb_sb , " PAP-12040 " ,
" unexpected mode: %s(%d) " ,
2005-07-13 07:21:28 +04:00
( flag = =
M_PASTE ) ? " PASTE " : ( ( flag = =
M_INSERT ) ? " INSERT " :
" UNKNOWN " ) , flag ) ;
}
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
/* the rule is that no shifting occurs unless by shifting a node can be freed */
n = B_NR_ITEMS ( tbS0 ) ;
if ( tb - > lnum [ 0 ] ) { /* L[0] takes part in balancing */
if ( tb - > lnum [ 0 ] = = - 1 ) { /* L[0] must be joined with S[0] */
if ( tb - > rnum [ 0 ] = = - 1 ) { /* R[0] must be also joined with S[0] */
if ( tb - > FR [ 0 ] = = PATH_H_PPARENT ( tb - > tb_path , 0 ) ) {
/* all contents of all the 3 buffers will be in L[0] */
if ( PATH_H_POSITION ( tb - > tb_path , 1 ) = = 0
& & 1 < B_NR_ITEMS ( tb - > FR [ 0 ] ) )
replace_key ( tb , tb - > CFL [ 0 ] ,
tb - > lkey [ 0 ] ,
tb - > FR [ 0 ] , 1 ) ;
leaf_move_items ( LEAF_FROM_S_TO_L , tb , n ,
- 1 , NULL ) ;
leaf_move_items ( LEAF_FROM_R_TO_L , tb ,
B_NR_ITEMS ( tb - > R [ 0 ] ) ,
- 1 , NULL ) ;
reiserfs_invalidate_buffer ( tb , tbS0 ) ;
reiserfs_invalidate_buffer ( tb ,
tb - > R [ 0 ] ) ;
return 0 ;
}
/* all contents of all the 3 buffers will be in R[0] */
leaf_move_items ( LEAF_FROM_S_TO_R , tb , n , - 1 ,
NULL ) ;
leaf_move_items ( LEAF_FROM_L_TO_R , tb ,
B_NR_ITEMS ( tb - > L [ 0 ] ) , - 1 , NULL ) ;
/* right_delimiting_key is correct in R[0] */
replace_key ( tb , tb - > CFR [ 0 ] , tb - > rkey [ 0 ] ,
tb - > R [ 0 ] , 0 ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
reiserfs_invalidate_buffer ( tb , tbS0 ) ;
reiserfs_invalidate_buffer ( tb , tb - > L [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
return - 1 ;
}
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
RFALSE ( tb - > rnum [ 0 ] ! = 0 ,
" PAP-12045: rnum must be 0 (%d) " , tb - > rnum [ 0 ] ) ;
/* all contents of L[0] and S[0] will be in L[0] */
leaf_shift_left ( tb , n , - 1 ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
reiserfs_invalidate_buffer ( tb , tbS0 ) ;
return 0 ;
}
/* a part of contents of S[0] will be in L[0] and the rest part of S[0] will be in R[0] */
RFALSE ( ( tb - > lnum [ 0 ] + tb - > rnum [ 0 ] < n ) | |
( tb - > lnum [ 0 ] + tb - > rnum [ 0 ] > n + 1 ) ,
" PAP-12050: rnum(%d) and lnum(%d) and item number(%d) in S[0] are not consistent " ,
tb - > rnum [ 0 ] , tb - > lnum [ 0 ] , n ) ;
RFALSE ( ( tb - > lnum [ 0 ] + tb - > rnum [ 0 ] = = n ) & &
( tb - > lbytes ! = - 1 | | tb - > rbytes ! = - 1 ) ,
" PAP-12055: bad rbytes (%d)/lbytes (%d) parameters when items are not split " ,
tb - > rbytes , tb - > lbytes ) ;
RFALSE ( ( tb - > lnum [ 0 ] + tb - > rnum [ 0 ] = = n + 1 ) & &
( tb - > lbytes < 1 | | tb - > rbytes ! = - 1 ) ,
" PAP-12060: bad rbytes (%d)/lbytes (%d) parameters when items are split " ,
tb - > rbytes , tb - > lbytes ) ;
leaf_shift_left ( tb , tb - > lnum [ 0 ] , tb - > lbytes ) ;
leaf_shift_right ( tb , tb - > rnum [ 0 ] , tb - > rbytes ) ;
reiserfs_invalidate_buffer ( tb , tbS0 ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
if ( tb - > rnum [ 0 ] = = - 1 ) {
/* all contents of R[0] and S[0] will be in R[0] */
leaf_shift_right ( tb , n , - 1 ) ;
reiserfs_invalidate_buffer ( tb , tbS0 ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
RFALSE ( tb - > rnum [ 0 ] ,
" PAP-12065: bad rnum parameter must be 0 (%d) " , tb - > rnum [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2005-07-13 07:21:28 +04:00
static int balance_leaf ( struct tree_balance * tb , struct item_head * ih , /* item header of inserted item (this is on little endian) */
const char * body , /* body of inserted item or bytes to paste */
int flag , /* i - insert, d - delete, c - cut, p - paste
( see comment to do_balance ) */
struct item_head * insert_key , /* in our processing of one level we sometimes determine what
must be inserted into the next higher level . This insertion
consists of a key or two keys and their corresponding
pointers */
struct buffer_head * * insert_ptr /* inserted node-ptrs for the next level */
2005-04-17 02:20:36 +04:00
)
{
2005-07-13 07:21:28 +04:00
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
2009-03-30 22:02:44 +04:00
int item_pos = PATH_LAST_POSITION ( tb - > tb_path ) ; /* index into the array of item headers in S[0]
2005-07-13 07:21:28 +04:00
of the affected item */
struct buffer_info bi ;
struct buffer_head * S_new [ 2 ] ; /* new nodes allocated to hold what could not fit into S */
int snum [ 2 ] ; /* number of items that will be placed
into S_new ( includes partially shifted
items ) */
2009-03-30 22:02:44 +04:00
int sbytes [ 2 ] ; /* if an item is partially shifted into S_new then
if it is a directory item
2005-07-13 07:21:28 +04:00
it is the number of entries from the item that are shifted into S_new
else
it is the number of bytes from the item that are shifted into S_new
*/
int n , i ;
int ret_val ;
int pos_in_item ;
int zeros_num ;
PROC_INFO_INC ( tb - > tb_sb , balance_at [ 0 ] ) ;
/* Make balance in case insert_size[0] < 0 */
if ( tb - > insert_size [ 0 ] < 0 )
return balance_leaf_when_delete ( tb , flag ) ;
zeros_num = 0 ;
2008-03-29 06:07:28 +03:00
if ( flag = = M_INSERT & & ! body )
2005-07-13 07:21:28 +04:00
zeros_num = ih_item_len ( ih ) ;
pos_in_item = tb - > tb_path - > pos_in_item ;
/* for indirect item pos_in_item is measured in unformatted node
pointers . Recalculate to bytes */
if ( flag ! = M_INSERT
& & is_indirect_le_ih ( B_N_PITEM_HEAD ( tbS0 , item_pos ) ) )
pos_in_item * = UNFM_P_SIZE ;
if ( tb - > lnum [ 0 ] > 0 ) {
/* Shift lnum[0] items from S[0] to the left neighbor L[0] */
if ( item_pos < tb - > lnum [ 0 ] ) {
/* new item or it part falls to L[0], shift it too */
n = B_NR_ITEMS ( tb - > L [ 0 ] ) ;
switch ( flag ) {
case M_INSERT : /* insert item into L[0] */
if ( item_pos = = tb - > lnum [ 0 ] - 1
& & tb - > lbytes ! = - 1 ) {
/* part of new item falls into L[0] */
int new_item_len ;
int version ;
ret_val =
leaf_shift_left ( tb , tb - > lnum [ 0 ] - 1 ,
- 1 ) ;
/* Calculate item length to insert to S[0] */
new_item_len =
ih_item_len ( ih ) - tb - > lbytes ;
/* Calculate and check item length to insert to L[0] */
put_ih_item_len ( ih ,
ih_item_len ( ih ) -
new_item_len ) ;
RFALSE ( ih_item_len ( ih ) < = 0 ,
" PAP-12080: there is nothing to insert into L[0]: ih_item_len=%d " ,
ih_item_len ( ih ) ) ;
/* Insert new item into L[0] */
2009-03-30 22:02:42 +04:00
buffer_info_init_left ( tb , & bi ) ;
2005-07-13 07:21:28 +04:00
leaf_insert_into_buf ( & bi ,
n + item_pos -
ret_val , ih , body ,
zeros_num >
ih_item_len ( ih ) ?
ih_item_len ( ih ) :
zeros_num ) ;
version = ih_version ( ih ) ;
/* Calculate key component, item length and body to insert into S[0] */
set_le_ih_k_offset ( ih ,
le_ih_k_offset ( ih ) +
( tb - >
lbytes < <
( is_indirect_le_ih
( ih ) ? tb - > tb_sb - >
s_blocksize_bits -
UNFM_P_SHIFT :
0 ) ) ) ;
put_ih_item_len ( ih , new_item_len ) ;
if ( tb - > lbytes > zeros_num ) {
body + =
( tb - > lbytes - zeros_num ) ;
zeros_num = 0 ;
} else
zeros_num - = tb - > lbytes ;
RFALSE ( ih_item_len ( ih ) < = 0 ,
" PAP-12085: there is nothing to insert into S[0]: ih_item_len=%d " ,
ih_item_len ( ih ) ) ;
} else {
/* new item in whole falls into L[0] */
/* Shift lnum[0]-1 items to L[0] */
ret_val =
leaf_shift_left ( tb , tb - > lnum [ 0 ] - 1 ,
tb - > lbytes ) ;
/* Insert new item into L[0] */
2009-03-30 22:02:42 +04:00
buffer_info_init_left ( tb , & bi ) ;
2005-07-13 07:21:28 +04:00
leaf_insert_into_buf ( & bi ,
n + item_pos -
ret_val , ih , body ,
zeros_num ) ;
tb - > insert_size [ 0 ] = 0 ;
zeros_num = 0 ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
break ;
case M_PASTE : /* append item in L[0] */
if ( item_pos = = tb - > lnum [ 0 ] - 1
& & tb - > lbytes ! = - 1 ) {
/* we must shift the part of the appended item */
if ( is_direntry_le_ih
( B_N_PITEM_HEAD ( tbS0 , item_pos ) ) ) {
RFALSE ( zeros_num ,
" PAP-12090: invalid parameter in case of a directory " ) ;
/* directory item */
if ( tb - > lbytes > pos_in_item ) {
/* new directory entry falls into L[0] */
struct item_head
* pasted ;
int l_pos_in_item =
pos_in_item ;
/* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 entries from given directory item */
ret_val =
leaf_shift_left ( tb ,
tb - >
lnum
[ 0 ] ,
tb - >
lbytes
-
1 ) ;
if ( ret_val
& & ! item_pos ) {
pasted =
B_N_PITEM_HEAD
( tb - > L [ 0 ] ,
B_NR_ITEMS
( tb - >
L [ 0 ] ) -
1 ) ;
l_pos_in_item + =
I_ENTRY_COUNT
( pasted ) -
( tb - >
lbytes -
1 ) ;
}
/* Append given directory entry to directory item */
2009-03-30 22:02:42 +04:00
buffer_info_init_left ( tb , & bi ) ;
2005-07-13 07:21:28 +04:00
leaf_paste_in_buffer
( & bi ,
n + item_pos -
ret_val ,
l_pos_in_item ,
tb - > insert_size [ 0 ] ,
body , zeros_num ) ;
/* previous string prepared space for pasting new entry, following string pastes this entry */
/* when we have merge directory item, pos_in_item has been changed too */
/* paste new directory entry. 1 is entry number */
2009-03-30 22:02:18 +04:00
leaf_paste_entries ( & bi ,
2005-07-13 07:21:28 +04:00
n +
item_pos
-
ret_val ,
l_pos_in_item ,
1 ,
( struct
reiserfs_de_head
* )
body ,
body
+
DEH_SIZE ,
tb - >
insert_size
[ 0 ]
) ;
tb - > insert_size [ 0 ] = 0 ;
} else {
/* new directory item doesn't fall into L[0] */
/* Shift lnum[0]-1 items in whole. Shift lbytes directory entries from directory item number lnum[0] */
leaf_shift_left ( tb ,
tb - >
lnum [ 0 ] ,
tb - >
lbytes ) ;
}
/* Calculate new position to append in item body */
pos_in_item - = tb - > lbytes ;
} else {
/* regular object */
RFALSE ( tb - > lbytes < = 0 ,
" PAP-12095: there is nothing to shift to L[0]. lbytes=%d " ,
tb - > lbytes ) ;
RFALSE ( pos_in_item ! =
ih_item_len
( B_N_PITEM_HEAD
( tbS0 , item_pos ) ) ,
" PAP-12100: incorrect position to paste: item_len=%d, pos_in_item=%d " ,
ih_item_len
( B_N_PITEM_HEAD
( tbS0 , item_pos ) ) ,
pos_in_item ) ;
if ( tb - > lbytes > = pos_in_item ) {
/* appended item will be in L[0] in whole */
int l_n ;
/* this bytes number must be appended to the last item of L[h] */
l_n =
tb - > lbytes -
pos_in_item ;
/* Calculate new insert_size[0] */
tb - > insert_size [ 0 ] - =
l_n ;
RFALSE ( tb - >
insert_size [ 0 ] < =
0 ,
" PAP-12105: there is nothing to paste into L[0]. insert_size=%d " ,
tb - >
insert_size [ 0 ] ) ;
ret_val =
leaf_shift_left ( tb ,
tb - >
lnum
[ 0 ] ,
ih_item_len
( B_N_PITEM_HEAD
( tbS0 ,
item_pos ) ) ) ;
/* Append to body of item in L[0] */
2009-03-30 22:02:42 +04:00
buffer_info_init_left ( tb , & bi ) ;
2005-07-13 07:21:28 +04:00
leaf_paste_in_buffer
( & bi ,
n + item_pos -
ret_val ,
ih_item_len
( B_N_PITEM_HEAD
( tb - > L [ 0 ] ,
n + item_pos -
ret_val ) ) , l_n ,
body ,
zeros_num >
l_n ? l_n :
zeros_num ) ;
/* 0-th item in S0 can be only of DIRECT type when l_n != 0 */
{
int version ;
int temp_l =
l_n ;
RFALSE
( ih_item_len
( B_N_PITEM_HEAD
( tbS0 ,
0 ) ) ,
" PAP-12106: item length must be 0 " ) ;
RFALSE
( comp_short_le_keys
( B_N_PKEY
( tbS0 , 0 ) ,
B_N_PKEY
( tb - > L [ 0 ] ,
n +
item_pos
-
ret_val ) ) ,
" PAP-12107: items must be of the same file " ) ;
if ( is_indirect_le_ih ( B_N_PITEM_HEAD ( tb - > L [ 0 ] , n + item_pos - ret_val ) ) ) {
temp_l =
l_n
< <
( tb - >
tb_sb - >
s_blocksize_bits
-
UNFM_P_SHIFT ) ;
}
/* update key of first item in S0 */
version =
ih_version
( B_N_PITEM_HEAD
( tbS0 , 0 ) ) ;
set_le_key_k_offset
( version ,
B_N_PKEY
( tbS0 , 0 ) ,
le_key_k_offset
( version ,
B_N_PKEY
( tbS0 ,
0 ) ) +
temp_l ) ;
/* update left delimiting key */
set_le_key_k_offset
( version ,
B_N_PDELIM_KEY
( tb - >
CFL [ 0 ] ,
tb - >
lkey [ 0 ] ) ,
le_key_k_offset
( version ,
B_N_PDELIM_KEY
( tb - >
CFL [ 0 ] ,
tb - >
lkey [ 0 ] ) )
+ temp_l ) ;
}
/* Calculate new body, position in item and insert_size[0] */
if ( l_n > zeros_num ) {
body + =
( l_n -
zeros_num ) ;
zeros_num = 0 ;
} else
zeros_num - =
l_n ;
pos_in_item = 0 ;
RFALSE
( comp_short_le_keys
( B_N_PKEY ( tbS0 , 0 ) ,
B_N_PKEY ( tb - > L [ 0 ] ,
B_NR_ITEMS
( tb - >
L [ 0 ] ) -
1 ) )
| |
! op_is_left_mergeable
( B_N_PKEY ( tbS0 , 0 ) ,
tbS0 - > b_size )
| |
! op_is_left_mergeable
( B_N_PDELIM_KEY
( tb - > CFL [ 0 ] ,
tb - > lkey [ 0 ] ) ,
tbS0 - > b_size ) ,
" PAP-12120: item must be merge-able with left neighboring item " ) ;
} else { /* only part of the appended item will be in L[0] */
/* Calculate position in item for append in S[0] */
pos_in_item - =
tb - > lbytes ;
RFALSE ( pos_in_item < = 0 ,
" PAP-12125: no place for paste. pos_in_item=%d " ,
pos_in_item ) ;
/* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
leaf_shift_left ( tb ,
tb - >
lnum [ 0 ] ,
tb - >
lbytes ) ;
}
}
} else { /* appended item will be in L[0] in whole */
struct item_head * pasted ;
if ( ! item_pos & & op_is_left_mergeable ( B_N_PKEY ( tbS0 , 0 ) , tbS0 - > b_size ) ) { /* if we paste into first item of S[0] and it is left mergable */
/* then increment pos_in_item by the size of the last item in L[0] */
pasted =
B_N_PITEM_HEAD ( tb - > L [ 0 ] ,
n - 1 ) ;
if ( is_direntry_le_ih ( pasted ) )
pos_in_item + =
ih_entry_count
( pasted ) ;
else
pos_in_item + =
ih_item_len ( pasted ) ;
}
/* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
ret_val =
leaf_shift_left ( tb , tb - > lnum [ 0 ] ,
tb - > lbytes ) ;
/* Append to body of item in L[0] */
2009-03-30 22:02:42 +04:00
buffer_info_init_left ( tb , & bi ) ;
2005-07-13 07:21:28 +04:00
leaf_paste_in_buffer ( & bi ,
n + item_pos -
ret_val ,
pos_in_item ,
tb - > insert_size [ 0 ] ,
body , zeros_num ) ;
/* if appended item is directory, paste entry */
pasted =
B_N_PITEM_HEAD ( tb - > L [ 0 ] ,
n + item_pos -
ret_val ) ;
if ( is_direntry_le_ih ( pasted ) )
2009-03-30 22:02:18 +04:00
leaf_paste_entries ( & bi ,
2005-07-13 07:21:28 +04:00
n +
item_pos -
ret_val ,
pos_in_item ,
1 ,
( struct
reiserfs_de_head
* ) body ,
body +
DEH_SIZE ,
tb - >
insert_size
[ 0 ]
) ;
/* if appended item is indirect item, put unformatted node into un list */
if ( is_indirect_le_ih ( pasted ) )
set_ih_free_space ( pasted , 0 ) ;
tb - > insert_size [ 0 ] = 0 ;
zeros_num = 0 ;
}
break ;
default : /* cases d and t */
2009-03-30 22:02:25 +04:00
reiserfs_panic ( tb - > tb_sb , " PAP-12130 " ,
" lnum > 0: unexpected mode: "
" %s(%d) " ,
2005-07-13 07:21:28 +04:00
( flag = =
M_DELETE ) ? " DELETE " : ( ( flag = =
M_CUT )
? " CUT "
:
" UNKNOWN " ) ,
flag ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
} else {
/* new item doesn't fall into L[0] */
leaf_shift_left ( tb , tb - > lnum [ 0 ] , tb - > lbytes ) ;
2005-04-17 02:20:36 +04:00
}
}
2005-07-13 07:21:28 +04:00
/* tb->lnum[0] > 0 */
/* Calculate new item position */
item_pos - = ( tb - > lnum [ 0 ] - ( ( tb - > lbytes ! = - 1 ) ? 1 : 0 ) ) ;
if ( tb - > rnum [ 0 ] > 0 ) {
/* shift rnum[0] items from S[0] to the right neighbor R[0] */
n = B_NR_ITEMS ( tbS0 ) ;
switch ( flag ) {
case M_INSERT : /* insert item */
if ( n - tb - > rnum [ 0 ] < item_pos ) { /* new item or its part falls to R[0] */
if ( item_pos = = n - tb - > rnum [ 0 ] + 1 & & tb - > rbytes ! = - 1 ) { /* part of new item falls into R[0] */
loff_t old_key_comp , old_len ,
r_zeros_number ;
const char * r_body ;
int version ;
loff_t offset ;
leaf_shift_right ( tb , tb - > rnum [ 0 ] - 1 ,
- 1 ) ;
version = ih_version ( ih ) ;
/* Remember key component and item length */
old_key_comp = le_ih_k_offset ( ih ) ;
old_len = ih_item_len ( ih ) ;
/* Calculate key component and item length to insert into R[0] */
offset =
le_ih_k_offset ( ih ) +
( ( old_len -
tb - >
rbytes ) < < ( is_indirect_le_ih ( ih )
? tb - > tb_sb - >
s_blocksize_bits -
UNFM_P_SHIFT : 0 ) ) ;
set_le_ih_k_offset ( ih , offset ) ;
put_ih_item_len ( ih , tb - > rbytes ) ;
/* Insert part of the item into R[0] */
2009-03-30 22:02:42 +04:00
buffer_info_init_right ( tb , & bi ) ;
2005-07-13 07:21:28 +04:00
if ( ( old_len - tb - > rbytes ) > zeros_num ) {
r_zeros_number = 0 ;
r_body =
body + ( old_len -
tb - > rbytes ) -
zeros_num ;
} else {
r_body = body ;
r_zeros_number =
zeros_num - ( old_len -
tb - > rbytes ) ;
zeros_num - = r_zeros_number ;
}
leaf_insert_into_buf ( & bi , 0 , ih , r_body ,
r_zeros_number ) ;
/* Replace right delimiting key by first key in R[0] */
replace_key ( tb , tb - > CFR [ 0 ] , tb - > rkey [ 0 ] ,
tb - > R [ 0 ] , 0 ) ;
/* Calculate key component and item length to insert into S[0] */
set_le_ih_k_offset ( ih , old_key_comp ) ;
put_ih_item_len ( ih ,
old_len - tb - > rbytes ) ;
tb - > insert_size [ 0 ] - = tb - > rbytes ;
} else { /* whole new item falls into R[0] */
/* Shift rnum[0]-1 items to R[0] */
ret_val =
leaf_shift_right ( tb ,
tb - > rnum [ 0 ] - 1 ,
tb - > rbytes ) ;
/* Insert new item into R[0] */
2009-03-30 22:02:42 +04:00
buffer_info_init_right ( tb , & bi ) ;
2005-07-13 07:21:28 +04:00
leaf_insert_into_buf ( & bi ,
item_pos - n +
tb - > rnum [ 0 ] - 1 ,
ih , body ,
zeros_num ) ;
if ( item_pos - n + tb - > rnum [ 0 ] - 1 = = 0 ) {
replace_key ( tb , tb - > CFR [ 0 ] ,
tb - > rkey [ 0 ] ,
tb - > R [ 0 ] , 0 ) ;
}
zeros_num = tb - > insert_size [ 0 ] = 0 ;
}
} else { /* new item or part of it doesn't fall into R[0] */
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
leaf_shift_right ( tb , tb - > rnum [ 0 ] , tb - > rbytes ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
break ;
case M_PASTE : /* append item */
if ( n - tb - > rnum [ 0 ] < = item_pos ) { /* pasted item or part of it falls to R[0] */
if ( item_pos = = n - tb - > rnum [ 0 ] & & tb - > rbytes ! = - 1 ) { /* we must shift the part of the appended item */
if ( is_direntry_le_ih ( B_N_PITEM_HEAD ( tbS0 , item_pos ) ) ) { /* we append to directory item */
int entry_count ;
RFALSE ( zeros_num ,
" PAP-12145: invalid parameter in case of a directory " ) ;
entry_count =
I_ENTRY_COUNT ( B_N_PITEM_HEAD
( tbS0 ,
item_pos ) ) ;
if ( entry_count - tb - > rbytes <
pos_in_item )
/* new directory entry falls into R[0] */
{
int paste_entry_position ;
RFALSE ( tb - > rbytes - 1 > =
entry_count
| | ! tb - >
insert_size [ 0 ] ,
" PAP-12150: no enough of entries to shift to R[0]: rbytes=%d, entry_count=%d " ,
tb - > rbytes ,
entry_count ) ;
/* Shift rnum[0]-1 items in whole. Shift rbytes-1 directory entries from directory item number rnum[0] */
leaf_shift_right ( tb ,
tb - >
rnum
[ 0 ] ,
tb - >
rbytes
- 1 ) ;
/* Paste given directory entry to directory item */
paste_entry_position =
pos_in_item -
entry_count +
tb - > rbytes - 1 ;
2009-03-30 22:02:42 +04:00
buffer_info_init_right ( tb , & bi ) ;
2005-07-13 07:21:28 +04:00
leaf_paste_in_buffer
( & bi , 0 ,
paste_entry_position ,
tb - > insert_size [ 0 ] ,
body , zeros_num ) ;
/* paste entry */
2009-03-30 22:02:18 +04:00
leaf_paste_entries ( & bi ,
2005-07-13 07:21:28 +04:00
0 ,
paste_entry_position ,
1 ,
( struct
reiserfs_de_head
* )
body ,
body
+
DEH_SIZE ,
tb - >
insert_size
[ 0 ]
) ;
if ( paste_entry_position
= = 0 ) {
/* change delimiting keys */
replace_key ( tb ,
tb - >
CFR
[ 0 ] ,
tb - >
rkey
[ 0 ] ,
tb - >
R
[ 0 ] ,
0 ) ;
}
tb - > insert_size [ 0 ] = 0 ;
pos_in_item + + ;
} else { /* new directory entry doesn't fall into R[0] */
leaf_shift_right ( tb ,
tb - >
rnum
[ 0 ] ,
tb - >
rbytes ) ;
}
} else { /* regular object */
int n_shift , n_rem ,
r_zeros_number ;
const char * r_body ;
/* Calculate number of bytes which must be shifted from appended item */
if ( ( n_shift =
tb - > rbytes -
tb - > insert_size [ 0 ] ) < 0 )
n_shift = 0 ;
RFALSE ( pos_in_item ! =
ih_item_len
( B_N_PITEM_HEAD
( tbS0 , item_pos ) ) ,
" PAP-12155: invalid position to paste. ih_item_len=%d, pos_in_item=%d " ,
pos_in_item ,
ih_item_len
( B_N_PITEM_HEAD
( tbS0 , item_pos ) ) ) ;
leaf_shift_right ( tb ,
tb - > rnum [ 0 ] ,
n_shift ) ;
/* Calculate number of bytes which must remain in body after appending to R[0] */
if ( ( n_rem =
tb - > insert_size [ 0 ] -
tb - > rbytes ) < 0 )
n_rem = 0 ;
{
int version ;
unsigned long temp_rem =
n_rem ;
version =
ih_version
( B_N_PITEM_HEAD
( tb - > R [ 0 ] , 0 ) ) ;
if ( is_indirect_le_key
( version ,
B_N_PKEY ( tb - > R [ 0 ] ,
0 ) ) ) {
temp_rem =
n_rem < <
( tb - > tb_sb - >
s_blocksize_bits
-
UNFM_P_SHIFT ) ;
}
set_le_key_k_offset
( version ,
B_N_PKEY ( tb - > R [ 0 ] ,
0 ) ,
le_key_k_offset
( version ,
B_N_PKEY ( tb - > R [ 0 ] ,
0 ) ) +
temp_rem ) ;
set_le_key_k_offset
( version ,
B_N_PDELIM_KEY ( tb - >
CFR
[ 0 ] ,
tb - >
rkey
[ 0 ] ) ,
le_key_k_offset
( version ,
B_N_PDELIM_KEY
( tb - > CFR [ 0 ] ,
tb - > rkey [ 0 ] ) ) +
temp_rem ) ;
}
2005-04-17 02:20:36 +04:00
/* k_offset (B_N_PKEY(tb->R[0],0)) += n_rem;
k_offset ( B_N_PDELIM_KEY ( tb - > CFR [ 0 ] , tb - > rkey [ 0 ] ) ) + = n_rem ; */
2005-07-13 07:21:28 +04:00
do_balance_mark_internal_dirty
( tb , tb - > CFR [ 0 ] , 0 ) ;
/* Append part of body into R[0] */
2009-03-30 22:02:42 +04:00
buffer_info_init_right ( tb , & bi ) ;
2005-07-13 07:21:28 +04:00
if ( n_rem > zeros_num ) {
r_zeros_number = 0 ;
r_body =
body + n_rem -
zeros_num ;
} else {
r_body = body ;
r_zeros_number =
zeros_num - n_rem ;
zeros_num - =
r_zeros_number ;
}
leaf_paste_in_buffer ( & bi , 0 ,
n_shift ,
tb - >
insert_size
[ 0 ] -
n_rem ,
r_body ,
r_zeros_number ) ;
if ( is_indirect_le_ih
( B_N_PITEM_HEAD
( tb - > R [ 0 ] , 0 ) ) ) {
2005-04-17 02:20:36 +04:00
#if 0
2005-07-13 07:21:28 +04:00
RFALSE ( n_rem ,
" PAP-12160: paste more than one unformatted node pointer " ) ;
2005-04-17 02:20:36 +04:00
# endif
2005-07-13 07:21:28 +04:00
set_ih_free_space
( B_N_PITEM_HEAD
( tb - > R [ 0 ] , 0 ) , 0 ) ;
}
tb - > insert_size [ 0 ] = n_rem ;
if ( ! n_rem )
pos_in_item + + ;
}
} else { /* pasted item in whole falls into R[0] */
struct item_head * pasted ;
ret_val =
leaf_shift_right ( tb , tb - > rnum [ 0 ] ,
tb - > rbytes ) ;
/* append item in R[0] */
if ( pos_in_item > = 0 ) {
2009-03-30 22:02:42 +04:00
buffer_info_init_right ( tb , & bi ) ;
2005-07-13 07:21:28 +04:00
leaf_paste_in_buffer ( & bi ,
item_pos -
n +
tb - >
rnum [ 0 ] ,
pos_in_item ,
tb - >
insert_size
[ 0 ] , body ,
zeros_num ) ;
}
/* paste new entry, if item is directory item */
pasted =
B_N_PITEM_HEAD ( tb - > R [ 0 ] ,
item_pos - n +
tb - > rnum [ 0 ] ) ;
if ( is_direntry_le_ih ( pasted )
& & pos_in_item > = 0 ) {
2009-03-30 22:02:18 +04:00
leaf_paste_entries ( & bi ,
2005-07-13 07:21:28 +04:00
item_pos -
n +
tb - > rnum [ 0 ] ,
pos_in_item ,
1 ,
( struct
reiserfs_de_head
* ) body ,
body +
DEH_SIZE ,
tb - >
insert_size
[ 0 ]
) ;
if ( ! pos_in_item ) {
RFALSE ( item_pos - n +
tb - > rnum [ 0 ] ,
" PAP-12165: directory item must be first item of node when pasting is in 0th position " ) ;
/* update delimiting keys */
replace_key ( tb ,
tb - > CFR [ 0 ] ,
tb - > rkey [ 0 ] ,
tb - > R [ 0 ] ,
0 ) ;
}
}
if ( is_indirect_le_ih ( pasted ) )
set_ih_free_space ( pasted , 0 ) ;
zeros_num = tb - > insert_size [ 0 ] = 0 ;
}
} else { /* new item doesn't fall into R[0] */
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
leaf_shift_right ( tb , tb - > rnum [ 0 ] , tb - > rbytes ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
break ;
default : /* cases d and t */
2009-03-30 22:02:25 +04:00
reiserfs_panic ( tb - > tb_sb , " PAP-12175 " ,
" rnum > 0: unexpected mode: %s(%d) " ,
2005-07-13 07:21:28 +04:00
( flag = =
M_DELETE ) ? " DELETE " : ( ( flag = =
M_CUT ) ? " CUT "
: " UNKNOWN " ) ,
flag ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
}
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
/* tb->rnum[0] > 0 */
RFALSE ( tb - > blknum [ 0 ] > 3 ,
" PAP-12180: blknum can not be %d. It must be <= 3 " ,
tb - > blknum [ 0 ] ) ;
RFALSE ( tb - > blknum [ 0 ] < 0 ,
" PAP-12185: blknum can not be %d. It must be >= 0 " ,
tb - > blknum [ 0 ] ) ;
/* if while adding to a node we discover that it is possible to split
it in two , and merge the left part into the left neighbor and the
right part into the right neighbor , eliminating the node */
if ( tb - > blknum [ 0 ] = = 0 ) { /* node S[0] is empty now */
RFALSE ( ! tb - > lnum [ 0 ] | | ! tb - > rnum [ 0 ] ,
" PAP-12190: lnum and rnum must not be zero " ) ;
/* if insertion was done before 0-th position in R[0], right
delimiting key of the tb - > L [ 0 ] ' s and left delimiting key are
not set correctly */
if ( tb - > CFL [ 0 ] ) {
if ( ! tb - > CFR [ 0 ] )
2009-03-30 22:02:25 +04:00
reiserfs_panic ( tb - > tb_sb , " vs-12195 " ,
" CFR not initialized " ) ;
2005-07-13 07:21:28 +04:00
copy_key ( B_N_PDELIM_KEY ( tb - > CFL [ 0 ] , tb - > lkey [ 0 ] ) ,
B_N_PDELIM_KEY ( tb - > CFR [ 0 ] , tb - > rkey [ 0 ] ) ) ;
do_balance_mark_internal_dirty ( tb , tb - > CFL [ 0 ] , 0 ) ;
}
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
reiserfs_invalidate_buffer ( tb , tbS0 ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
/* Fill new nodes that appear in place of S[0] */
/* I am told that this copying is because we need an array to enable
the looping code . - Hans */
snum [ 0 ] = tb - > s1num , snum [ 1 ] = tb - > s2num ;
sbytes [ 0 ] = tb - > s1bytes ;
sbytes [ 1 ] = tb - > s2bytes ;
for ( i = tb - > blknum [ 0 ] - 2 ; i > = 0 ; i - - ) {
RFALSE ( ! snum [ i ] , " PAP-12200: snum[%d] == %d. Must be > 0 " , i ,
snum [ i ] ) ;
/* here we shift from S to S_new nodes */
S_new [ i ] = get_FEB ( tb ) ;
/* initialized block type and tree level */
set_blkh_level ( B_BLK_HEAD ( S_new [ i ] ) , DISK_LEAF_NODE_LEVEL ) ;
n = B_NR_ITEMS ( tbS0 ) ;
switch ( flag ) {
case M_INSERT : /* insert item */
if ( n - snum [ i ] < item_pos ) { /* new item or it's part falls to first new node S_new[i] */
if ( item_pos = = n - snum [ i ] + 1 & & sbytes [ i ] ! = - 1 ) { /* part of new item falls into S_new[i] */
int old_key_comp , old_len ,
r_zeros_number ;
const char * r_body ;
int version ;
/* Move snum[i]-1 items from S[0] to S_new[i] */
leaf_move_items ( LEAF_FROM_S_TO_SNEW , tb ,
snum [ i ] - 1 , - 1 ,
S_new [ i ] ) ;
/* Remember key component and item length */
version = ih_version ( ih ) ;
old_key_comp = le_ih_k_offset ( ih ) ;
old_len = ih_item_len ( ih ) ;
/* Calculate key component and item length to insert into S_new[i] */
set_le_ih_k_offset ( ih ,
le_ih_k_offset ( ih ) +
( ( old_len -
sbytes [ i ] ) < <
( is_indirect_le_ih
( ih ) ? tb - > tb_sb - >
s_blocksize_bits -
UNFM_P_SHIFT :
0 ) ) ) ;
put_ih_item_len ( ih , sbytes [ i ] ) ;
/* Insert part of the item into S_new[i] before 0-th item */
2009-03-30 22:02:42 +04:00
buffer_info_init_bh ( tb , & bi , S_new [ i ] ) ;
2005-07-13 07:21:28 +04:00
if ( ( old_len - sbytes [ i ] ) > zeros_num ) {
r_zeros_number = 0 ;
r_body =
body + ( old_len -
sbytes [ i ] ) -
zeros_num ;
} else {
r_body = body ;
r_zeros_number =
zeros_num - ( old_len -
sbytes [ i ] ) ;
zeros_num - = r_zeros_number ;
}
leaf_insert_into_buf ( & bi , 0 , ih , r_body ,
r_zeros_number ) ;
/* Calculate key component and item length to insert into S[i] */
set_le_ih_k_offset ( ih , old_key_comp ) ;
put_ih_item_len ( ih ,
old_len - sbytes [ i ] ) ;
tb - > insert_size [ 0 ] - = sbytes [ i ] ;
} else { /* whole new item falls into S_new[i] */
/* Shift snum[0] - 1 items to S_new[i] (sbytes[i] of split item) */
leaf_move_items ( LEAF_FROM_S_TO_SNEW , tb ,
snum [ i ] - 1 , sbytes [ i ] ,
S_new [ i ] ) ;
/* Insert new item into S_new[i] */
2009-03-30 22:02:42 +04:00
buffer_info_init_bh ( tb , & bi , S_new [ i ] ) ;
2005-07-13 07:21:28 +04:00
leaf_insert_into_buf ( & bi ,
item_pos - n +
snum [ i ] - 1 , ih ,
body , zeros_num ) ;
zeros_num = tb - > insert_size [ 0 ] = 0 ;
}
}
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
else { /* new item or it part don't falls into S_new[i] */
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
leaf_move_items ( LEAF_FROM_S_TO_SNEW , tb ,
snum [ i ] , sbytes [ i ] , S_new [ i ] ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
break ;
case M_PASTE : /* append item */
if ( n - snum [ i ] < = item_pos ) { /* pasted item or part if it falls to S_new[i] */
if ( item_pos = = n - snum [ i ] & & sbytes [ i ] ! = - 1 ) { /* we must shift part of the appended item */
struct item_head * aux_ih ;
RFALSE ( ih , " PAP-12210: ih must be 0 " ) ;
2009-06-18 03:26:29 +04:00
aux_ih = B_N_PITEM_HEAD ( tbS0 , item_pos ) ;
if ( is_direntry_le_ih ( aux_ih ) ) {
2005-07-13 07:21:28 +04:00
/* we append to directory item */
int entry_count ;
entry_count =
ih_entry_count ( aux_ih ) ;
if ( entry_count - sbytes [ i ] <
pos_in_item
& & pos_in_item < =
entry_count ) {
/* new directory entry falls into S_new[i] */
RFALSE ( ! tb - >
insert_size [ 0 ] ,
" PAP-12215: insert_size is already 0 " ) ;
RFALSE ( sbytes [ i ] - 1 > =
entry_count ,
" PAP-12220: there are no so much entries (%d), only %d " ,
sbytes [ i ] - 1 ,
entry_count ) ;
/* Shift snum[i]-1 items in whole. Shift sbytes[i] directory entries from directory item number snum[i] */
leaf_move_items
( LEAF_FROM_S_TO_SNEW ,
tb , snum [ i ] ,
sbytes [ i ] - 1 ,
S_new [ i ] ) ;
/* Paste given directory entry to directory item */
2009-03-30 22:02:42 +04:00
buffer_info_init_bh ( tb , & bi , S_new [ i ] ) ;
2005-07-13 07:21:28 +04:00
leaf_paste_in_buffer
( & bi , 0 ,
pos_in_item -
entry_count +
sbytes [ i ] - 1 ,
tb - > insert_size [ 0 ] ,
body , zeros_num ) ;
/* paste new directory entry */
2009-03-30 22:02:18 +04:00
leaf_paste_entries ( & bi ,
2005-07-13 07:21:28 +04:00
0 ,
pos_in_item
-
entry_count
+
sbytes
[ i ] -
1 , 1 ,
( struct
reiserfs_de_head
* )
body ,
body
+
DEH_SIZE ,
tb - >
insert_size
[ 0 ]
) ;
tb - > insert_size [ 0 ] = 0 ;
pos_in_item + + ;
} else { /* new directory entry doesn't fall into S_new[i] */
leaf_move_items
( LEAF_FROM_S_TO_SNEW ,
tb , snum [ i ] ,
sbytes [ i ] ,
S_new [ i ] ) ;
}
} else { /* regular object */
int n_shift , n_rem ,
r_zeros_number ;
const char * r_body ;
RFALSE ( pos_in_item ! =
ih_item_len
( B_N_PITEM_HEAD
( tbS0 , item_pos ) )
| | tb - > insert_size [ 0 ] < =
0 ,
" PAP-12225: item too short or insert_size <= 0 " ) ;
/* Calculate number of bytes which must be shifted from appended item */
n_shift =
sbytes [ i ] -
tb - > insert_size [ 0 ] ;
if ( n_shift < 0 )
n_shift = 0 ;
leaf_move_items
( LEAF_FROM_S_TO_SNEW , tb ,
snum [ i ] , n_shift ,
S_new [ i ] ) ;
/* Calculate number of bytes which must remain in body after append to S_new[i] */
n_rem =
tb - > insert_size [ 0 ] -
sbytes [ i ] ;
if ( n_rem < 0 )
n_rem = 0 ;
/* Append part of body into S_new[0] */
2009-03-30 22:02:42 +04:00
buffer_info_init_bh ( tb , & bi , S_new [ i ] ) ;
2005-07-13 07:21:28 +04:00
if ( n_rem > zeros_num ) {
r_zeros_number = 0 ;
r_body =
body + n_rem -
zeros_num ;
} else {
r_body = body ;
r_zeros_number =
zeros_num - n_rem ;
zeros_num - =
r_zeros_number ;
}
leaf_paste_in_buffer ( & bi , 0 ,
n_shift ,
tb - >
insert_size
[ 0 ] -
n_rem ,
r_body ,
r_zeros_number ) ;
{
struct item_head * tmp ;
tmp =
B_N_PITEM_HEAD ( S_new
[ i ] ,
0 ) ;
if ( is_indirect_le_ih
( tmp ) ) {
set_ih_free_space
( tmp , 0 ) ;
set_le_ih_k_offset
( tmp ,
le_ih_k_offset
( tmp ) +
( n_rem < <
( tb - >
tb_sb - >
s_blocksize_bits
-
UNFM_P_SHIFT ) ) ) ;
} else {
set_le_ih_k_offset
( tmp ,
le_ih_k_offset
( tmp ) +
n_rem ) ;
}
}
tb - > insert_size [ 0 ] = n_rem ;
if ( ! n_rem )
pos_in_item + + ;
}
} else
/* item falls wholly into S_new[i] */
{
2008-04-28 13:16:21 +04:00
int leaf_mi ;
2005-07-13 07:21:28 +04:00
struct item_head * pasted ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
# ifdef CONFIG_REISERFS_CHECK
2008-04-28 13:16:21 +04:00
struct item_head * ih_check =
2005-07-13 07:21:28 +04:00
B_N_PITEM_HEAD ( tbS0 , item_pos ) ;
2008-04-28 13:16:21 +04:00
if ( ! is_direntry_le_ih ( ih_check )
& & ( pos_in_item ! = ih_item_len ( ih_check )
2005-07-13 07:21:28 +04:00
| | tb - > insert_size [ 0 ] < = 0 ) )
reiserfs_panic ( tb - > tb_sb ,
2009-03-30 22:02:25 +04:00
" PAP-12235 " ,
" pos_in_item "
" must be equal "
" to ih_item_len " ) ;
2005-07-13 07:21:28 +04:00
# endif /* CONFIG_REISERFS_CHECK */
2008-04-28 13:16:21 +04:00
leaf_mi =
2005-07-13 07:21:28 +04:00
leaf_move_items ( LEAF_FROM_S_TO_SNEW ,
tb , snum [ i ] ,
sbytes [ i ] ,
S_new [ i ] ) ;
2008-04-28 13:16:21 +04:00
RFALSE ( leaf_mi ,
2005-07-13 07:21:28 +04:00
" PAP-12240: unexpected value returned by leaf_move_items (%d) " ,
2008-04-28 13:16:21 +04:00
leaf_mi ) ;
2005-07-13 07:21:28 +04:00
/* paste into item */
2009-03-30 22:02:42 +04:00
buffer_info_init_bh ( tb , & bi , S_new [ i ] ) ;
2005-07-13 07:21:28 +04:00
leaf_paste_in_buffer ( & bi ,
item_pos - n +
snum [ i ] ,
pos_in_item ,
tb - > insert_size [ 0 ] ,
body , zeros_num ) ;
pasted =
B_N_PITEM_HEAD ( S_new [ i ] ,
item_pos - n +
snum [ i ] ) ;
if ( is_direntry_le_ih ( pasted ) ) {
2009-03-30 22:02:18 +04:00
leaf_paste_entries ( & bi ,
2005-07-13 07:21:28 +04:00
item_pos -
n + snum [ i ] ,
pos_in_item ,
1 ,
( struct
reiserfs_de_head
* ) body ,
body +
DEH_SIZE ,
tb - >
insert_size
[ 0 ]
) ;
}
/* if we paste to indirect item update ih_free_space */
if ( is_indirect_le_ih ( pasted ) )
set_ih_free_space ( pasted , 0 ) ;
zeros_num = tb - > insert_size [ 0 ] = 0 ;
}
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
else { /* pasted item doesn't fall into S_new[i] */
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
leaf_move_items ( LEAF_FROM_S_TO_SNEW , tb ,
snum [ i ] , sbytes [ i ] , S_new [ i ] ) ;
}
break ;
default : /* cases d and t */
2009-03-30 22:02:25 +04:00
reiserfs_panic ( tb - > tb_sb , " PAP-12245 " ,
" blknum > 2: unexpected mode: %s(%d) " ,
2005-07-13 07:21:28 +04:00
( flag = =
M_DELETE ) ? " DELETE " : ( ( flag = =
M_CUT ) ? " CUT "
: " UNKNOWN " ) ,
flag ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
memcpy ( insert_key + i , B_N_PKEY ( S_new [ i ] , 0 ) , KEY_SIZE ) ;
insert_ptr [ i ] = S_new [ i ] ;
RFALSE ( ! buffer_journaled ( S_new [ i ] )
| | buffer_journal_dirty ( S_new [ i ] )
| | buffer_dirty ( S_new [ i ] ) , " PAP-12247: S_new[%d] : (%b) " ,
i , S_new [ i ] ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
/* if the affected item was not wholly shifted then we perform all necessary operations on that part or whole of the
affected item which remains in S */
if ( 0 < = item_pos & & item_pos < tb - > s0num ) { /* if we must insert or append into buffer S[0] */
switch ( flag ) {
case M_INSERT : /* insert item into S[0] */
2009-03-30 22:02:42 +04:00
buffer_info_init_tbS0 ( tb , & bi ) ;
2005-07-13 07:21:28 +04:00
leaf_insert_into_buf ( & bi , item_pos , ih , body ,
zeros_num ) ;
/* If we insert the first key change the delimiting key */
if ( item_pos = = 0 ) {
if ( tb - > CFL [ 0 ] ) /* can be 0 in reiserfsck */
replace_key ( tb , tb - > CFL [ 0 ] , tb - > lkey [ 0 ] ,
tbS0 , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
break ;
case M_PASTE : { /* append item in S[0] */
struct item_head * pasted ;
pasted = B_N_PITEM_HEAD ( tbS0 , item_pos ) ;
/* when directory, may be new entry already pasted */
if ( is_direntry_le_ih ( pasted ) ) {
if ( pos_in_item > = 0 & &
pos_in_item < =
ih_entry_count ( pasted ) ) {
RFALSE ( ! tb - > insert_size [ 0 ] ,
" PAP-12260: insert_size is 0 already " ) ;
/* prepare space */
2009-03-30 22:02:42 +04:00
buffer_info_init_tbS0 ( tb , & bi ) ;
2005-07-13 07:21:28 +04:00
leaf_paste_in_buffer ( & bi ,
item_pos ,
pos_in_item ,
tb - >
insert_size
[ 0 ] , body ,
zeros_num ) ;
/* paste entry */
2009-03-30 22:02:18 +04:00
leaf_paste_entries ( & bi ,
2005-07-13 07:21:28 +04:00
item_pos ,
pos_in_item ,
1 ,
( struct
reiserfs_de_head
* ) body ,
body +
DEH_SIZE ,
tb - >
insert_size
[ 0 ]
) ;
if ( ! item_pos & & ! pos_in_item ) {
RFALSE ( ! tb - > CFL [ 0 ]
| | ! tb - > L [ 0 ] ,
" PAP-12270: CFL[0]/L[0] must be specified " ) ;
if ( tb - > CFL [ 0 ] ) {
replace_key ( tb ,
tb - >
CFL
[ 0 ] ,
tb - >
lkey
[ 0 ] ,
tbS0 ,
0 ) ;
}
}
tb - > insert_size [ 0 ] = 0 ;
}
} else { /* regular object */
if ( pos_in_item = = ih_item_len ( pasted ) ) {
RFALSE ( tb - > insert_size [ 0 ] < = 0 ,
" PAP-12275: insert size must not be %d " ,
tb - > insert_size [ 0 ] ) ;
2009-03-30 22:02:42 +04:00
buffer_info_init_tbS0 ( tb , & bi ) ;
2005-07-13 07:21:28 +04:00
leaf_paste_in_buffer ( & bi ,
item_pos ,
pos_in_item ,
tb - >
insert_size
[ 0 ] , body ,
zeros_num ) ;
if ( is_indirect_le_ih ( pasted ) ) {
2005-04-17 02:20:36 +04:00
#if 0
2005-07-13 07:21:28 +04:00
RFALSE ( tb - >
insert_size [ 0 ] ! =
UNFM_P_SIZE ,
" PAP-12280: insert_size for indirect item must be %d, not %d " ,
UNFM_P_SIZE ,
tb - >
insert_size [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
# endif
2005-07-13 07:21:28 +04:00
set_ih_free_space
( pasted , 0 ) ;
}
tb - > insert_size [ 0 ] = 0 ;
}
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_REISERFS_CHECK
2005-07-13 07:21:28 +04:00
else {
if ( tb - > insert_size [ 0 ] ) {
print_cur_tb ( " 12285 " ) ;
reiserfs_panic ( tb - >
tb_sb ,
2009-03-30 22:02:25 +04:00
" PAP-12285 " ,
" insert_size "
" must be 0 "
" (%d) " ,
tb - > insert_size [ 0 ] ) ;
2005-07-13 07:21:28 +04:00
}
}
# endif /* CONFIG_REISERFS_CHECK */
}
} /* case M_PASTE: */
2005-04-17 02:20:36 +04:00
}
}
# ifdef CONFIG_REISERFS_CHECK
2005-07-13 07:21:28 +04:00
if ( flag = = M_PASTE & & tb - > insert_size [ 0 ] ) {
print_cur_tb ( " 12290 " ) ;
reiserfs_panic ( tb - > tb_sb ,
2009-03-30 22:02:25 +04:00
" PAP-12290 " , " insert_size is still not 0 (%d) " ,
2005-07-13 07:21:28 +04:00
tb - > insert_size [ 0 ] ) ;
}
# endif /* CONFIG_REISERFS_CHECK */
return 0 ;
} /* Leaf level of the tree is balanced (end of balance_leaf) */
2005-04-17 02:20:36 +04:00
/* Make empty node */
2005-07-13 07:21:28 +04:00
void make_empty_node ( struct buffer_info * bi )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
struct block_head * blkh ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
RFALSE ( bi - > bi_bh = = NULL , " PAP-12295: pointer to the buffer is NULL " ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
blkh = B_BLK_HEAD ( bi - > bi_bh ) ;
set_blkh_nr_item ( blkh , 0 ) ;
set_blkh_free_space ( blkh , MAX_CHILD_SIZE ( bi - > bi_bh ) ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
if ( bi - > bi_parent )
B_N_CHILD ( bi - > bi_parent , bi - > bi_position ) - > dc_size = 0 ; /* Endian safe if 0 */
2005-04-17 02:20:36 +04:00
}
/* Get first empty buffer */
2005-07-13 07:21:28 +04:00
struct buffer_head * get_FEB ( struct tree_balance * tb )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
int i ;
struct buffer_info bi ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
for ( i = 0 ; i < MAX_FEB_SIZE ; i + + )
2008-03-29 06:07:28 +03:00
if ( tb - > FEB [ i ] ! = NULL )
2005-07-13 07:21:28 +04:00
break ;
if ( i = = MAX_FEB_SIZE )
2009-03-30 22:02:25 +04:00
reiserfs_panic ( tb - > tb_sb , " vs-12300 " , " FEB list is empty " ) ;
2005-07-13 07:21:28 +04:00
2009-03-30 22:02:42 +04:00
buffer_info_init_bh ( tb , & bi , tb - > FEB [ i ] ) ;
2005-07-13 07:21:28 +04:00
make_empty_node ( & bi ) ;
2009-03-30 22:02:42 +04:00
set_buffer_uptodate ( tb - > FEB [ i ] ) ;
tb - > used [ i ] = tb - > FEB [ i ] ;
2005-07-13 07:21:28 +04:00
tb - > FEB [ i ] = NULL ;
2009-03-30 22:02:42 +04:00
return tb - > used [ i ] ;
2005-07-13 07:21:28 +04:00
}
2005-04-17 02:20:36 +04:00
/* This is now used because reiserfs_free_block has to be able to
* * schedule .
*/
2005-07-13 07:21:28 +04:00
static void store_thrown ( struct tree_balance * tb , struct buffer_head * bh )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
int i ;
if ( buffer_dirty ( bh ) )
2009-03-30 22:02:21 +04:00
reiserfs_warning ( tb - > tb_sb , " reiserfs-12320 " ,
" called with dirty buffer " ) ;
2007-02-12 11:52:09 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( tb - > thrown ) ; i + + )
2005-07-13 07:21:28 +04:00
if ( ! tb - > thrown [ i ] ) {
tb - > thrown [ i ] = bh ;
get_bh ( bh ) ; /* free_thrown puts this */
return ;
}
2009-03-30 22:02:21 +04:00
reiserfs_warning ( tb - > tb_sb , " reiserfs-12321 " ,
" too many thrown buffers " ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
static void free_thrown ( struct tree_balance * tb )
{
int i ;
b_blocknr_t blocknr ;
2007-02-12 11:52:09 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( tb - > thrown ) ; i + + ) {
2005-07-13 07:21:28 +04:00
if ( tb - > thrown [ i ] ) {
blocknr = tb - > thrown [ i ] - > b_blocknr ;
if ( buffer_dirty ( tb - > thrown [ i ] ) )
2009-03-30 22:02:21 +04:00
reiserfs_warning ( tb - > tb_sb , " reiserfs-12322 " ,
" called with dirty buffer %d " ,
2005-07-13 07:21:28 +04:00
blocknr ) ;
brelse ( tb - > thrown [ i ] ) ; /* incremented in store_thrown */
reiserfs_free_block ( tb - > transaction_handle , NULL ,
blocknr , 0 ) ;
}
2005-04-17 02:20:36 +04:00
}
}
2005-07-13 07:21:28 +04:00
void reiserfs_invalidate_buffer ( struct tree_balance * tb , struct buffer_head * bh )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
struct block_head * blkh ;
blkh = B_BLK_HEAD ( bh ) ;
set_blkh_level ( blkh , FREE_LEVEL ) ;
set_blkh_nr_item ( blkh , 0 ) ;
clear_buffer_dirty ( bh ) ;
store_thrown ( tb , bh ) ;
2005-04-17 02:20:36 +04:00
}
/* Replace n_dest'th key in buffer dest by n_src'th key of buffer src.*/
2005-07-13 07:21:28 +04:00
void replace_key ( struct tree_balance * tb , struct buffer_head * dest , int n_dest ,
struct buffer_head * src , int n_src )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
RFALSE ( dest = = NULL | | src = = NULL ,
" vs-12305: source or destination buffer is 0 (src=%p, dest=%p) " ,
src , dest ) ;
RFALSE ( ! B_IS_KEYS_LEVEL ( dest ) ,
" vs-12310: invalid level (%z) for destination buffer. dest must be leaf " ,
dest ) ;
RFALSE ( n_dest < 0 | | n_src < 0 ,
" vs-12315: src(%d) or dest(%d) key number < 0 " , n_src , n_dest ) ;
RFALSE ( n_dest > = B_NR_ITEMS ( dest ) | | n_src > = B_NR_ITEMS ( src ) ,
" vs-12320: src(%d(%d)) or dest(%d(%d)) key number is too big " ,
n_src , B_NR_ITEMS ( src ) , n_dest , B_NR_ITEMS ( dest ) ) ;
if ( B_IS_ITEMS_LEVEL ( src ) )
/* source buffer contains leaf node */
memcpy ( B_N_PDELIM_KEY ( dest , n_dest ) , B_N_PITEM_HEAD ( src , n_src ) ,
KEY_SIZE ) ;
else
memcpy ( B_N_PDELIM_KEY ( dest , n_dest ) , B_N_PDELIM_KEY ( src , n_src ) ,
KEY_SIZE ) ;
do_balance_mark_internal_dirty ( tb , dest , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
int get_left_neighbor_position ( struct tree_balance * tb , int h )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
int Sh_position = PATH_H_POSITION ( tb - > tb_path , h + 1 ) ;
2005-04-17 02:20:36 +04:00
2008-03-29 06:07:28 +03:00
RFALSE ( PATH_H_PPARENT ( tb - > tb_path , h ) = = NULL | | tb - > FL [ h ] = = NULL ,
2005-07-13 07:21:28 +04:00
" vs-12325: FL[%d](%p) or F[%d](%p) does not exist " ,
h , tb - > FL [ h ] , h , PATH_H_PPARENT ( tb - > tb_path , h ) ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
if ( Sh_position = = 0 )
return B_NR_ITEMS ( tb - > FL [ h ] ) ;
else
return Sh_position - 1 ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
int get_right_neighbor_position ( struct tree_balance * tb , int h )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
int Sh_position = PATH_H_POSITION ( tb - > tb_path , h + 1 ) ;
2005-04-17 02:20:36 +04:00
2008-03-29 06:07:28 +03:00
RFALSE ( PATH_H_PPARENT ( tb - > tb_path , h ) = = NULL | | tb - > FR [ h ] = = NULL ,
2005-07-13 07:21:28 +04:00
" vs-12330: F[%d](%p) or FR[%d](%p) does not exist " ,
h , PATH_H_PPARENT ( tb - > tb_path , h ) , h , tb - > FR [ h ] ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
if ( Sh_position = = B_NR_ITEMS ( PATH_H_PPARENT ( tb - > tb_path , h ) ) )
return 0 ;
else
return Sh_position + 1 ;
2005-04-17 02:20:36 +04:00
}
# ifdef CONFIG_REISERFS_CHECK
2005-07-13 07:21:28 +04:00
int is_reusable ( struct super_block * s , b_blocknr_t block , int bit_value ) ;
static void check_internal_node ( struct super_block * s , struct buffer_head * bh ,
char * mes )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
struct disk_child * dc ;
int i ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
RFALSE ( ! bh , " PAP-12336: bh == 0 " ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
if ( ! bh | | ! B_IS_IN_TREE ( bh ) )
return ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
RFALSE ( ! buffer_dirty ( bh ) & &
! ( buffer_journaled ( bh ) | | buffer_journal_dirty ( bh ) ) ,
" PAP-12337: buffer (%b) must be dirty " , bh ) ;
dc = B_N_CHILD ( bh , 0 ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
for ( i = 0 ; i < = B_NR_ITEMS ( bh ) ; i + + , dc + + ) {
if ( ! is_reusable ( s , dc_block_number ( dc ) , 1 ) ) {
print_cur_tb ( mes ) ;
2009-03-30 22:02:25 +04:00
reiserfs_panic ( s , " PAP-12338 " ,
" invalid child pointer %y in %b " ,
2005-07-13 07:21:28 +04:00
dc , bh ) ;
}
}
2005-04-17 02:20:36 +04:00
}
2009-03-30 22:02:21 +04:00
static int locked_or_not_in_tree ( struct tree_balance * tb ,
struct buffer_head * bh , char * which )
2005-07-13 07:21:28 +04:00
{
if ( ( ! buffer_journal_prepared ( bh ) & & buffer_locked ( bh ) ) | |
! B_IS_IN_TREE ( bh ) ) {
2009-03-30 22:02:21 +04:00
reiserfs_warning ( tb - > tb_sb , " vs-12339 " , " %s (%b) " , which , bh ) ;
2005-07-13 07:21:28 +04:00
return 1 ;
}
return 0 ;
}
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
static int check_before_balancing ( struct tree_balance * tb )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
int retval = 0 ;
kill-the-bkl/reiserfs: move the concurrent tree accesses checks per superblock
When do_balance() balances the tree, a trick is performed to
provide the ability for other tree writers/readers to check whether
do_balance() is executing concurrently (requires CONFIG_REISERFS_CHECK).
This is done to protect concurrent accesses to the tree. The trick
is the following:
When do_balance is called, a unique global variable called cur_tb
takes a pointer to the current tree to be rebalanced.
Once do_balance finishes its work, cur_tb takes the NULL value.
Then, concurrent tree readers/writers just have to check the value
of cur_tb to ensure do_balance isn't executing concurrently.
If it is, then it proves that schedule() occured on do_balance(),
which then relaxed the bkl that protected the tree.
Now that the bkl has be turned into a mutex, this check is still
fine even though do_balance() becomes preemptible: the write lock
will not be automatically released on schedule(), so the tree is
still protected.
But this is only fine if we have a single reiserfs mountpoint.
Indeed, because the bkl is a global lock, it didn't allowed
concurrent executions between a tree reader/writer in a mount point
and a do_balance() on another tree from another mountpoint.
So assuming all these readers/writers weren't supposed to be
reentrant, the current check now sometimes detect false positives with
the current per-superblock mutex which allows this reentrancy.
This patch keeps the concurrent tree accesses check but moves it
per superblock, so that only trees from a same mount point are
checked to be not accessed concurrently.
[ Impact: fix spurious panic while running several reiserfs mount-points ]
Cc: Jeff Mahoney <jeffm@suse.com>
Cc: Chris Mason <chris.mason@oracle.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Alexander Beregalov <a.beregalov@gmail.com>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
2009-05-16 21:10:38 +04:00
if ( REISERFS_SB ( tb - > tb_sb ) - > cur_tb ) {
2009-03-30 22:02:25 +04:00
reiserfs_panic ( tb - > tb_sb , " vs-12335 " , " suspect that schedule "
" occurred based on cur_tb not being null at "
" this point in code. do_balance cannot properly "
kill-the-bkl/reiserfs: move the concurrent tree accesses checks per superblock
When do_balance() balances the tree, a trick is performed to
provide the ability for other tree writers/readers to check whether
do_balance() is executing concurrently (requires CONFIG_REISERFS_CHECK).
This is done to protect concurrent accesses to the tree. The trick
is the following:
When do_balance is called, a unique global variable called cur_tb
takes a pointer to the current tree to be rebalanced.
Once do_balance finishes its work, cur_tb takes the NULL value.
Then, concurrent tree readers/writers just have to check the value
of cur_tb to ensure do_balance isn't executing concurrently.
If it is, then it proves that schedule() occured on do_balance(),
which then relaxed the bkl that protected the tree.
Now that the bkl has be turned into a mutex, this check is still
fine even though do_balance() becomes preemptible: the write lock
will not be automatically released on schedule(), so the tree is
still protected.
But this is only fine if we have a single reiserfs mountpoint.
Indeed, because the bkl is a global lock, it didn't allowed
concurrent executions between a tree reader/writer in a mount point
and a do_balance() on another tree from another mountpoint.
So assuming all these readers/writers weren't supposed to be
reentrant, the current check now sometimes detect false positives with
the current per-superblock mutex which allows this reentrancy.
This patch keeps the concurrent tree accesses check but moves it
per superblock, so that only trees from a same mount point are
checked to be not accessed concurrently.
[ Impact: fix spurious panic while running several reiserfs mount-points ]
Cc: Jeff Mahoney <jeffm@suse.com>
Cc: Chris Mason <chris.mason@oracle.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Alexander Beregalov <a.beregalov@gmail.com>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
2009-05-16 21:10:38 +04:00
" handle concurrent tree accesses on a same "
" mount point. " ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
/* double check that buffers that we will modify are unlocked. (fix_nodes should already have
prepped all of these for us ) . */
if ( tb - > lnum [ 0 ] ) {
2009-03-30 22:02:21 +04:00
retval | = locked_or_not_in_tree ( tb , tb - > L [ 0 ] , " L[0] " ) ;
retval | = locked_or_not_in_tree ( tb , tb - > FL [ 0 ] , " FL[0] " ) ;
retval | = locked_or_not_in_tree ( tb , tb - > CFL [ 0 ] , " CFL[0] " ) ;
2005-07-13 07:21:28 +04:00
check_leaf ( tb - > L [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
if ( tb - > rnum [ 0 ] ) {
2009-03-30 22:02:21 +04:00
retval | = locked_or_not_in_tree ( tb , tb - > R [ 0 ] , " R[0] " ) ;
retval | = locked_or_not_in_tree ( tb , tb - > FR [ 0 ] , " FR[0] " ) ;
retval | = locked_or_not_in_tree ( tb , tb - > CFR [ 0 ] , " CFR[0] " ) ;
2005-07-13 07:21:28 +04:00
check_leaf ( tb - > R [ 0 ] ) ;
}
2009-03-30 22:02:21 +04:00
retval | = locked_or_not_in_tree ( tb , PATH_PLAST_BUFFER ( tb - > tb_path ) ,
" S[0] " ) ;
2005-07-13 07:21:28 +04:00
check_leaf ( PATH_PLAST_BUFFER ( tb - > tb_path ) ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
return retval ;
}
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
static void check_after_balance_leaf ( struct tree_balance * tb )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
if ( tb - > lnum [ 0 ] ) {
if ( B_FREE_SPACE ( tb - > L [ 0 ] ) ! =
MAX_CHILD_SIZE ( tb - > L [ 0 ] ) -
dc_size ( B_N_CHILD
( tb - > FL [ 0 ] , get_left_neighbor_position ( tb , 0 ) ) ) ) {
print_cur_tb ( " 12221 " ) ;
2009-03-30 22:02:25 +04:00
reiserfs_panic ( tb - > tb_sb , " PAP-12355 " ,
" shift to left was incorrect " ) ;
2005-07-13 07:21:28 +04:00
}
}
if ( tb - > rnum [ 0 ] ) {
if ( B_FREE_SPACE ( tb - > R [ 0 ] ) ! =
MAX_CHILD_SIZE ( tb - > R [ 0 ] ) -
dc_size ( B_N_CHILD
( tb - > FR [ 0 ] , get_right_neighbor_position ( tb , 0 ) ) ) ) {
print_cur_tb ( " 12222 " ) ;
2009-03-30 22:02:25 +04:00
reiserfs_panic ( tb - > tb_sb , " PAP-12360 " ,
" shift to right was incorrect " ) ;
2005-07-13 07:21:28 +04:00
}
}
if ( PATH_H_PBUFFER ( tb - > tb_path , 1 ) & &
( B_FREE_SPACE ( PATH_H_PBUFFER ( tb - > tb_path , 0 ) ) ! =
( MAX_CHILD_SIZE ( PATH_H_PBUFFER ( tb - > tb_path , 0 ) ) -
dc_size ( B_N_CHILD ( PATH_H_PBUFFER ( tb - > tb_path , 1 ) ,
PATH_H_POSITION ( tb - > tb_path , 1 ) ) ) ) ) ) {
int left = B_FREE_SPACE ( PATH_H_PBUFFER ( tb - > tb_path , 0 ) ) ;
int right = ( MAX_CHILD_SIZE ( PATH_H_PBUFFER ( tb - > tb_path , 0 ) ) -
dc_size ( B_N_CHILD ( PATH_H_PBUFFER ( tb - > tb_path , 1 ) ,
PATH_H_POSITION ( tb - > tb_path ,
1 ) ) ) ) ;
print_cur_tb ( " 12223 " ) ;
2009-03-30 22:02:21 +04:00
reiserfs_warning ( tb - > tb_sb , " reiserfs-12363 " ,
2005-07-13 07:21:28 +04:00
" B_FREE_SPACE (PATH_H_PBUFFER(tb->tb_path,0)) = %d; "
" MAX_CHILD_SIZE (%d) - dc_size( %y, %d ) [%d] = %d " ,
left ,
MAX_CHILD_SIZE ( PATH_H_PBUFFER ( tb - > tb_path , 0 ) ) ,
PATH_H_PBUFFER ( tb - > tb_path , 1 ) ,
PATH_H_POSITION ( tb - > tb_path , 1 ) ,
dc_size ( B_N_CHILD
( PATH_H_PBUFFER ( tb - > tb_path , 1 ) ,
PATH_H_POSITION ( tb - > tb_path , 1 ) ) ) ,
right ) ;
2009-03-30 22:02:25 +04:00
reiserfs_panic ( tb - > tb_sb , " PAP-12365 " , " S is incorrect " ) ;
2005-07-13 07:21:28 +04:00
}
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
static void check_leaf_level ( struct tree_balance * tb )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
check_leaf ( tb - > L [ 0 ] ) ;
check_leaf ( tb - > R [ 0 ] ) ;
check_leaf ( PATH_PLAST_BUFFER ( tb - > tb_path ) ) ;
}
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
static void check_internal_levels ( struct tree_balance * tb )
{
int h ;
/* check all internal nodes */
for ( h = 1 ; tb - > insert_size [ h ] ; h + + ) {
check_internal_node ( tb - > tb_sb , PATH_H_PBUFFER ( tb - > tb_path , h ) ,
" BAD BUFFER ON PATH " ) ;
if ( tb - > lnum [ h ] )
check_internal_node ( tb - > tb_sb , tb - > L [ h ] , " BAD L " ) ;
if ( tb - > rnum [ h ] )
check_internal_node ( tb - > tb_sb , tb - > R [ h ] , " BAD R " ) ;
}
2005-04-17 02:20:36 +04:00
}
# endif
/* Now we have all of the buffers that must be used in balancing of
the tree . We rely on the assumption that schedule ( ) will not occur
while do_balance works . ( Only interrupt handlers are acceptable . )
We balance the tree according to the analysis made before this ,
using buffers already obtained . For SMP support it will someday be
necessary to add ordered locking of tb . */
/* Some interesting rules of balancing:
we delete a maximum of two nodes per level per balancing : we never
delete R , when we delete two of three nodes L , S , R then we move
them into R .
we only delete L if we are deleting two nodes , if we delete only
one node we delete S
if we shift leaves then we shift as much as we can : this is a
deliberate policy of extremism in node packing which results in
higher average utilization after repeated random balance operations
at the cost of more memory copies and more balancing as a result of
small insertions to full nodes .
if we shift internal nodes we try to evenly balance the node
utilization , with consequent less balancing at the cost of lower
utilization .
one could argue that the policy for directories in leaves should be
that of internal nodes , but we will wait until another day to
evaluate this . . . . It would be nice to someday measure and prove
these assumptions as to what is optimal . . . .
*/
2005-07-13 07:21:28 +04:00
static inline void do_balance_starts ( struct tree_balance * tb )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
/* use print_cur_tb() to see initial state of struct
tree_balance */
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
/* store_print_tb (tb); */
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
/* do not delete, just comment it out */
2009-03-30 22:02:44 +04:00
/* print_tb(flag, PATH_LAST_POSITION(tb->tb_path), tb->tb_path->pos_in_item, tb,
2005-04-17 02:20:36 +04:00
" check " ) ; */
2005-07-13 07:21:28 +04:00
RFALSE ( check_before_balancing ( tb ) , " PAP-12340: locked buffers in TB " ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_REISERFS_CHECK
kill-the-bkl/reiserfs: move the concurrent tree accesses checks per superblock
When do_balance() balances the tree, a trick is performed to
provide the ability for other tree writers/readers to check whether
do_balance() is executing concurrently (requires CONFIG_REISERFS_CHECK).
This is done to protect concurrent accesses to the tree. The trick
is the following:
When do_balance is called, a unique global variable called cur_tb
takes a pointer to the current tree to be rebalanced.
Once do_balance finishes its work, cur_tb takes the NULL value.
Then, concurrent tree readers/writers just have to check the value
of cur_tb to ensure do_balance isn't executing concurrently.
If it is, then it proves that schedule() occured on do_balance(),
which then relaxed the bkl that protected the tree.
Now that the bkl has be turned into a mutex, this check is still
fine even though do_balance() becomes preemptible: the write lock
will not be automatically released on schedule(), so the tree is
still protected.
But this is only fine if we have a single reiserfs mountpoint.
Indeed, because the bkl is a global lock, it didn't allowed
concurrent executions between a tree reader/writer in a mount point
and a do_balance() on another tree from another mountpoint.
So assuming all these readers/writers weren't supposed to be
reentrant, the current check now sometimes detect false positives with
the current per-superblock mutex which allows this reentrancy.
This patch keeps the concurrent tree accesses check but moves it
per superblock, so that only trees from a same mount point are
checked to be not accessed concurrently.
[ Impact: fix spurious panic while running several reiserfs mount-points ]
Cc: Jeff Mahoney <jeffm@suse.com>
Cc: Chris Mason <chris.mason@oracle.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Alexander Beregalov <a.beregalov@gmail.com>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
2009-05-16 21:10:38 +04:00
REISERFS_SB ( tb - > tb_sb ) - > cur_tb = tb ;
2005-04-17 02:20:36 +04:00
# endif
}
2005-07-13 07:21:28 +04:00
static inline void do_balance_completed ( struct tree_balance * tb )
2005-04-17 02:20:36 +04:00
{
2005-07-13 07:21:28 +04:00
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_REISERFS_CHECK
2005-07-13 07:21:28 +04:00
check_leaf_level ( tb ) ;
check_internal_levels ( tb ) ;
kill-the-bkl/reiserfs: move the concurrent tree accesses checks per superblock
When do_balance() balances the tree, a trick is performed to
provide the ability for other tree writers/readers to check whether
do_balance() is executing concurrently (requires CONFIG_REISERFS_CHECK).
This is done to protect concurrent accesses to the tree. The trick
is the following:
When do_balance is called, a unique global variable called cur_tb
takes a pointer to the current tree to be rebalanced.
Once do_balance finishes its work, cur_tb takes the NULL value.
Then, concurrent tree readers/writers just have to check the value
of cur_tb to ensure do_balance isn't executing concurrently.
If it is, then it proves that schedule() occured on do_balance(),
which then relaxed the bkl that protected the tree.
Now that the bkl has be turned into a mutex, this check is still
fine even though do_balance() becomes preemptible: the write lock
will not be automatically released on schedule(), so the tree is
still protected.
But this is only fine if we have a single reiserfs mountpoint.
Indeed, because the bkl is a global lock, it didn't allowed
concurrent executions between a tree reader/writer in a mount point
and a do_balance() on another tree from another mountpoint.
So assuming all these readers/writers weren't supposed to be
reentrant, the current check now sometimes detect false positives with
the current per-superblock mutex which allows this reentrancy.
This patch keeps the concurrent tree accesses check but moves it
per superblock, so that only trees from a same mount point are
checked to be not accessed concurrently.
[ Impact: fix spurious panic while running several reiserfs mount-points ]
Cc: Jeff Mahoney <jeffm@suse.com>
Cc: Chris Mason <chris.mason@oracle.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Alexander Beregalov <a.beregalov@gmail.com>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
2009-05-16 21:10:38 +04:00
REISERFS_SB ( tb - > tb_sb ) - > cur_tb = NULL ;
2005-04-17 02:20:36 +04:00
# endif
2005-07-13 07:21:28 +04:00
/* reiserfs_free_block is no longer schedule safe. So, we need to
* * put the buffers we want freed on the thrown list during do_balance ,
* * and then free them now
*/
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
REISERFS_SB ( tb - > tb_sb ) - > s_do_balance + + ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
/* release all nodes hold to perform the balancing */
unfix_nodes ( tb ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
free_thrown ( tb ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-13 07:21:28 +04:00
void do_balance ( struct tree_balance * tb , /* tree_balance structure */
struct item_head * ih , /* item header of inserted item */
const char * body , /* body of inserted item or bytes to paste */
int flag )
{ /* i - insert, d - delete
c - cut , p - paste
Cut means delete part of an item
( includes removing an entry from a
directory ) .
Delete means delete whole item .
Insert means add a new item into the
tree .
Paste means to append to the end of an
existing file or to insert a directory
entry . */
int child_pos , /* position of a child node in its parent */
h ; /* level of the tree being processed */
struct item_head insert_key [ 2 ] ; /* in our processing of one level
we sometimes determine what
must be inserted into the next
higher level . This insertion
consists of a key or two keys
and their corresponding
pointers */
struct buffer_head * insert_ptr [ 2 ] ; /* inserted node-ptrs for the next
level */
tb - > tb_mode = flag ;
tb - > need_balance_dirty = 0 ;
if ( FILESYSTEM_CHANGED_TB ( tb ) ) {
2009-03-30 22:02:25 +04:00
reiserfs_panic ( tb - > tb_sb , " clm-6000 " , " fs generation has "
" changed " ) ;
2005-07-13 07:21:28 +04:00
}
/* if we have no real work to do */
if ( ! tb - > insert_size [ 0 ] ) {
2009-03-30 22:02:21 +04:00
reiserfs_warning ( tb - > tb_sb , " PAP-12350 " ,
" insert_size == 0, mode == %c " , flag ) ;
2005-07-13 07:21:28 +04:00
unfix_nodes ( tb ) ;
return ;
}
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
atomic_inc ( & ( fs_generation ( tb - > tb_sb ) ) ) ;
do_balance_starts ( tb ) ;
2005-04-17 02:20:36 +04:00
/* balance leaf returns 0 except if combining L R and S into
one node . see balance_internal ( ) for explanation of this
2005-07-13 07:21:28 +04:00
line of code . */
child_pos = PATH_H_B_ITEM_ORDER ( tb - > tb_path , 0 ) +
balance_leaf ( tb , ih , body , flag , insert_key , insert_ptr ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_REISERFS_CHECK
2005-07-13 07:21:28 +04:00
check_after_balance_leaf ( tb ) ;
2005-04-17 02:20:36 +04:00
# endif
2005-07-13 07:21:28 +04:00
/* Balance internal level of the tree. */
for ( h = 1 ; h < MAX_HEIGHT & & tb - > insert_size [ h ] ; h + + )
child_pos =
balance_internal ( tb , h , child_pos , insert_key , insert_ptr ) ;
2005-04-17 02:20:36 +04:00
2005-07-13 07:21:28 +04:00
do_balance_completed ( tb ) ;
2005-04-17 02:20:36 +04:00
}