2005-04-17 02:20:36 +04:00
/*
* Copyright 2000 by Hans Reiser , licensing governed by reiserfs / README
*/
2014-04-23 18:00:36 +04:00
/*
* 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 .
*/
2005-04-17 02:20:36 +04:00
2014-08-09 01:21:12 +04:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <linux/time.h>
2012-03-17 09:16:43 +04:00
# include "reiserfs.h"
2005-04-17 02:20:36 +04:00
# 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
{
2014-04-23 18:00:39 +04:00
journal_mark_dirty ( tb - > transaction_handle , 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
2014-04-23 18:00:36 +04:00
/*
* summary :
* 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
* if snum2 is larger than 0 we put items into the new node s2
* Note that all * num * count new items being created .
*/
2014-04-23 18:01:02 +04:00
static void balance_leaf_when_delete_del ( struct tree_balance * tb )
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
int item_pos = PATH_LAST_POSITION ( tb - > tb_path ) ;
struct buffer_info bi ;
# ifdef CONFIG_REISERFS_CHECK
struct item_head * ih = item_head ( tbS0 , item_pos ) ;
# endif
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 ) ;
buffer_info_init_tbS0 ( tb , & bi ) ;
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 ) ;
}
}
RFALSE ( ! item_pos & & ! tb - > CFL [ 0 ] ,
" PAP-12020: tb->CFL[0]==%p, tb->L[0]==%p " , tb - > CFL [ 0 ] ,
tb - > L [ 0 ] ) ;
}
/* cut item in S[0] */
static void balance_leaf_when_delete_cut ( struct tree_balance * tb )
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
int item_pos = PATH_LAST_POSITION ( tb - > tb_path ) ;
struct item_head * ih = item_head ( tbS0 , item_pos ) ;
int pos_in_item = tb - > tb_path - > pos_in_item ;
struct buffer_info bi ;
buffer_info_init_tbS0 ( tb , & bi ) ;
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 " ) ;
}
}
static int balance_leaf_when_delete_left ( struct tree_balance * tb )
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
int n = B_NR_ITEMS ( tbS0 ) ;
/* L[0] must be joined with S[0] */
if ( tb - > lnum [ 0 ] = = - 1 ) {
/* R[0] must be also joined with S[0] */
if ( tb - > rnum [ 0 ] = = - 1 ) {
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 ) ;
reiserfs_invalidate_buffer ( tb , tbS0 ) ;
reiserfs_invalidate_buffer ( tb , tb - > L [ 0 ] ) ;
return - 1 ;
}
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 ) ;
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 ;
}
2014-04-23 18:00:36 +04:00
/*
* Balance leaf node in case of delete or cut : insert_size [ 0 ] < 0
2005-04-17 02:20:36 +04:00
*
* 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
2014-04-23 18:00:36 +04:00
* > 0 means to shift entirely or partly the specified number of items
* to the neighbor
2005-04-17 02:20:36 +04:00
*/
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 ) ;
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
2014-04-23 18:00:35 +04:00
ih = item_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
2014-04-23 18:01:02 +04:00
BUG_ON ( flag ! = M_DELETE & & flag ! = M_CUT ) ;
if ( flag = = M_DELETE )
balance_leaf_when_delete_del ( tb ) ;
else /* M_CUT */
balance_leaf_when_delete_cut ( tb ) ;
2005-04-17 02:20:36 +04:00
2014-04-23 18:00:36 +04:00
/*
* the rule is that no shifting occurs unless by shifting
* a node can be freed
*/
2005-07-13 07:21:28 +04:00
n = B_NR_ITEMS ( tbS0 ) ;
2005-04-17 02:20:36 +04:00
2014-04-23 18:01:02 +04:00
/* L[0] takes part in balancing */
if ( tb - > lnum [ 0 ] )
return balance_leaf_when_delete_left ( tb ) ;
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 ;
}
2014-08-05 03:51:47 +04:00
static unsigned int balance_leaf_insert_left ( struct tree_balance * tb ,
struct item_head * const ih ,
const char * const body )
2014-04-23 18:00:47 +04:00
{
2014-04-23 18:00:56 +04:00
int ret ;
2014-04-23 18:00:47 +04:00
struct buffer_info bi ;
int n = B_NR_ITEMS ( tb - > L [ 0 ] ) ;
2014-08-05 03:51:47 +04:00
unsigned body_shift_bytes = 0 ;
2014-04-23 18:00:47 +04:00
2014-04-23 18:00:56 +04:00
if ( tb - > item_pos = = tb - > lnum [ 0 ] - 1 & & tb - > lbytes ! = - 1 ) {
/* part of new item falls into L[0] */
int new_item_len , shift ;
int version ;
ret = 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 ) ;
2014-04-23 18:00:47 +04:00
2014-04-23 18:00:56 +04:00
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] */
buffer_info_init_left ( tb , & bi ) ;
leaf_insert_into_buf ( & bi , n + tb - > item_pos - ret , ih , body ,
min_t ( int , tb - > zeroes_num , ih_item_len ( ih ) ) ) ;
version = ih_version ( ih ) ;
/*
* Calculate key component , item length and body to
* insert into S [ 0 ]
*/
shift = 0 ;
if ( is_indirect_le_ih ( ih ) )
shift = tb - > tb_sb - > s_blocksize_bits - UNFM_P_SHIFT ;
add_le_ih_k_offset ( ih , tb - > lbytes < < shift ) ;
put_ih_item_len ( ih , new_item_len ) ;
if ( tb - > lbytes > tb - > zeroes_num ) {
2014-08-05 03:51:47 +04:00
body_shift_bytes = tb - > lbytes - tb - > zeroes_num ;
2014-04-23 18:00:56 +04:00
tb - > zeroes_num = 0 ;
} else
tb - > zeroes_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 = leaf_shift_left ( tb , tb - > lnum [ 0 ] - 1 , tb - > lbytes ) ;
/* Insert new item into L[0] */
buffer_info_init_left ( tb , & bi ) ;
leaf_insert_into_buf ( & bi , n + tb - > item_pos - ret , ih , body ,
tb - > zeroes_num ) ;
tb - > insert_size [ 0 ] = 0 ;
tb - > zeroes_num = 0 ;
}
2014-08-05 03:51:47 +04:00
return body_shift_bytes ;
2014-04-23 18:00:47 +04:00
}
2014-04-23 18:00:57 +04:00
static void balance_leaf_paste_left_shift_dirent ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body )
2014-04-23 18:00:57 +04:00
{
int n = B_NR_ITEMS ( tb - > L [ 0 ] ) ;
struct buffer_info bi ;
RFALSE ( tb - > zeroes_num ,
" PAP-12090: invalid parameter in case of a directory " ) ;
/* directory item */
if ( tb - > lbytes > tb - > pos_in_item ) {
/* new directory entry falls into L[0] */
struct item_head * pasted ;
int ret , l_pos_in_item = tb - > pos_in_item ;
/*
* Shift lnum [ 0 ] - 1 items in whole .
* Shift lbytes - 1 entries from given directory item
*/
ret = leaf_shift_left ( tb , tb - > lnum [ 0 ] , tb - > lbytes - 1 ) ;
if ( ret & & ! tb - > item_pos ) {
pasted = item_head ( tb - > L [ 0 ] , B_NR_ITEMS ( tb - > L [ 0 ] ) - 1 ) ;
l_pos_in_item + = ih_entry_count ( pasted ) -
( tb - > lbytes - 1 ) ;
}
/* Append given directory entry to directory item */
buffer_info_init_left ( tb , & bi ) ;
leaf_paste_in_buffer ( & bi , n + tb - > item_pos - ret ,
l_pos_in_item , tb - > insert_size [ 0 ] ,
body , tb - > zeroes_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 */
leaf_paste_entries ( & bi , n + tb - > item_pos - ret ,
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 */
tb - > pos_in_item - = tb - > lbytes ;
}
2014-08-05 03:51:47 +04:00
static unsigned int balance_leaf_paste_left_shift ( struct tree_balance * tb ,
struct item_head * const ih ,
const char * const body )
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 ) ;
2014-04-23 18:00:57 +04:00
int n = B_NR_ITEMS ( tb - > L [ 0 ] ) ;
2014-04-23 18:00:48 +04:00
struct buffer_info bi ;
2014-08-05 03:51:47 +04:00
int body_shift_bytes = 0 ;
2014-04-23 18:00:57 +04:00
if ( is_direntry_le_ih ( item_head ( tbS0 , tb - > item_pos ) ) ) {
balance_leaf_paste_left_shift_dirent ( tb , ih , body ) ;
2014-08-05 03:51:47 +04:00
return 0 ;
2014-04-23 18:00:57 +04:00
}
RFALSE ( tb - > lbytes < = 0 ,
" PAP-12095: there is nothing to shift to L[0]. "
" lbytes=%d " , tb - > lbytes ) ;
RFALSE ( tb - > pos_in_item ! = ih_item_len ( item_head ( tbS0 , tb - > item_pos ) ) ,
" PAP-12100: incorrect position to paste: "
" item_len=%d, pos_in_item=%d " ,
ih_item_len ( item_head ( tbS0 , tb - > item_pos ) ) , tb - > pos_in_item ) ;
/* appended item will be in L[0] in whole */
if ( tb - > lbytes > = tb - > pos_in_item ) {
struct item_head * tbS0_pos_ih , * tbL0_ih ;
struct item_head * tbS0_0_ih ;
struct reiserfs_key * left_delim_key ;
int ret , l_n , version , temp_l ;
tbS0_pos_ih = item_head ( tbS0 , tb - > item_pos ) ;
tbS0_0_ih = item_head ( tbS0 , 0 ) ;
/*
* this bytes number must be appended
* to the last item of L [ h ]
*/
l_n = tb - > lbytes - tb - > 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 = leaf_shift_left ( tb , tb - > lnum [ 0 ] ,
ih_item_len ( tbS0_pos_ih ) ) ;
tbL0_ih = item_head ( tb - > L [ 0 ] , n + tb - > item_pos - ret ) ;
/* Append to body of item in L[0] */
buffer_info_init_left ( tb , & bi ) ;
leaf_paste_in_buffer ( & bi , n + tb - > item_pos - ret ,
ih_item_len ( tbL0_ih ) , l_n , body ,
min_t ( int , l_n , tb - > zeroes_num ) ) ;
/*
* 0 - th item in S0 can be only of DIRECT type
* when l_n ! = 0
*/
temp_l = l_n ;
RFALSE ( ih_item_len ( tbS0_0_ih ) ,
" PAP-12106: item length must be 0 " ) ;
RFALSE ( comp_short_le_keys ( & tbS0_0_ih - > ih_key ,
leaf_key ( tb - > L [ 0 ] , n + tb - > item_pos - ret ) ) ,
" PAP-12107: items must be of the same file " ) ;
if ( is_indirect_le_ih ( tbL0_ih ) ) {
int shift = tb - > tb_sb - > s_blocksize_bits - UNFM_P_SHIFT ;
temp_l = l_n < < shift ;
}
/* update key of first item in S0 */
version = ih_version ( tbS0_0_ih ) ;
add_le_key_k_offset ( version , & tbS0_0_ih - > ih_key , temp_l ) ;
/* update left delimiting key */
left_delim_key = internal_key ( tb - > CFL [ 0 ] , tb - > lkey [ 0 ] ) ;
add_le_key_k_offset ( version , left_delim_key , temp_l ) ;
/*
* Calculate new body , position in item and
* insert_size [ 0 ]
*/
if ( l_n > tb - > zeroes_num ) {
2014-08-05 03:51:47 +04:00
body_shift_bytes = l_n - tb - > zeroes_num ;
2014-04-23 18:00:57 +04:00
tb - > zeroes_num = 0 ;
} else
tb - > zeroes_num - = l_n ;
tb - > pos_in_item = 0 ;
RFALSE ( comp_short_le_keys ( & tbS0_0_ih - > ih_key ,
leaf_key ( tb - > L [ 0 ] ,
B_NR_ITEMS ( tb - > L [ 0 ] ) - 1 ) ) | |
! op_is_left_mergeable ( leaf_key ( tbS0 , 0 ) , tbS0 - > b_size ) | |
! op_is_left_mergeable ( left_delim_key , 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] */
tb - > pos_in_item - = tb - > lbytes ;
RFALSE ( tb - > pos_in_item < = 0 ,
" PAP-12125: no place for paste. pos_in_item=%d " ,
tb - > 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 ) ;
}
2014-08-05 03:51:47 +04:00
return body_shift_bytes ;
2014-04-23 18:00:57 +04:00
}
/* appended item will be in L[0] in whole */
static void balance_leaf_paste_left_whole ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body )
2014-04-23 18:00:57 +04:00
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
2014-04-23 18:00:48 +04:00
int n = B_NR_ITEMS ( tb - > L [ 0 ] ) ;
2014-04-23 18:00:57 +04:00
struct buffer_info bi ;
struct item_head * pasted ;
int ret ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:57 +04:00
/* if we paste into first item of S[0] and it is left mergable */
if ( ! tb - > item_pos & &
op_is_left_mergeable ( leaf_key ( tbS0 , 0 ) , tbS0 - > b_size ) ) {
/*
* then increment pos_in_item by the size of the
* last item in L [ 0 ]
*/
pasted = item_head ( tb - > L [ 0 ] , n - 1 ) ;
if ( is_direntry_le_ih ( pasted ) )
tb - > pos_in_item + = ih_entry_count ( pasted ) ;
else
tb - > pos_in_item + = ih_item_len ( pasted ) ;
}
/*
* Shift lnum [ 0 ] - 1 items in whole .
* Shift lbytes - 1 byte from item number lnum [ 0 ]
*/
ret = leaf_shift_left ( tb , tb - > lnum [ 0 ] , tb - > lbytes ) ;
/* Append to body of item in L[0] */
buffer_info_init_left ( tb , & bi ) ;
leaf_paste_in_buffer ( & bi , n + tb - > item_pos - ret , tb - > pos_in_item ,
tb - > insert_size [ 0 ] , body , tb - > zeroes_num ) ;
/* if appended item is directory, paste entry */
pasted = item_head ( tb - > L [ 0 ] , n + tb - > item_pos - ret ) ;
if ( is_direntry_le_ih ( pasted ) )
leaf_paste_entries ( & bi , n + tb - > item_pos - ret ,
tb - > 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 ) ;
2014-04-23 18:00:48 +04:00
2014-04-23 18:00:57 +04:00
tb - > insert_size [ 0 ] = 0 ;
tb - > zeroes_num = 0 ;
}
2014-08-05 03:51:47 +04:00
static unsigned int balance_leaf_paste_left ( struct tree_balance * tb ,
struct item_head * const ih ,
const char * const body )
2014-04-23 18:00:57 +04:00
{
/* we must shift the part of the appended item */
if ( tb - > item_pos = = tb - > lnum [ 0 ] - 1 & & tb - > lbytes ! = - 1 )
2014-08-05 03:51:47 +04:00
return balance_leaf_paste_left_shift ( tb , ih , body ) ;
2014-04-23 18:00:57 +04:00
else
balance_leaf_paste_left_whole ( tb , ih , body ) ;
2014-08-05 03:51:47 +04:00
return 0 ;
2014-04-23 18:00:48 +04:00
}
2014-04-23 18:00:55 +04:00
/* Shift lnum[0] items from S[0] to the left neighbor L[0] */
2014-08-05 03:51:47 +04:00
static unsigned int balance_leaf_left ( struct tree_balance * tb ,
struct item_head * const ih ,
const char * const body , int flag )
2014-04-23 18:00:55 +04:00
{
if ( tb - > lnum [ 0 ] < = 0 )
2014-08-05 03:51:47 +04:00
return 0 ;
2014-04-23 18:00:55 +04:00
/* new item or it part falls to L[0], shift it too */
if ( tb - > item_pos < tb - > lnum [ 0 ] ) {
BUG_ON ( flag ! = M_INSERT & & flag ! = M_PASTE ) ;
if ( flag = = M_INSERT )
2014-08-05 03:51:47 +04:00
return balance_leaf_insert_left ( tb , ih , body ) ;
2014-04-23 18:00:55 +04:00
else /* M_PASTE */
2014-08-05 03:51:47 +04:00
return balance_leaf_paste_left ( tb , ih , body ) ;
2014-04-23 18:00:55 +04:00
} else
/* new item doesn't fall into L[0] */
leaf_shift_left ( tb , tb - > lnum [ 0 ] , tb - > lbytes ) ;
2014-08-05 03:51:47 +04:00
return 0 ;
2014-04-23 18:00:55 +04:00
}
2014-04-23 18:00:49 +04:00
static void balance_leaf_insert_right ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body )
2014-04-23 18:00:49 +04:00
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
int n = B_NR_ITEMS ( tbS0 ) ;
struct buffer_info bi ;
2014-04-23 18:00:58 +04:00
int ret ;
2014-04-23 18:00:49 +04:00
2014-04-23 18:00:58 +04:00
/* new item or part of it doesn't fall into R[0] */
if ( n - tb - > rnum [ 0 ] > = tb - > item_pos ) {
leaf_shift_right ( tb , tb - > rnum [ 0 ] , tb - > rbytes ) ;
return ;
}
/* new item or its part falls to R[0] */
/* part of new item falls into R[0] */
if ( tb - > item_pos = = n - tb - > rnum [ 0 ] + 1 & & tb - > rbytes ! = - 1 ) {
loff_t old_key_comp , old_len , r_zeroes_number ;
const char * r_body ;
int version , shift ;
loff_t offset ;
2014-04-23 18:00:49 +04:00
2014-04-23 18:00:58 +04:00
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 ]
*/
shift = 0 ;
if ( is_indirect_le_ih ( ih ) )
shift = tb - > tb_sb - > s_blocksize_bits - UNFM_P_SHIFT ;
offset = le_ih_k_offset ( ih ) + ( ( old_len - tb - > rbytes ) < < shift ) ;
set_le_ih_k_offset ( ih , offset ) ;
put_ih_item_len ( ih , tb - > rbytes ) ;
/* Insert part of the item into R[0] */
buffer_info_init_right ( tb , & bi ) ;
if ( ( old_len - tb - > rbytes ) > tb - > zeroes_num ) {
r_zeroes_number = 0 ;
r_body = body + ( old_len - tb - > rbytes ) - tb - > zeroes_num ;
} else {
r_body = body ;
r_zeroes_number = tb - > zeroes_num -
( old_len - tb - > rbytes ) ;
tb - > zeroes_num - = r_zeroes_number ;
}
leaf_insert_into_buf ( & bi , 0 , ih , r_body , r_zeroes_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 = leaf_shift_right ( tb , tb - > rnum [ 0 ] - 1 , tb - > rbytes ) ;
/* Insert new item into R[0] */
buffer_info_init_right ( tb , & bi ) ;
leaf_insert_into_buf ( & bi , tb - > item_pos - n + tb - > rnum [ 0 ] - 1 ,
ih , body , tb - > zeroes_num ) ;
if ( tb - > item_pos - n + tb - > rnum [ 0 ] - 1 = = 0 )
replace_key ( tb , tb - > CFR [ 0 ] , tb - > rkey [ 0 ] , tb - > R [ 0 ] , 0 ) ;
tb - > zeroes_num = tb - > insert_size [ 0 ] = 0 ;
}
2014-04-23 18:00:49 +04:00
}
2014-04-23 18:00:59 +04:00
static void balance_leaf_paste_right_shift_dirent ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body )
2014-04-23 18:00:48 +04:00
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
struct buffer_info bi ;
2014-04-23 18:00:59 +04:00
int entry_count ;
2014-04-23 18:00:48 +04:00
2014-04-23 18:01:00 +04:00
RFALSE ( tb - > zeroes_num ,
2014-04-23 18:00:59 +04:00
" PAP-12145: invalid parameter in case of a directory " ) ;
entry_count = ih_entry_count ( item_head ( tbS0 , tb - > item_pos ) ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
/* new directory entry falls into R[0] */
if ( entry_count - tb - > rbytes < tb - > pos_in_item ) {
int paste_entry_position ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
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 ) ;
2014-02-18 01:21:24 +04:00
2014-04-23 18:00:59 +04:00
/*
* 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 ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
/* Paste given directory entry to directory item */
paste_entry_position = tb - > pos_in_item - entry_count +
tb - > rbytes - 1 ;
buffer_info_init_right ( tb , & bi ) ;
leaf_paste_in_buffer ( & bi , 0 , paste_entry_position ,
tb - > insert_size [ 0 ] , body , tb - > zeroes_num ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
/* paste entry */
leaf_paste_entries ( & bi , 0 , paste_entry_position , 1 ,
( struct reiserfs_de_head * ) body ,
body + DEH_SIZE , tb - > insert_size [ 0 ] ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
/* change delimiting keys */
if ( paste_entry_position = = 0 )
replace_key ( tb , tb - > CFR [ 0 ] , tb - > rkey [ 0 ] , tb - > R [ 0 ] , 0 ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
tb - > insert_size [ 0 ] = 0 ;
tb - > pos_in_item + + ;
} else {
/* new directory entry doesn't fall into R[0] */
leaf_shift_right ( tb , tb - > rnum [ 0 ] , tb - > rbytes ) ;
}
}
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
static void balance_leaf_paste_right_shift ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body )
2014-04-23 18:00:59 +04:00
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
int n_shift , n_rem , r_zeroes_number , version ;
unsigned long temp_rem ;
const char * r_body ;
struct buffer_info bi ;
2014-02-18 01:21:24 +04:00
2014-04-23 18:00:59 +04:00
/* we append to directory item */
if ( is_direntry_le_ih ( item_head ( tbS0 , tb - > item_pos ) ) ) {
balance_leaf_paste_right_shift_dirent ( tb , ih , body ) ;
return ;
}
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
/* regular object */
2014-02-18 01:21:24 +04:00
2014-04-23 18:00:59 +04:00
/*
* Calculate number of bytes which must be shifted
* from appended item
*/
n_shift = tb - > rbytes - tb - > insert_size [ 0 ] ;
if ( n_shift < 0 )
n_shift = 0 ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:01:00 +04:00
RFALSE ( tb - > pos_in_item ! = ih_item_len ( item_head ( tbS0 , tb - > item_pos ) ) ,
2014-04-23 18:00:59 +04:00
" PAP-12155: invalid position to paste. ih_item_len=%d, "
2014-04-23 18:01:00 +04:00
" pos_in_item=%d " , tb - > pos_in_item ,
ih_item_len ( item_head ( tbS0 , tb - > item_pos ) ) ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
leaf_shift_right ( tb , tb - > rnum [ 0 ] , n_shift ) ;
2014-02-18 01:21:24 +04:00
2014-04-23 18:00:59 +04:00
/*
* Calculate number of bytes which must remain in body
* after appending to R [ 0 ]
*/
n_rem = tb - > insert_size [ 0 ] - tb - > rbytes ;
if ( n_rem < 0 )
n_rem = 0 ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
temp_rem = n_rem ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
version = ih_version ( item_head ( tb - > R [ 0 ] , 0 ) ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
if ( is_indirect_le_key ( version , leaf_key ( tb - > R [ 0 ] , 0 ) ) ) {
int shift = tb - > tb_sb - > s_blocksize_bits - UNFM_P_SHIFT ;
temp_rem = n_rem < < shift ;
}
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
add_le_key_k_offset ( version , leaf_key ( tb - > R [ 0 ] , 0 ) , temp_rem ) ;
add_le_key_k_offset ( version , internal_key ( tb - > CFR [ 0 ] , tb - > rkey [ 0 ] ) ,
temp_rem ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
do_balance_mark_internal_dirty ( tb , tb - > CFR [ 0 ] , 0 ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:59 +04:00
/* Append part of body into R[0] */
buffer_info_init_right ( tb , & bi ) ;
if ( n_rem > tb - > zeroes_num ) {
r_zeroes_number = 0 ;
r_body = body + n_rem - tb - > zeroes_num ;
} else {
r_body = body ;
r_zeroes_number = tb - > zeroes_num - n_rem ;
tb - > zeroes_num - = r_zeroes_number ;
}
2005-04-17 02:20:36 +04:00
2014-04-23 18:00:59 +04:00
leaf_paste_in_buffer ( & bi , 0 , n_shift , tb - > insert_size [ 0 ] - n_rem ,
r_body , r_zeroes_number ) ;
if ( is_indirect_le_ih ( item_head ( tb - > R [ 0 ] , 0 ) ) )
set_ih_free_space ( item_head ( tb - > R [ 0 ] , 0 ) , 0 ) ;
tb - > insert_size [ 0 ] = n_rem ;
if ( ! n_rem )
tb - > pos_in_item + + ;
}
static void balance_leaf_paste_right_whole ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body )
2014-04-23 18:00:59 +04:00
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
int n = B_NR_ITEMS ( tbS0 ) ;
struct item_head * pasted ;
struct buffer_info bi ;
buffer_info_init_right ( tb , & bi ) ;
leaf_shift_right ( tb , tb - > rnum [ 0 ] , tb - > rbytes ) ;
/* append item in R[0] */
if ( tb - > pos_in_item > = 0 ) {
buffer_info_init_right ( tb , & bi ) ;
leaf_paste_in_buffer ( & bi , tb - > item_pos - n + tb - > rnum [ 0 ] ,
tb - > pos_in_item , tb - > insert_size [ 0 ] , body ,
tb - > zeroes_num ) ;
}
/* paste new entry, if item is directory item */
pasted = item_head ( tb - > R [ 0 ] , tb - > item_pos - n + tb - > rnum [ 0 ] ) ;
if ( is_direntry_le_ih ( pasted ) & & tb - > pos_in_item > = 0 ) {
leaf_paste_entries ( & bi , tb - > item_pos - n + tb - > rnum [ 0 ] ,
tb - > pos_in_item , 1 ,
( struct reiserfs_de_head * ) body ,
body + DEH_SIZE , tb - > insert_size [ 0 ] ) ;
if ( ! tb - > pos_in_item ) {
RFALSE ( tb - > item_pos - n + tb - > rnum [ 0 ] ,
" PAP-12165: directory item must be first "
" item of node when pasting is in 0th position " ) ;
2014-04-23 18:00:50 +04:00
2014-04-23 18:00:59 +04:00
/* 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 ) ;
tb - > zeroes_num = tb - > insert_size [ 0 ] = 0 ;
}
static void balance_leaf_paste_right ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body )
2014-04-23 18:00:59 +04:00
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
int n = B_NR_ITEMS ( tbS0 ) ;
/* new item doesn't fall into R[0] */
if ( n - tb - > rnum [ 0 ] > tb - > item_pos ) {
leaf_shift_right ( tb , tb - > rnum [ 0 ] , tb - > rbytes ) ;
return ;
}
/* pasted item or part of it falls to R[0] */
if ( tb - > item_pos = = n - tb - > rnum [ 0 ] & & tb - > rbytes ! = - 1 )
/* we must shift the part of the appended item */
balance_leaf_paste_right_shift ( tb , ih , body ) ;
else
/* pasted item in whole falls into R[0] */
balance_leaf_paste_right_whole ( tb , ih , body ) ;
2014-04-23 18:00:50 +04:00
}
2014-04-23 18:00:55 +04:00
/* shift rnum[0] items from S[0] to the right neighbor R[0] */
2014-08-05 03:51:47 +04:00
static void balance_leaf_right ( struct tree_balance * tb ,
struct item_head * const ih ,
const char * const body , int flag )
2014-04-23 18:00:55 +04:00
{
if ( tb - > rnum [ 0 ] < = 0 )
return ;
BUG_ON ( flag ! = M_INSERT & & flag ! = M_PASTE ) ;
if ( flag = = M_INSERT )
balance_leaf_insert_right ( tb , ih , body ) ;
else /* M_PASTE */
balance_leaf_paste_right ( tb , ih , body ) ;
}
2014-04-23 18:00:51 +04:00
static void balance_leaf_new_nodes_insert ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body ,
2014-04-23 18:00:51 +04:00
struct item_head * insert_key ,
struct buffer_head * * insert_ptr ,
int i )
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
int n = B_NR_ITEMS ( tbS0 ) ;
struct buffer_info bi ;
2014-04-23 18:01:00 +04:00
int shift ;
/* new item or it part don't falls into S_new[i] */
if ( n - tb - > snum [ i ] > = tb - > item_pos ) {
leaf_move_items ( LEAF_FROM_S_TO_SNEW , tb ,
tb - > snum [ i ] , tb - > sbytes [ i ] , tb - > S_new [ i ] ) ;
return ;
}
2014-04-23 18:00:51 +04:00
2014-04-23 18:01:00 +04:00
/* new item or it's part falls to first new node S_new[i] */
2014-04-23 18:00:51 +04:00
2014-04-23 18:01:00 +04:00
/* part of new item falls into S_new[i] */
if ( tb - > item_pos = = n - tb - > snum [ i ] + 1 & & tb - > sbytes [ i ] ! = - 1 ) {
int old_key_comp , old_len , r_zeroes_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 , tb - > snum [ i ] - 1 , - 1 ,
tb - > 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 ]
*/
shift = 0 ;
if ( is_indirect_le_ih ( ih ) )
shift = tb - > tb_sb - > s_blocksize_bits - UNFM_P_SHIFT ;
set_le_ih_k_offset ( ih ,
le_ih_k_offset ( ih ) +
( ( old_len - tb - > sbytes [ i ] ) < < shift ) ) ;
put_ih_item_len ( ih , tb - > sbytes [ i ] ) ;
/* Insert part of the item into S_new[i] before 0-th item */
buffer_info_init_bh ( tb , & bi , tb - > S_new [ i ] ) ;
if ( ( old_len - tb - > sbytes [ i ] ) > tb - > zeroes_num ) {
r_zeroes_number = 0 ;
r_body = body + ( old_len - tb - > sbytes [ i ] ) -
tb - > zeroes_num ;
} else {
r_body = body ;
r_zeroes_number = tb - > zeroes_num - ( old_len -
tb - > sbytes [ i ] ) ;
tb - > zeroes_num - = r_zeroes_number ;
}
leaf_insert_into_buf ( & bi , 0 , ih , r_body , r_zeroes_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 - tb - > sbytes [ i ] ) ;
tb - > insert_size [ 0 ] - = tb - > 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 ,
tb - > snum [ i ] - 1 , tb - > sbytes [ i ] , tb - > S_new [ i ] ) ;
/* Insert new item into S_new[i] */
buffer_info_init_bh ( tb , & bi , tb - > S_new [ i ] ) ;
leaf_insert_into_buf ( & bi , tb - > item_pos - n + tb - > snum [ i ] - 1 ,
ih , body , tb - > zeroes_num ) ;
tb - > zeroes_num = tb - > insert_size [ 0 ] = 0 ;
}
2014-04-23 18:00:51 +04:00
}
2014-04-23 18:01:00 +04:00
/* we append to directory item */
static void balance_leaf_new_nodes_paste_dirent ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body ,
2014-04-23 18:01:00 +04:00
struct item_head * insert_key ,
struct buffer_head * * insert_ptr ,
int i )
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
struct item_head * aux_ih = item_head ( tbS0 , tb - > item_pos ) ;
int entry_count = ih_entry_count ( aux_ih ) ;
struct buffer_info bi ;
if ( entry_count - tb - > sbytes [ i ] < tb - > pos_in_item & &
tb - > 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 ( tb - > sbytes [ i ] - 1 > = entry_count ,
" PAP-12220: there are no so much entries (%d), only %d " ,
tb - > 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 , tb - > snum [ i ] ,
tb - > sbytes [ i ] - 1 , tb - > S_new [ i ] ) ;
/*
* Paste given directory entry to
* directory item
*/
buffer_info_init_bh ( tb , & bi , tb - > S_new [ i ] ) ;
leaf_paste_in_buffer ( & bi , 0 , tb - > pos_in_item - entry_count +
tb - > sbytes [ i ] - 1 , tb - > insert_size [ 0 ] ,
body , tb - > zeroes_num ) ;
/* paste new directory entry */
leaf_paste_entries ( & bi , 0 , tb - > pos_in_item - entry_count +
tb - > sbytes [ i ] - 1 , 1 ,
( struct reiserfs_de_head * ) body ,
body + DEH_SIZE , tb - > insert_size [ 0 ] ) ;
tb - > insert_size [ 0 ] = 0 ;
tb - > pos_in_item + + ;
} else {
/* new directory entry doesn't fall into S_new[i] */
leaf_move_items ( LEAF_FROM_S_TO_SNEW , tb , tb - > snum [ i ] ,
tb - > sbytes [ i ] , tb - > S_new [ i ] ) ;
}
}
static void balance_leaf_new_nodes_paste_shift ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body ,
2014-04-23 18:00:52 +04:00
struct item_head * insert_key ,
struct buffer_head * * insert_ptr ,
int i )
2014-04-23 18:01:00 +04:00
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
struct item_head * aux_ih = item_head ( tbS0 , tb - > item_pos ) ;
int n_shift , n_rem , r_zeroes_number , shift ;
const char * r_body ;
struct item_head * tmp ;
struct buffer_info bi ;
RFALSE ( ih , " PAP-12210: ih must be 0 " ) ;
if ( is_direntry_le_ih ( aux_ih ) ) {
balance_leaf_new_nodes_paste_dirent ( tb , ih , body , insert_key ,
insert_ptr , i ) ;
return ;
}
/* regular object */
RFALSE ( tb - > pos_in_item ! = ih_item_len ( item_head ( tbS0 , tb - > 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 = tb - > sbytes [ i ] - tb - > insert_size [ 0 ] ;
if ( n_shift < 0 )
n_shift = 0 ;
leaf_move_items ( LEAF_FROM_S_TO_SNEW , tb , tb - > snum [ i ] , n_shift ,
tb - > S_new [ i ] ) ;
/*
* Calculate number of bytes which must remain in body after
* append to S_new [ i ]
*/
n_rem = tb - > insert_size [ 0 ] - tb - > sbytes [ i ] ;
if ( n_rem < 0 )
n_rem = 0 ;
/* Append part of body into S_new[0] */
buffer_info_init_bh ( tb , & bi , tb - > S_new [ i ] ) ;
if ( n_rem > tb - > zeroes_num ) {
r_zeroes_number = 0 ;
r_body = body + n_rem - tb - > zeroes_num ;
} else {
r_body = body ;
r_zeroes_number = tb - > zeroes_num - n_rem ;
tb - > zeroes_num - = r_zeroes_number ;
}
leaf_paste_in_buffer ( & bi , 0 , n_shift , tb - > insert_size [ 0 ] - n_rem ,
r_body , r_zeroes_number ) ;
tmp = item_head ( tb - > S_new [ i ] , 0 ) ;
shift = 0 ;
if ( is_indirect_le_ih ( tmp ) ) {
set_ih_free_space ( tmp , 0 ) ;
shift = tb - > tb_sb - > s_blocksize_bits - UNFM_P_SHIFT ;
}
add_le_ih_k_offset ( tmp , n_rem < < shift ) ;
tb - > insert_size [ 0 ] = n_rem ;
if ( ! n_rem )
tb - > pos_in_item + + ;
}
static void balance_leaf_new_nodes_paste_whole ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body ,
2014-04-23 18:01:00 +04:00
struct item_head * insert_key ,
struct buffer_head * * insert_ptr ,
int i )
2014-04-23 18:00:52 +04:00
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
int n = B_NR_ITEMS ( tbS0 ) ;
2014-04-23 18:01:00 +04:00
int leaf_mi ;
struct item_head * pasted ;
2014-04-23 18:00:52 +04:00
struct buffer_info bi ;
# ifdef CONFIG_REISERFS_CHECK
2014-04-23 18:01:00 +04:00
struct item_head * ih_check = item_head ( tbS0 , tb - > item_pos ) ;
if ( ! is_direntry_le_ih ( ih_check ) & &
( tb - > pos_in_item ! = ih_item_len ( ih_check ) | |
tb - > insert_size [ 0 ] < = 0 ) )
reiserfs_panic ( tb - > tb_sb ,
" PAP-12235 " ,
" pos_in_item must be equal to ih_item_len " ) ;
# endif
leaf_mi = leaf_move_items ( LEAF_FROM_S_TO_SNEW , tb , tb - > snum [ i ] ,
tb - > sbytes [ i ] , tb - > S_new [ i ] ) ;
RFALSE ( leaf_mi ,
" PAP-12240: unexpected value returned by leaf_move_items (%d) " ,
leaf_mi ) ;
/* paste into item */
buffer_info_init_bh ( tb , & bi , tb - > S_new [ i ] ) ;
leaf_paste_in_buffer ( & bi , tb - > item_pos - n + tb - > snum [ i ] ,
tb - > pos_in_item , tb - > insert_size [ 0 ] ,
body , tb - > zeroes_num ) ;
pasted = item_head ( tb - > S_new [ i ] , tb - > item_pos - n +
tb - > snum [ i ] ) ;
if ( is_direntry_le_ih ( pasted ) )
leaf_paste_entries ( & bi , tb - > item_pos - n + tb - > snum [ i ] ,
tb - > pos_in_item , 1 ,
( struct reiserfs_de_head * ) body ,
body + DEH_SIZE , tb - > insert_size [ 0 ] ) ;
2014-04-23 18:00:52 +04:00
2014-04-23 18:01:00 +04:00
/* if we paste to indirect item update ih_free_space */
if ( is_indirect_le_ih ( pasted ) )
set_ih_free_space ( pasted , 0 ) ;
2014-04-23 18:00:52 +04:00
2014-04-23 18:01:00 +04:00
tb - > zeroes_num = tb - > insert_size [ 0 ] = 0 ;
}
static void balance_leaf_new_nodes_paste ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body ,
2014-04-23 18:01:00 +04:00
struct item_head * insert_key ,
struct buffer_head * * insert_ptr ,
int i )
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
int n = B_NR_ITEMS ( tbS0 ) ;
/* pasted item doesn't fall into S_new[i] */
if ( n - tb - > snum [ i ] > tb - > item_pos ) {
leaf_move_items ( LEAF_FROM_S_TO_SNEW , tb ,
tb - > snum [ i ] , tb - > sbytes [ i ] , tb - > S_new [ i ] ) ;
return ;
}
2014-04-23 18:00:52 +04:00
2014-04-23 18:01:00 +04:00
/* pasted item or part if it falls to S_new[i] */
if ( tb - > item_pos = = n - tb - > snum [ i ] & & tb - > sbytes [ i ] ! = - 1 )
/* we must shift part of the appended item */
balance_leaf_new_nodes_paste_shift ( tb , ih , body , insert_key ,
insert_ptr , i ) ;
else
/* item falls wholly into S_new[i] */
balance_leaf_new_nodes_paste_whole ( tb , ih , body , insert_key ,
insert_ptr , i ) ;
2014-04-23 18:00:52 +04:00
}
2014-04-23 18:00:55 +04:00
/* Fill new nodes that appear in place of S[0] */
static void balance_leaf_new_nodes ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body ,
2014-04-23 18:00:55 +04:00
struct item_head * insert_key ,
struct buffer_head * * insert_ptr ,
int flag )
{
int i ;
for ( i = tb - > blknum [ 0 ] - 2 ; i > = 0 ; i - - ) {
2014-04-23 18:01:00 +04:00
BUG_ON ( flag ! = M_INSERT & & flag ! = M_PASTE ) ;
2014-04-23 18:00:55 +04:00
RFALSE ( ! tb - > snum [ i ] ,
" PAP-12200: snum[%d] == %d. Must be > 0 " , i ,
tb - > snum [ i ] ) ;
/* here we shift from S to S_new nodes */
tb - > S_new [ i ] = get_FEB ( tb ) ;
/* initialized block type and tree level */
set_blkh_level ( B_BLK_HEAD ( tb - > S_new [ i ] ) , DISK_LEAF_NODE_LEVEL ) ;
2014-04-23 18:01:00 +04:00
if ( flag = = M_INSERT )
2014-04-23 18:00:55 +04:00
balance_leaf_new_nodes_insert ( tb , ih , body , insert_key ,
insert_ptr , i ) ;
2014-04-23 18:01:00 +04:00
else /* M_PASTE */
2014-04-23 18:00:55 +04:00
balance_leaf_new_nodes_paste ( tb , ih , body , insert_key ,
insert_ptr , i ) ;
memcpy ( insert_key + i , leaf_key ( tb - > S_new [ i ] , 0 ) , KEY_SIZE ) ;
insert_ptr [ i ] = tb - > S_new [ i ] ;
RFALSE ( ! buffer_journaled ( tb - > S_new [ i ] )
| | buffer_journal_dirty ( tb - > S_new [ i ] )
| | buffer_dirty ( tb - > S_new [ i ] ) ,
" PAP-12247: S_new[%d] : (%b) " ,
2014-06-11 19:29:26 +04:00
i , tb - > S_new [ i ] ) ;
2014-04-23 18:00:55 +04:00
}
}
2014-04-23 18:00:53 +04:00
static void balance_leaf_finish_node_insert ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body )
2014-04-23 18:00:53 +04:00
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
struct buffer_info bi ;
2014-04-23 18:01:01 +04:00
buffer_info_init_tbS0 ( tb , & bi ) ;
leaf_insert_into_buf ( & bi , tb - > item_pos , ih , body , tb - > zeroes_num ) ;
/* If we insert the first key change the delimiting key */
if ( tb - > item_pos = = 0 ) {
if ( tb - > CFL [ 0 ] ) /* can be 0 in reiserfsck */
replace_key ( tb , tb - > CFL [ 0 ] , tb - > lkey [ 0 ] , tbS0 , 0 ) ;
}
}
static void balance_leaf_finish_node_paste_dirent ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body )
2014-04-23 18:01:01 +04:00
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
struct item_head * pasted = item_head ( tbS0 , tb - > item_pos ) ;
struct buffer_info bi ;
if ( tb - > pos_in_item > = 0 & & tb - > pos_in_item < = ih_entry_count ( pasted ) ) {
RFALSE ( ! tb - > insert_size [ 0 ] ,
" PAP-12260: insert_size is 0 already " ) ;
/* prepare space */
buffer_info_init_tbS0 ( tb , & bi ) ;
leaf_paste_in_buffer ( & bi , tb - > item_pos , tb - > pos_in_item ,
tb - > insert_size [ 0 ] , body , tb - > zeroes_num ) ;
/* paste entry */
leaf_paste_entries ( & bi , tb - > item_pos , tb - > pos_in_item , 1 ,
( struct reiserfs_de_head * ) body ,
body + DEH_SIZE , tb - > insert_size [ 0 ] ) ;
if ( ! tb - > item_pos & & ! tb - > 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 ;
}
2014-04-23 18:00:53 +04:00
}
2014-04-23 18:00:54 +04:00
static void balance_leaf_finish_node_paste ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body )
2014-04-23 18:00:54 +04:00
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
struct buffer_info bi ;
2014-04-23 18:01:01 +04:00
struct item_head * pasted = item_head ( tbS0 , tb - > item_pos ) ;
2014-04-23 18:00:54 +04:00
2014-04-23 18:01:01 +04:00
/* when directory, may be new entry already pasted */
if ( is_direntry_le_ih ( pasted ) ) {
balance_leaf_finish_node_paste_dirent ( tb , ih , body ) ;
return ;
}
/* regular object */
if ( tb - > 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 ] ) ;
buffer_info_init_tbS0 ( tb , & bi ) ;
leaf_paste_in_buffer ( & bi , tb - > item_pos ,
tb - > pos_in_item , tb - > insert_size [ 0 ] , body ,
tb - > zeroes_num ) ;
if ( is_indirect_le_ih ( pasted ) )
set_ih_free_space ( pasted , 0 ) ;
tb - > insert_size [ 0 ] = 0 ;
}
# ifdef CONFIG_REISERFS_CHECK
else if ( tb - > insert_size [ 0 ] ) {
print_cur_tb ( " 12285 " ) ;
reiserfs_panic ( tb - > tb_sb , " PAP-12285 " ,
" insert_size must be 0 (%d) " , tb - > insert_size [ 0 ] ) ;
}
# endif
2014-04-23 18:00:54 +04:00
}
2014-04-23 18:00:55 +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
*/
static void balance_leaf_finish_node ( struct tree_balance * tb ,
2014-08-05 03:51:47 +04:00
struct item_head * const ih ,
const char * const body , int flag )
2014-04-23 18:00:55 +04:00
{
/* if we must insert or append into buffer S[0] */
if ( 0 < = tb - > item_pos & & tb - > item_pos < tb - > s0num ) {
if ( flag = = M_INSERT )
balance_leaf_finish_node_insert ( tb , ih , body ) ;
else /* M_PASTE */
balance_leaf_finish_node_paste ( tb , ih , body ) ;
}
}
2014-04-23 18:00:50 +04:00
/**
* balance_leaf - reiserfs tree balancing algorithm
* @ tb : tree balance state
* @ ih : item header of inserted item ( little endian )
* @ body : body of inserted item or bytes to paste
* @ flag : i - insert , d - delete , c - cut , p - paste ( see do_balance )
* passed back :
* @ insert_key : key to insert new nodes
* @ insert_ptr : array of nodes to insert at the next level
*
* 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 .
*/
static int balance_leaf ( struct tree_balance * tb , struct item_head * ih ,
const char * body , int flag ,
struct item_head * insert_key ,
struct buffer_head * * insert_ptr )
{
struct buffer_head * tbS0 = PATH_PLAST_BUFFER ( tb - > tb_path ) ;
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 ) ;
tb - > item_pos = PATH_LAST_POSITION ( tb - > tb_path ) ,
tb - > pos_in_item = tb - > tb_path - > pos_in_item ,
tb - > zeroes_num = 0 ;
if ( flag = = M_INSERT & & ! body )
tb - > zeroes_num = ih_item_len ( ih ) ;
/*
* for indirect item pos_in_item is measured in unformatted node
* pointers . Recalculate to bytes
*/
if ( flag ! = M_INSERT
& & is_indirect_le_ih ( item_head ( tbS0 , tb - > item_pos ) ) )
tb - > pos_in_item * = UNFM_P_SIZE ;
2014-08-05 03:51:47 +04:00
body + = balance_leaf_left ( tb , ih , body , flag ) ;
2014-04-23 18:00:50 +04:00
/* tb->lnum[0] > 0 */
/* Calculate new item position */
tb - > item_pos - = ( tb - > lnum [ 0 ] - ( ( tb - > lbytes ! = - 1 ) ? 1 : 0 ) ) ;
2014-04-23 18:00:55 +04:00
balance_leaf_right ( tb , ih , body , flag ) ;
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 ,
2014-02-18 01:21:24 +04:00
" PAP-12180: blknum can not be %d. It must be <= 3 " , tb - > blknum [ 0 ] ) ;
2005-07-13 07:21:28 +04:00
RFALSE ( tb - > blknum [ 0 ] < 0 ,
2014-02-18 01:21:24 +04:00
" PAP-12185: blknum can not be %d. It must be >= 0 " , tb - > blknum [ 0 ] ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:45 +04:00
/*
* 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
*/
2005-07-13 07:21:28 +04:00
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 " ) ;
2014-04-23 18:00:45 +04:00
/*
* 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
*/
2005-07-13 07:21:28 +04:00
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 " ) ;
2014-04-23 18:00:35 +04:00
copy_key ( internal_key ( tb - > CFL [ 0 ] , tb - > lkey [ 0 ] ) ,
internal_key ( tb - > CFR [ 0 ] , tb - > rkey [ 0 ] ) ) ;
2005-07-13 07:21:28 +04:00
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
2014-04-23 18:00:55 +04:00
balance_leaf_new_nodes ( tb , ih , body , insert_key , insert_ptr , flag ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:55 +04:00
balance_leaf_finish_node ( tb , ih , body , flag ) ;
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
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 ] ) ;
}
2014-04-23 18:00:45 +04:00
# endif
/* Leaf level of the tree is balanced (end of balance_leaf) */
2005-07-13 07:21:28 +04:00
return 0 ;
2014-04-23 18:00:45 +04:00
}
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
2014-04-23 18:00: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 */
2014-04-23 18:00:35 +04:00
memcpy ( internal_key ( dest , n_dest ) , item_head ( src , n_src ) ,
2005-07-13 07:21:28 +04:00
KEY_SIZE ) ;
else
2014-04-23 18:00:35 +04:00
memcpy ( internal_key ( dest , n_dest ) , internal_key ( src , n_src ) ,
2005-07-13 07:21:28 +04:00
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
2014-04-23 18:00:36 +04:00
/*
* double check that buffers that we will modify are unlocked .
* ( fix_nodes should already have prepped all of these for us ) .
*/
2005-07-13 07:21:28 +04:00
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
2014-04-23 18:00:36 +04:00
/*
* 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 .
*/
2005-04-17 02:20:36 +04:00
2014-04-23 18:00:36 +04:00
/*
* 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-04-17 02:20:36 +04:00
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
{
2014-04-23 18:00:36 +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 */
2014-04-23 18:00:36 +04:00
/*
print_tb ( flag , PATH_LAST_POSITION ( tb - > tb_path ) ,
tb - > tb_path - > pos_in_item , tb , " 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
2014-04-23 18:00:36 +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-07-13 07:21:28 +04:00
*/
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
}
2014-04-23 18:00:36 +04:00
/*
* do_balance - balance the tree
*
* @ tb : tree_balance structure
* @ ih : item header of inserted item
* @ body : body of inserted item or bytes to paste
* @ 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 .
*/
void do_balance ( struct tree_balance * tb , struct item_head * ih ,
const char * body , int flag )
{
int child_pos ; /* position of a child node in its parent */
int h ; /* level of the tree being processed */
/*
* 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 item_head insert_key [ 2 ] ;
/* inserted node-ptrs for the next level */
struct buffer_head * insert_ptr [ 2 ] ;
2005-07-13 07:21:28 +04:00
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
2014-04-23 18:00:42 +04:00
atomic_inc ( & fs_generation ( tb - > tb_sb ) ) ;
2005-07-13 07:21:28 +04:00
do_balance_starts ( tb ) ;
2005-04-17 02:20:36 +04:00
2014-04-23 18:00:36 +04:00
/*
* balance_leaf returns 0 except if combining L R and S into
* one node . see balance_internal ( ) for explanation of this
* line of code .
*/
2005-07-13 07:21:28 +04:00
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 + + )
2014-04-23 18:01:02 +04:00
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
}