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
# include <asm/uaccess.h>
# 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 .
*
* 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
* might save cache space and improve software maintenance costs to do so .
*
* 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
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 ) ;
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
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
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 ) ) {
2014-04-23 18:00:36 +04:00
/*
* 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 )
*/
2005-07-13 07:21:28 +04:00
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
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 ) ;
2014-04-23 18:00:36 +04:00
/* L[0] takes part in balancing */
if ( tb - > lnum [ 0 ] ) {
/* 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 ) {
2005-07-13 07:21:28 +04:00
if ( tb - > FR [ 0 ] = = PATH_H_PPARENT ( tb - > tb_path , 0 ) ) {
2014-04-23 18:00:36 +04:00
/*
* all contents of all the 3 buffers
* will be in L [ 0 ]
*/
2005-07-13 07:21:28 +04:00
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 ;
}
2014-04-23 18:00:36 +04:00
/*
* all contents of all the 3 buffers will
* be in R [ 0 ]
*/
2005-07-13 07:21:28 +04:00
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 ;
}
2014-04-23 18:00:36 +04:00
/*
* a part of contents of S [ 0 ] will be in L [ 0 ] and the
* rest part of S [ 0 ] will be in R [ 0 ]
*/
2005-07-13 07:21:28 +04:00
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 ;
}
2014-04-23 18:00:45 +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 )
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 ) ;
struct buffer_info bi ;
int n , i ;
int ret_val ;
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 ) ;
2014-04-23 18:00:46 +04:00
tb - > item_pos = PATH_LAST_POSITION ( tb - > tb_path ) ,
tb - > pos_in_item = tb - > tb_path - > pos_in_item ,
tb - > zeroes_num = 0 ;
2008-03-29 06:07:28 +03:00
if ( flag = = M_INSERT & & ! body )
2014-04-23 18:00:46 +04:00
tb - > zeroes_num = ih_item_len ( ih ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:45 +04:00
/*
* for indirect item pos_in_item is measured in unformatted node
* pointers . Recalculate to bytes
*/
2005-07-13 07:21:28 +04:00
if ( flag ! = M_INSERT
2014-04-23 18:00:46 +04:00
& & is_indirect_le_ih ( item_head ( tbS0 , tb - > item_pos ) ) )
tb - > pos_in_item * = UNFM_P_SIZE ;
2005-07-13 07:21:28 +04:00
if ( tb - > lnum [ 0 ] > 0 ) {
/* Shift lnum[0] items from S[0] to the left neighbor L[0] */
2014-04-23 18:00:46 +04:00
if ( tb - > item_pos < tb - > lnum [ 0 ] ) {
2005-07-13 07:21:28 +04:00
/* 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] */
2014-04-23 18:00:46 +04:00
if ( tb - > item_pos = = tb - > lnum [ 0 ] - 1 & & tb - > lbytes ! = - 1 ) {
2005-07-13 07:21:28 +04:00
/* part of new item falls into L[0] */
int new_item_len ;
int version ;
2014-02-18 01:21:24 +04:00
ret_val = leaf_shift_left ( tb , tb - > lnum [ 0 ] - 1 , - 1 ) ;
2005-07-13 07:21:28 +04:00
/* Calculate item length to insert to S[0] */
2014-02-18 01:21:24 +04:00
new_item_len = ih_item_len ( ih ) - tb - > lbytes ;
2005-07-13 07:21:28 +04:00
/* Calculate and check item length to insert to L[0] */
2014-02-18 01:21:24 +04:00
put_ih_item_len ( ih , ih_item_len ( ih ) - new_item_len ) ;
2005-07-13 07:21:28 +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] */
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 ,
2014-04-23 18:00:46 +04:00
n + tb - > item_pos - ret_val , ih , body ,
tb - > zeroes_num > ih_item_len ( ih ) ? ih_item_len ( ih ) : tb - > zeroes_num ) ;
2005-07-13 07:21:28 +04:00
version = ih_version ( ih ) ;
/* Calculate key component, item length and body to insert into S[0] */
2014-02-18 01:21:24 +04:00
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 ) ) ) ;
2005-07-13 07:21:28 +04:00
put_ih_item_len ( ih , new_item_len ) ;
2014-04-23 18:00:46 +04:00
if ( tb - > lbytes > tb - > zeroes_num ) {
body + = ( tb - > lbytes - tb - > zeroes_num ) ;
tb - > zeroes_num = 0 ;
2005-07-13 07:21:28 +04:00
} else
2014-04-23 18:00:46 +04:00
tb - > zeroes_num - = tb - > lbytes ;
2005-07-13 07:21:28 +04:00
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] */
2014-02-18 01:21:24 +04:00
ret_val = leaf_shift_left ( tb , tb - > lnum [ 0 ] - 1 , tb - > lbytes ) ;
2005-07-13 07:21:28 +04:00
/* Insert new item into L[0] */
2009-03-30 22:02:42 +04:00
buffer_info_init_left ( tb , & bi ) ;
2014-04-23 18:00:46 +04:00
leaf_insert_into_buf ( & bi , n + tb - > item_pos - ret_val , ih , body , tb - > zeroes_num ) ;
2005-07-13 07:21:28 +04:00
tb - > insert_size [ 0 ] = 0 ;
2014-04-23 18:00:46 +04:00
tb - > zeroes_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] */
2014-04-23 18:00:46 +04:00
if ( tb - > item_pos = = tb - > lnum [ 0 ] - 1 & & tb - > lbytes ! = - 1 ) {
2005-07-13 07:21:28 +04:00
/* we must shift the part of the appended item */
2014-04-23 18:00:46 +04:00
if ( is_direntry_le_ih ( item_head ( tbS0 , tb - > item_pos ) ) ) {
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:46 +04:00
RFALSE ( tb - > zeroes_num ,
2005-07-13 07:21:28 +04:00
" PAP-12090: invalid parameter in case of a directory " ) ;
/* directory item */
2014-04-23 18:00:46 +04:00
if ( tb - > lbytes > tb - > pos_in_item ) {
2005-07-13 07:21:28 +04:00
/* new directory entry falls into L[0] */
2014-02-18 01:21:24 +04:00
struct item_head * pasted ;
2014-04-23 18:00:46 +04:00
int l_pos_in_item = tb - > pos_in_item ;
2005-07-13 07:21:28 +04:00
/* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 entries from given directory item */
2014-02-18 01:21:24 +04:00
ret_val = leaf_shift_left ( tb , tb - > lnum [ 0 ] , tb - > lbytes - 1 ) ;
2014-04-23 18:00:46 +04:00
if ( ret_val & & ! tb - > item_pos ) {
2014-04-23 18:00:35 +04:00
pasted = item_head ( tb - > L [ 0 ] , B_NR_ITEMS ( tb - > L [ 0 ] ) - 1 ) ;
l_pos_in_item + = ih_entry_count ( pasted ) - ( tb - > lbytes - 1 ) ;
2005-07-13 07:21:28 +04:00
}
/* Append given directory entry to directory item */
2009-03-30 22:02:42 +04:00
buffer_info_init_left ( tb , & bi ) ;
2014-04-23 18:00:46 +04:00
leaf_paste_in_buffer ( & bi , n + tb - > item_pos - ret_val , l_pos_in_item , tb - > insert_size [ 0 ] , body , tb - > zeroes_num ) ;
2005-07-13 07:21:28 +04:00
/* 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 */
2014-04-23 18:00:46 +04:00
leaf_paste_entries ( & bi , n + tb - > item_pos - ret_val , l_pos_in_item ,
2014-02-18 01:21:24 +04:00
1 , ( struct reiserfs_de_head * ) body ,
body + DEH_SIZE , tb - > insert_size [ 0 ] ) ;
2005-07-13 07:21:28 +04:00
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] */
2014-02-18 01:21:24 +04:00
leaf_shift_left ( tb , tb - > lnum [ 0 ] , tb - > lbytes ) ;
2005-07-13 07:21:28 +04:00
}
/* Calculate new position to append in item body */
2014-04-23 18:00:46 +04:00
tb - > pos_in_item - = tb - > lbytes ;
2005-07-13 07:21:28 +04:00
} else {
/* regular object */
2014-02-18 01:21:24 +04:00
RFALSE ( tb - > lbytes < = 0 , " PAP-12095: there is nothing to shift to L[0]. lbytes=%d " , tb - > lbytes ) ;
2014-04-23 18:00:46 +04:00
RFALSE ( tb - > pos_in_item ! = ih_item_len ( item_head ( tbS0 , tb - > item_pos ) ) ,
2005-07-13 07:21:28 +04:00
" PAP-12100: incorrect position to paste: item_len=%d, pos_in_item=%d " ,
2014-04-23 18:00:46 +04:00
ih_item_len ( item_head ( tbS0 , tb - > item_pos ) ) , tb - > pos_in_item ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:46 +04:00
if ( tb - > lbytes > = tb - > pos_in_item ) {
2005-07-13 07:21:28 +04:00
/* 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] */
2014-04-23 18:00:46 +04:00
l_n = tb - > lbytes - tb - > pos_in_item ;
2005-07-13 07:21:28 +04:00
/* Calculate new insert_size[0] */
2014-02-18 01:21:24 +04:00
tb - > insert_size [ 0 ] - = l_n ;
2005-07-13 07:21:28 +04:00
2014-02-18 01:21:24 +04:00
RFALSE ( tb - > insert_size [ 0 ] < = 0 ,
2005-07-13 07:21:28 +04:00
" PAP-12105: there is nothing to paste into L[0]. insert_size=%d " ,
2014-02-18 01:21:24 +04:00
tb - > insert_size [ 0 ] ) ;
ret_val = leaf_shift_left ( tb , tb - > lnum [ 0 ] , ih_item_len
2014-04-23 18:00:46 +04:00
( item_head ( tbS0 , tb - > item_pos ) ) ) ;
2005-07-13 07:21:28 +04:00
/* 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
2014-04-23 18:00:46 +04:00
( & bi , n + tb - > item_pos - ret_val , ih_item_len
( item_head ( tb - > L [ 0 ] , n + tb - > item_pos - ret_val ) ) ,
2014-02-18 01:21:24 +04:00
l_n , body ,
2014-04-23 18:00:46 +04:00
tb - > zeroes_num > l_n ? l_n : tb - > zeroes_num ) ;
2005-07-13 07:21:28 +04:00
/* 0-th item in S0 can be only of DIRECT type when l_n != 0 */
{
int version ;
2014-02-18 01:21:24 +04:00
int temp_l = l_n ;
2014-04-23 18:00:35 +04:00
RFALSE ( ih_item_len ( item_head ( tbS0 , 0 ) ) ,
2005-07-13 07:21:28 +04:00
" PAP-12106: item length must be 0 " ) ;
2014-04-23 18:00:35 +04:00
RFALSE ( comp_short_le_keys ( leaf_key ( tbS0 , 0 ) , leaf_key
2014-04-23 18:00:46 +04:00
( tb - > L [ 0 ] , n + tb - > item_pos - ret_val ) ) ,
2005-07-13 07:21:28 +04:00
" PAP-12107: items must be of the same file " ) ;
2014-04-23 18:00:46 +04:00
if ( is_indirect_le_ih ( item_head ( tb - > L [ 0 ] , n + tb - > item_pos - ret_val ) ) ) {
2014-02-18 01:21:24 +04:00
temp_l = l_n < < ( tb - > tb_sb - > s_blocksize_bits - UNFM_P_SHIFT ) ;
2005-07-13 07:21:28 +04:00
}
/* update key of first item in S0 */
2014-04-23 18:00:35 +04:00
version = ih_version ( item_head ( tbS0 , 0 ) ) ;
set_le_key_k_offset ( version , leaf_key ( tbS0 , 0 ) ,
le_key_k_offset ( version , leaf_key ( tbS0 , 0 ) ) + temp_l ) ;
2005-07-13 07:21:28 +04:00
/* update left delimiting key */
2014-04-23 18:00:35 +04:00
set_le_key_k_offset ( version , internal_key ( tb - > CFL [ 0 ] , tb - > lkey [ 0 ] ) ,
le_key_k_offset ( version , internal_key ( tb - > CFL [ 0 ] , tb - > lkey [ 0 ] ) ) + temp_l ) ;
2005-07-13 07:21:28 +04:00
}
/* Calculate new body, position in item and insert_size[0] */
2014-04-23 18:00:46 +04:00
if ( l_n > tb - > zeroes_num ) {
body + = ( l_n - tb - > zeroes_num ) ;
tb - > zeroes_num = 0 ;
2005-07-13 07:21:28 +04:00
} else
2014-04-23 18:00:46 +04:00
tb - > zeroes_num - = l_n ;
tb - > pos_in_item = 0 ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:35 +04:00
RFALSE ( comp_short_le_keys ( leaf_key ( tbS0 , 0 ) , 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 ( internal_key ( tb - > CFL [ 0 ] , tb - > lkey [ 0 ] ) , tbS0 - > b_size ) ,
2005-07-13 07:21:28 +04:00
" 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] */
2014-04-23 18:00:46 +04:00
tb - > pos_in_item - = tb - > lbytes ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:46 +04:00
RFALSE ( tb - > pos_in_item < = 0 , " PAP-12125: no place for paste. pos_in_item=%d " , tb - > pos_in_item ) ;
2005-07-13 07:21:28 +04:00
/* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
2014-02-18 01:21:24 +04:00
leaf_shift_left ( tb , tb - > lnum [ 0 ] , tb - > lbytes ) ;
2005-07-13 07:21:28 +04:00
}
}
} else { /* appended item will be in L[0] in whole */
struct item_head * pasted ;
2014-04-23 18:00:46 +04:00
if ( ! tb - > item_pos & & op_is_left_mergeable ( leaf_key ( tbS0 , 0 ) , tbS0 - > b_size ) ) { /* if we paste into first item of S[0] and it is left mergable */
2005-07-13 07:21:28 +04:00
/* then increment pos_in_item by the size of the last item in L[0] */
2014-04-23 18:00:35 +04:00
pasted = item_head ( tb - > L [ 0 ] , n - 1 ) ;
2005-07-13 07:21:28 +04:00
if ( is_direntry_le_ih ( pasted ) )
2014-04-23 18:00:46 +04:00
tb - > pos_in_item + = ih_entry_count ( pasted ) ;
2005-07-13 07:21:28 +04:00
else
2014-04-23 18:00:46 +04:00
tb - > pos_in_item + = ih_item_len ( pasted ) ;
2005-07-13 07:21:28 +04:00
}
/* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
2014-02-18 01:21:24 +04:00
ret_val = leaf_shift_left ( tb , tb - > lnum [ 0 ] , tb - > lbytes ) ;
2005-07-13 07:21:28 +04:00
/* Append to body of item in L[0] */
2009-03-30 22:02:42 +04:00
buffer_info_init_left ( tb , & bi ) ;
2014-04-23 18:00:46 +04:00
leaf_paste_in_buffer ( & bi , n + tb - > item_pos - ret_val ,
tb - > pos_in_item ,
2005-07-13 07:21:28 +04:00
tb - > insert_size [ 0 ] ,
2014-04-23 18:00:46 +04:00
body , tb - > zeroes_num ) ;
2005-07-13 07:21:28 +04:00
/* if appended item is directory, paste entry */
2014-04-23 18:00:46 +04:00
pasted = item_head ( tb - > L [ 0 ] , n + tb - > item_pos - ret_val ) ;
2005-07-13 07:21:28 +04:00
if ( is_direntry_le_ih ( pasted ) )
2014-04-23 18:00:46 +04:00
leaf_paste_entries ( & bi , n + tb - > item_pos - ret_val ,
tb - > pos_in_item , 1 ,
2014-02-18 01:21:24 +04:00
( struct reiserfs_de_head * ) body ,
body + DEH_SIZE ,
tb - > insert_size [ 0 ] ) ;
2005-07-13 07:21:28 +04:00
/* 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 ;
2014-04-23 18:00:46 +04:00
tb - > zeroes_num = 0 ;
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-12130 " ,
" lnum > 0: unexpected mode: "
" %s(%d) " ,
2014-02-18 01:21:24 +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 */
2014-04-23 18:00:46 +04:00
tb - > item_pos - = ( tb - > lnum [ 0 ] - ( ( tb - > lbytes ! = - 1 ) ? 1 : 0 ) ) ;
2005-07-13 07:21:28 +04:00
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 */
2014-04-23 18:00:46 +04:00
if ( n - tb - > rnum [ 0 ] < tb - > item_pos ) { /* new item or its part falls to R[0] */
if ( tb - > 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_zeroes_number ;
2005-07-13 07:21:28 +04:00
const char * r_body ;
int version ;
loff_t offset ;
2014-02-18 01:21:24 +04:00
leaf_shift_right ( tb , tb - > rnum [ 0 ] - 1 , - 1 ) ;
2005-07-13 07:21:28 +04:00
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] */
2014-02-18 01:21:24 +04:00
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 ) ) ;
2005-07-13 07:21:28 +04:00
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 ) ;
2014-04-23 18:00:46 +04:00
if ( ( old_len - tb - > rbytes ) > tb - > zeroes_num ) {
r_zeroes_number = 0 ;
r_body = body + ( old_len - tb - > rbytes ) - tb - > zeroes_num ;
2005-07-13 07:21:28 +04:00
} else {
r_body = body ;
2014-04-23 18:00:46 +04:00
r_zeroes_number = tb - > zeroes_num - ( old_len - tb - > rbytes ) ;
tb - > zeroes_num - = r_zeroes_number ;
2005-07-13 07:21:28 +04:00
}
leaf_insert_into_buf ( & bi , 0 , ih , r_body ,
2014-04-23 18:00:46 +04:00
r_zeroes_number ) ;
2005-07-13 07:21:28 +04:00
/* 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 ) ;
2014-02-18 01:21:24 +04:00
put_ih_item_len ( ih , old_len - tb - > rbytes ) ;
2005-07-13 07:21:28 +04:00
tb - > insert_size [ 0 ] - = tb - > rbytes ;
} else { /* whole new item falls into R[0] */
/* Shift rnum[0]-1 items to R[0] */
2014-02-18 01:21:24 +04:00
ret_val = leaf_shift_right ( tb , tb - > rnum [ 0 ] - 1 , tb - > rbytes ) ;
2005-07-13 07:21:28 +04:00
/* Insert new item into R[0] */
2009-03-30 22:02:42 +04:00
buffer_info_init_right ( tb , & bi ) ;
2014-04-23 18:00:46 +04:00
leaf_insert_into_buf ( & bi , tb - > item_pos - n + tb - > rnum [ 0 ] - 1 ,
ih , body , tb - > zeroes_num ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:46 +04:00
if ( tb - > item_pos - n + tb - > rnum [ 0 ] - 1 = = 0 ) {
2005-07-13 07:21:28 +04:00
replace_key ( tb , tb - > CFR [ 0 ] ,
tb - > rkey [ 0 ] ,
tb - > R [ 0 ] , 0 ) ;
}
2014-04-23 18:00:46 +04:00
tb - > zeroes_num = tb - > insert_size [ 0 ] = 0 ;
2005-07-13 07:21:28 +04:00
}
} 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 */
2014-04-23 18:00:46 +04:00
if ( n - tb - > rnum [ 0 ] < = tb - > item_pos ) { /* 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 */
if ( is_direntry_le_ih ( item_head ( tbS0 , tb - > item_pos ) ) ) { /* we append to directory item */
2005-07-13 07:21:28 +04:00
int entry_count ;
2014-04-23 18:00:46 +04:00
RFALSE ( tb - > zeroes_num ,
2005-07-13 07:21:28 +04:00
" PAP-12145: invalid parameter in case of a directory " ) ;
2014-04-23 18:00:35 +04:00
entry_count = ih_entry_count ( item_head
2014-04-23 18:00:46 +04:00
( tbS0 , tb - > item_pos ) ) ;
2005-07-13 07:21:28 +04:00
if ( entry_count - tb - > rbytes <
2014-04-23 18:00:46 +04:00
tb - > pos_in_item )
2005-07-13 07:21:28 +04:00
/* new directory entry falls into R[0] */
{
int paste_entry_position ;
2014-02-18 01:21:24 +04:00
RFALSE ( tb - > rbytes - 1 > = entry_count | | ! tb - > insert_size [ 0 ] ,
2005-07-13 07:21:28 +04:00
" PAP-12150: no enough of entries to shift to R[0]: rbytes=%d, entry_count=%d " ,
2014-02-18 01:21:24 +04:00
tb - > rbytes , entry_count ) ;
2005-07-13 07:21:28 +04:00
/* Shift rnum[0]-1 items in whole. Shift rbytes-1 directory entries from directory item number rnum[0] */
2014-02-18 01:21:24 +04:00
leaf_shift_right ( tb , tb - > rnum [ 0 ] , tb - > rbytes - 1 ) ;
2005-07-13 07:21:28 +04:00
/* Paste given directory entry to directory item */
2014-04-23 18:00:46 +04:00
paste_entry_position = tb - > pos_in_item - entry_count + tb - > rbytes - 1 ;
2009-03-30 22:02:42 +04:00
buffer_info_init_right ( tb , & bi ) ;
2014-04-23 18:00:46 +04:00
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
/* paste entry */
2014-02-18 01:21:24 +04:00
leaf_paste_entries ( & bi , 0 , paste_entry_position , 1 ,
( struct reiserfs_de_head * ) body ,
body + DEH_SIZE , tb - > insert_size [ 0 ] ) ;
if ( paste_entry_position = = 0 ) {
2005-07-13 07:21:28 +04:00
/* change delimiting keys */
2014-02-18 01:21:24 +04:00
replace_key ( tb , tb - > CFR [ 0 ] , tb - > rkey [ 0 ] , tb - > R [ 0 ] , 0 ) ;
2005-07-13 07:21:28 +04:00
}
tb - > insert_size [ 0 ] = 0 ;
2014-04-23 18:00:46 +04:00
tb - > pos_in_item + + ;
2005-07-13 07:21:28 +04:00
} else { /* new directory entry doesn't fall into R[0] */
2014-02-18 01:21:24 +04:00
leaf_shift_right ( tb , tb - > rnum [ 0 ] , tb - > rbytes ) ;
2005-07-13 07:21:28 +04:00
}
} else { /* regular object */
2014-04-23 18:00:46 +04:00
int n_shift , n_rem , r_zeroes_number ;
2005-07-13 07:21:28 +04:00
const char * r_body ;
/* Calculate number of bytes which must be shifted from appended item */
2014-02-18 01:21:24 +04:00
if ( ( n_shift = tb - > rbytes - tb - > insert_size [ 0 ] ) < 0 )
2005-07-13 07:21:28 +04:00
n_shift = 0 ;
2014-04-23 18:00:46 +04:00
RFALSE ( tb - > pos_in_item ! = ih_item_len
( item_head ( tbS0 , tb - > item_pos ) ) ,
2005-07-13 07:21:28 +04:00
" PAP-12155: invalid position to paste. ih_item_len=%d, pos_in_item=%d " ,
2014-04-23 18:00:46 +04:00
tb - > pos_in_item , ih_item_len
( item_head ( tbS0 , tb - > item_pos ) ) ) ;
2014-02-18 01:21:24 +04:00
leaf_shift_right ( tb , tb - > rnum [ 0 ] , n_shift ) ;
2005-07-13 07:21:28 +04:00
/* Calculate number of bytes which must remain in body after appending to R[0] */
2014-02-18 01:21:24 +04:00
if ( ( n_rem = tb - > insert_size [ 0 ] - tb - > rbytes ) < 0 )
2005-07-13 07:21:28 +04:00
n_rem = 0 ;
{
int version ;
2014-02-18 01:21:24 +04:00
unsigned long temp_rem = n_rem ;
2014-04-23 18:00:35 +04:00
version = ih_version ( item_head ( tb - > R [ 0 ] , 0 ) ) ;
if ( is_indirect_le_key ( version , leaf_key ( tb - > R [ 0 ] , 0 ) ) ) {
2014-02-18 01:21:24 +04:00
temp_rem = n_rem < < ( tb - > tb_sb - > s_blocksize_bits - UNFM_P_SHIFT ) ;
2005-07-13 07:21:28 +04:00
}
2014-04-23 18:00:35 +04:00
set_le_key_k_offset ( version , leaf_key ( tb - > R [ 0 ] , 0 ) ,
le_key_k_offset ( version , leaf_key ( tb - > R [ 0 ] , 0 ) ) + temp_rem ) ;
set_le_key_k_offset ( version , internal_key ( tb - > CFR [ 0 ] , tb - > rkey [ 0 ] ) ,
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:35 +04:00
/* k_offset (leaf_key(tb->R[0],0)) += n_rem;
k_offset ( internal_key ( tb - > CFR [ 0 ] , tb - > rkey [ 0 ] ) ) + = n_rem ; */
2014-02-18 01:21:24 +04:00
do_balance_mark_internal_dirty ( tb , tb - > CFR [ 0 ] , 0 ) ;
2005-07-13 07:21:28 +04:00
/* Append part of body into R[0] */
2009-03-30 22:02:42 +04:00
buffer_info_init_right ( tb , & bi ) ;
2014-04-23 18:00:46 +04:00
if ( n_rem > tb - > zeroes_num ) {
r_zeroes_number = 0 ;
r_body = body + n_rem - tb - > zeroes_num ;
2005-07-13 07:21:28 +04:00
} else {
r_body = body ;
2014-04-23 18:00:46 +04:00
r_zeroes_number = tb - > zeroes_num - n_rem ;
tb - > zeroes_num - = r_zeroes_number ;
2005-07-13 07:21:28 +04:00
}
2014-02-18 01:21:24 +04:00
leaf_paste_in_buffer ( & bi , 0 , n_shift ,
tb - > insert_size [ 0 ] - n_rem ,
2014-04-23 18:00:46 +04:00
r_body , r_zeroes_number ) ;
2014-02-18 01:21:24 +04:00
2014-04-23 18:00:35 +04:00
if ( is_indirect_le_ih ( item_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
2014-04-23 18:00:35 +04:00
set_ih_free_space ( item_head ( tb - > R [ 0 ] , 0 ) , 0 ) ;
2005-07-13 07:21:28 +04:00
}
tb - > insert_size [ 0 ] = n_rem ;
if ( ! n_rem )
2014-04-23 18:00:46 +04:00
tb - > pos_in_item + + ;
2005-07-13 07:21:28 +04:00
}
} else { /* pasted item in whole falls into R[0] */
struct item_head * pasted ;
2014-02-18 01:21:24 +04:00
ret_val = leaf_shift_right ( tb , tb - > rnum [ 0 ] , tb - > rbytes ) ;
2005-07-13 07:21:28 +04:00
/* append item in R[0] */
2014-04-23 18:00:46 +04:00
if ( tb - > pos_in_item > = 0 ) {
2009-03-30 22:02:42 +04:00
buffer_info_init_right ( tb , & bi ) ;
2014-04-23 18:00:46 +04:00
leaf_paste_in_buffer ( & bi , tb - > item_pos - n + tb - > rnum [ 0 ] , tb - > pos_in_item ,
tb - > insert_size [ 0 ] , body , tb - > zeroes_num ) ;
2005-07-13 07:21:28 +04:00
}
/* paste new entry, if item is directory item */
2014-04-23 18:00:46 +04:00
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 ,
2014-02-18 01:21:24 +04:00
( struct reiserfs_de_head * ) body ,
body + DEH_SIZE , tb - > insert_size [ 0 ] ) ;
2014-04-23 18:00:46 +04:00
if ( ! tb - > pos_in_item ) {
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:46 +04:00
RFALSE ( tb - > item_pos - n + tb - > rnum [ 0 ] ,
2005-07-13 07:21:28 +04:00
" PAP-12165: directory item must be first item of node when pasting is in 0th position " ) ;
/* update delimiting keys */
2014-02-18 01:21:24 +04:00
replace_key ( tb , tb - > CFR [ 0 ] , tb - > rkey [ 0 ] , tb - > R [ 0 ] , 0 ) ;
2005-07-13 07:21:28 +04:00
}
}
if ( is_indirect_le_ih ( pasted ) )
set_ih_free_space ( pasted , 0 ) ;
2014-04-23 18:00:46 +04:00
tb - > zeroes_num = tb - > insert_size [ 0 ] = 0 ;
2005-07-13 07:21:28 +04:00
}
} 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) " ,
2014-02-18 01:21:24 +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 ,
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
2005-07-13 07:21:28 +04:00
/* Fill new nodes that appear in place of S[0] */
for ( i = tb - > blknum [ 0 ] - 2 ; i > = 0 ; i - - ) {
2014-04-23 18:00:46 +04:00
RFALSE ( ! tb - > snum [ i ] ,
" PAP-12200: snum[%d] == %d. Must be > 0 " , i ,
tb - > snum [ i ] ) ;
2005-07-13 07:21:28 +04:00
/* here we shift from S to S_new nodes */
2014-04-23 18:00:46 +04:00
tb - > S_new [ i ] = get_FEB ( tb ) ;
2005-07-13 07:21:28 +04:00
/* initialized block type and tree level */
2014-04-23 18:00:46 +04:00
set_blkh_level ( B_BLK_HEAD ( tb - > S_new [ i ] ) , DISK_LEAF_NODE_LEVEL ) ;
2005-07-13 07:21:28 +04:00
n = B_NR_ITEMS ( tbS0 ) ;
switch ( flag ) {
case M_INSERT : /* insert item */
2014-04-23 18:00:46 +04:00
if ( n - tb - > snum [ i ] < tb - > item_pos ) { /* new item or it's part falls to first new node S_new[i] */
if ( tb - > item_pos = = n - tb - > snum [ i ] + 1 & & tb - > sbytes [ i ] ! = - 1 ) { /* part of new item falls into S_new[i] */
int old_key_comp , old_len , r_zeroes_number ;
2005-07-13 07:21:28 +04:00
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 ,
2014-04-23 18:00:46 +04:00
tb - > snum [ i ] - 1 , - 1 ,
tb - > S_new [ i ] ) ;
2005-07-13 07:21:28 +04:00
/* 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] */
2014-02-18 01:21:24 +04:00
set_le_ih_k_offset ( ih , le_ih_k_offset ( ih ) +
2014-04-23 18:00:46 +04:00
( ( old_len - tb - > sbytes [ i ] ) < < ( is_indirect_le_ih ( ih ) ? tb - > tb_sb - > s_blocksize_bits - UNFM_P_SHIFT : 0 ) ) ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:46 +04:00
put_ih_item_len ( ih , tb - > sbytes [ i ] ) ;
2005-07-13 07:21:28 +04:00
/* Insert part of the item into S_new[i] before 0-th item */
2014-04-23 18:00:46 +04:00
buffer_info_init_bh ( tb , & bi , tb - > S_new [ i ] ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:46 +04:00
if ( ( old_len - tb - > sbytes [ i ] ) > tb - > zeroes_num ) {
r_zeroes_number = 0 ;
r_body = body + ( old_len - tb - > sbytes [ i ] ) - tb - > zeroes_num ;
2005-07-13 07:21:28 +04:00
} else {
r_body = body ;
2014-04-23 18:00:46 +04:00
r_zeroes_number = tb - > zeroes_num - ( old_len - tb - > sbytes [ i ] ) ;
tb - > zeroes_num - = r_zeroes_number ;
2005-07-13 07:21:28 +04:00
}
2014-04-23 18:00:46 +04:00
leaf_insert_into_buf ( & bi , 0 , ih , r_body , r_zeroes_number ) ;
2005-07-13 07:21:28 +04:00
/* Calculate key component and item length to insert into S[i] */
set_le_ih_k_offset ( ih , old_key_comp ) ;
2014-04-23 18:00:46 +04:00
put_ih_item_len ( ih , old_len - tb - > sbytes [ i ] ) ;
tb - > insert_size [ 0 ] - = tb - > sbytes [ i ] ;
2005-07-13 07:21:28 +04:00
} 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 ,
2014-04-23 18:00:46 +04:00
tb - > snum [ i ] - 1 , tb - > sbytes [ i ] , tb - > S_new [ i ] ) ;
2005-07-13 07:21:28 +04:00
/* Insert new item into S_new[i] */
2014-04-23 18:00:46 +04:00
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 ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:46 +04:00
tb - > zeroes_num = tb - > insert_size [ 0 ] = 0 ;
2005-07-13 07:21:28 +04:00
}
}
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 ,
2014-04-23 18:00:46 +04:00
tb - > snum [ i ] , tb - > sbytes [ i ] , tb - > 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 */
2014-04-23 18:00:46 +04:00
if ( n - tb - > snum [ i ] < = tb - > item_pos ) { /* 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 */
2005-07-13 07:21:28 +04:00
struct item_head * aux_ih ;
RFALSE ( ih , " PAP-12210: ih must be 0 " ) ;
2014-04-23 18:00:46 +04:00
aux_ih = item_head ( tbS0 , tb - > item_pos ) ;
2009-06-18 03:26:29 +04:00
if ( is_direntry_le_ih ( aux_ih ) ) {
2005-07-13 07:21:28 +04:00
/* we append to directory item */
int entry_count ;
2014-02-18 01:21:24 +04:00
entry_count = ih_entry_count ( aux_ih ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:46 +04:00
if ( entry_count - tb - > sbytes [ i ] < tb - > pos_in_item & & tb - > pos_in_item < = entry_count ) {
2005-07-13 07:21:28 +04:00
/* new directory entry falls into S_new[i] */
2014-02-18 01:21:24 +04:00
RFALSE ( ! tb - > insert_size [ 0 ] , " PAP-12215: insert_size is already 0 " ) ;
2014-04-23 18:00:46 +04:00
RFALSE ( tb - > sbytes [ i ] - 1 > = entry_count ,
2005-07-13 07:21:28 +04:00
" PAP-12220: there are no so much entries (%d), only %d " ,
2014-04-23 18:00:46 +04:00
tb - > sbytes [ i ] - 1 , entry_count ) ;
2005-07-13 07:21:28 +04:00
/* Shift snum[i]-1 items in whole. Shift sbytes[i] directory entries from directory item number snum[i] */
2014-04-23 18:00:46 +04:00
leaf_move_items ( LEAF_FROM_S_TO_SNEW , tb , tb - > snum [ i ] , tb - > sbytes [ i ] - 1 , tb - > S_new [ i ] ) ;
2005-07-13 07:21:28 +04:00
/* Paste given directory entry to directory item */
2014-04-23 18:00:46 +04:00
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 ) ;
2005-07-13 07:21:28 +04:00
/* paste new directory entry */
2014-04-23 18:00:46 +04:00
leaf_paste_entries ( & bi , 0 , tb - > pos_in_item - entry_count + tb - > sbytes [ i ] - 1 , 1 ,
2014-02-18 01:21:24 +04:00
( struct reiserfs_de_head * ) body ,
body + DEH_SIZE , tb - > insert_size [ 0 ] ) ;
2005-07-13 07:21:28 +04:00
tb - > insert_size [ 0 ] = 0 ;
2014-04-23 18:00:46 +04:00
tb - > pos_in_item + + ;
2005-07-13 07:21:28 +04:00
} else { /* new directory entry doesn't fall into S_new[i] */
2014-04-23 18:00:46 +04:00
leaf_move_items ( LEAF_FROM_S_TO_SNEW , tb , tb - > snum [ i ] , tb - > sbytes [ i ] , tb - > S_new [ i ] ) ;
2005-07-13 07:21:28 +04:00
}
} else { /* regular object */
2014-04-23 18:00:46 +04:00
int n_shift , n_rem , r_zeroes_number ;
2005-07-13 07:21:28 +04:00
const char * r_body ;
2014-04-23 18:00:46 +04:00
RFALSE ( tb - > pos_in_item ! = ih_item_len ( item_head ( tbS0 , tb - > item_pos ) ) | | tb - > insert_size [ 0 ] < = 0 ,
2005-07-13 07:21:28 +04:00
" PAP-12225: item too short or insert_size <= 0 " ) ;
/* Calculate number of bytes which must be shifted from appended item */
2014-04-23 18:00:46 +04:00
n_shift = tb - > sbytes [ i ] - tb - > insert_size [ 0 ] ;
2005-07-13 07:21:28 +04:00
if ( n_shift < 0 )
n_shift = 0 ;
2014-04-23 18:00:46 +04:00
leaf_move_items ( LEAF_FROM_S_TO_SNEW , tb , tb - > snum [ i ] , n_shift , tb - > S_new [ i ] ) ;
2005-07-13 07:21:28 +04:00
/* Calculate number of bytes which must remain in body after append to S_new[i] */
2014-04-23 18:00:46 +04:00
n_rem = tb - > insert_size [ 0 ] - tb - > sbytes [ i ] ;
2005-07-13 07:21:28 +04:00
if ( n_rem < 0 )
n_rem = 0 ;
/* Append part of body into S_new[0] */
2014-04-23 18:00:46 +04:00
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 ;
2005-07-13 07:21:28 +04:00
} else {
r_body = body ;
2014-04-23 18:00:46 +04:00
r_zeroes_number = tb - > zeroes_num - n_rem ;
tb - > zeroes_num - = r_zeroes_number ;
2005-07-13 07:21:28 +04:00
}
2014-02-18 01:21:24 +04:00
leaf_paste_in_buffer ( & bi , 0 , n_shift ,
tb - > insert_size [ 0 ] - n_rem ,
2014-04-23 18:00:46 +04:00
r_body , r_zeroes_number ) ;
2005-07-13 07:21:28 +04:00
{
struct item_head * tmp ;
2014-04-23 18:00:46 +04:00
tmp = item_head ( tb - > S_new [ i ] , 0 ) ;
2005-07-13 07:21:28 +04:00
if ( is_indirect_le_ih
( tmp ) ) {
2014-02-18 01:21:24 +04:00
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 ) ) ) ;
2005-07-13 07:21:28 +04:00
} else {
2014-02-18 01:21:24 +04:00
set_le_ih_k_offset ( tmp , le_ih_k_offset ( tmp ) + n_rem ) ;
2005-07-13 07:21:28 +04:00
}
}
tb - > insert_size [ 0 ] = n_rem ;
if ( ! n_rem )
2014-04-23 18:00:46 +04:00
tb - > pos_in_item + + ;
2005-07-13 07:21:28 +04:00
}
} 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
2014-04-23 18:00:46 +04:00
struct item_head * ih_check = item_head ( tbS0 , tb - > item_pos ) ;
2005-07-13 07:21:28 +04:00
2008-04-28 13:16:21 +04:00
if ( ! is_direntry_le_ih ( ih_check )
2014-04-23 18:00:46 +04:00
& & ( tb - > 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 */
2014-02-18 01:21:24 +04:00
leaf_mi = leaf_move_items ( LEAF_FROM_S_TO_SNEW ,
2014-04-23 18:00:46 +04:00
tb , tb - > snum [ i ] ,
tb - > sbytes [ i ] ,
tb - > S_new [ i ] ) ;
2005-07-13 07:21:28 +04:00
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 */
2014-04-23 18:00:46 +04:00
buffer_info_init_bh ( tb , & bi , tb - > S_new [ i ] ) ;
2005-07-13 07:21:28 +04:00
leaf_paste_in_buffer ( & bi ,
2014-04-23 18:00:46 +04:00
tb - > item_pos - n + tb - > snum [ i ] ,
tb - > pos_in_item ,
2005-07-13 07:21:28 +04:00
tb - > insert_size [ 0 ] ,
2014-04-23 18:00:46 +04:00
body , tb - > zeroes_num ) ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:46 +04:00
pasted = item_head ( tb - > S_new [ i ] , tb - > item_pos - n + tb - > snum [ i ] ) ;
2005-07-13 07:21:28 +04:00
if ( is_direntry_le_ih ( pasted ) ) {
2009-03-30 22:02:18 +04:00
leaf_paste_entries ( & bi ,
2014-04-23 18:00:46 +04:00
tb - > item_pos - n + tb - > snum [ i ] ,
tb - > pos_in_item , 1 ,
2014-02-18 01:21:24 +04:00
( struct reiserfs_de_head * ) body ,
body + DEH_SIZE ,
tb - > insert_size [ 0 ]
2005-07-13 07:21:28 +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:46 +04:00
tb - > zeroes_num = tb - > insert_size [ 0 ] = 0 ;
2005-07-13 07:21:28 +04:00
}
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 ,
2014-04-23 18:00:46 +04:00
tb - > snum [ i ] , tb - > sbytes [ i ] , tb - > S_new [ i ] ) ;
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-12245 " ,
" blknum > 2: unexpected mode: %s(%d) " ,
2014-02-18 01:21:24 +04:00
( flag = = M_DELETE ) ? " DELETE " : ( ( flag = = M_CUT ) ? " CUT " : " UNKNOWN " ) , flag ) ;
2005-04-17 02:20:36 +04:00
}
2014-04-23 18:00:46 +04:00
memcpy ( insert_key + i , leaf_key ( tb - > S_new [ i ] , 0 ) , KEY_SIZE ) ;
insert_ptr [ i ] = tb - > S_new [ i ] ;
2005-07-13 07:21:28 +04:00
2014-04-23 18:00:46 +04:00
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) " ,
i , tb - > 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 */
2014-04-23 18:00:46 +04:00
if ( 0 < = tb - > item_pos & & tb - > item_pos < tb - > s0num ) { /* if we must insert or append into buffer S[0] */
2005-07-13 07:21:28 +04:00
switch ( flag ) {
case M_INSERT : /* insert item into S[0] */
2009-03-30 22:02:42 +04:00
buffer_info_init_tbS0 ( tb , & bi ) ;
2014-04-23 18:00:46 +04:00
leaf_insert_into_buf ( & bi , tb - > item_pos , ih ,
body , tb - > zeroes_num ) ;
2005-07-13 07:21:28 +04:00
/* If we insert the first key change the delimiting key */
2014-04-23 18:00:46 +04:00
if ( tb - > item_pos = = 0 ) {
2005-07-13 07:21:28 +04:00
if ( tb - > CFL [ 0 ] ) /* can be 0 in reiserfsck */
2014-02-18 01:21:24 +04:00
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 ;
2014-04-23 18:00:46 +04:00
pasted = item_head ( tbS0 , tb - > item_pos ) ;
2005-07-13 07:21:28 +04:00
/* when directory, may be new entry already pasted */
if ( is_direntry_le_ih ( pasted ) ) {
2014-04-23 18:00:46 +04:00
if ( tb - > pos_in_item > = 0 & & tb - > pos_in_item < = ih_entry_count ( pasted ) ) {
2005-07-13 07:21:28 +04:00
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 ) ;
2014-04-23 18:00:46 +04:00
leaf_paste_in_buffer ( & bi , tb - > item_pos , tb - > pos_in_item ,
2014-02-18 01:21:24 +04:00
tb - > insert_size [ 0 ] , body ,
2014-04-23 18:00:46 +04:00
tb - > zeroes_num ) ;
2005-07-13 07:21:28 +04:00
/* paste entry */
2014-04-23 18:00:46 +04:00
leaf_paste_entries ( & bi , tb - > item_pos , tb - > pos_in_item , 1 ,
2014-02-18 01:21:24 +04:00
( struct reiserfs_de_head * ) body ,
body + DEH_SIZE ,
tb - > insert_size [ 0 ] ) ;
2014-04-23 18:00:46 +04:00
if ( ! tb - > item_pos & & ! tb - > pos_in_item ) {
2014-02-18 01:21:24 +04:00
RFALSE ( ! tb - > CFL [ 0 ] | | ! tb - > L [ 0 ] ,
2005-07-13 07:21:28 +04:00
" PAP-12270: CFL[0]/L[0] must be specified " ) ;
2014-02-18 01:21:24 +04:00
if ( tb - > CFL [ 0 ] )
replace_key ( tb , tb - > CFL [ 0 ] , tb - > lkey [ 0 ] , tbS0 , 0 ) ;
2005-07-13 07:21:28 +04:00
}
tb - > insert_size [ 0 ] = 0 ;
}
} else { /* regular object */
2014-04-23 18:00:46 +04:00
if ( tb - > pos_in_item = = ih_item_len ( pasted ) ) {
2005-07-13 07:21:28 +04:00
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 ) ;
2014-04-23 18:00:46 +04:00
leaf_paste_in_buffer ( & bi , tb - > item_pos , tb - > pos_in_item ,
tb - > insert_size [ 0 ] , body , tb - > zeroes_num ) ;
2005-07-13 07:21:28 +04:00
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
2014-02-18 01:21:24 +04:00
set_ih_free_space ( pasted , 0 ) ;
2005-07-13 07:21:28 +04:00
}
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 " ) ;
2014-02-18 01:21:24 +04:00
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 ] ) ;
}
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 + + )
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
}