diff options
Diffstat (limited to 'fs/reiserfs')
-rw-r--r-- | fs/reiserfs/do_balan.c | 361 |
1 files changed, 222 insertions, 139 deletions
diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c index cca685d..843c402 100644 --- a/fs/reiserfs/do_balan.c +++ b/fs/reiserfs/do_balan.c @@ -355,164 +355,247 @@ static void balance_leaf_insert_left(struct tree_balance *tb, } } -static void balance_leaf_paste_left(struct tree_balance *tb, - struct item_head *ih, const char *body) +static void balance_leaf_paste_left_shift_dirent(struct tree_balance *tb, + struct item_head *ih, + const char *body) { - struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path); - int ret_val; + 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; +} + +static void balance_leaf_paste_left_shift(struct tree_balance *tb, + struct item_head *ih, + const char *body) +{ + struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path); int n = B_NR_ITEMS(tb->L[0]); + struct buffer_info bi; - if (tb->item_pos == tb->lnum[0] - 1 && tb->lbytes != -1) { - /* we must shift the part of the appended item */ - if (is_direntry_le_ih(item_head(tbS0, tb->item_pos))) { + if (is_direntry_le_ih(item_head(tbS0, tb->item_pos))) { + balance_leaf_paste_left_shift_dirent(tb, ih, body); + return; + } - 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 l_pos_in_item = tb->pos_in_item; - - /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 entries from given directory item */ - ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes-1); - if (ret_val && !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); - } + 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); - /* Append given directory entry to directory item */ - buffer_info_init_left(tb, &bi); - leaf_paste_in_buffer(&bi, n + tb->item_pos - ret_val, l_pos_in_item, tb->insert_size[0], body, tb->zeroes_num); + /* 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; - /* previous string prepared space for pasting new entry, following string pastes this entry */ + tbS0_pos_ih = item_head(tbS0, tb->item_pos); + tbS0_0_ih = item_head(tbS0, 0); - /* when we have merge directory item, pos_in_item has been changed too */ + /* + * this bytes number must be appended + * to the last item of L[h] + */ + l_n = tb->lbytes - tb->pos_in_item; - /* paste new directory entry. 1 is entry number */ - leaf_paste_entries(&bi, n + tb->item_pos - ret_val, l_pos_in_item, - 1, (struct reiserfs_de_head *) body, - body + DEH_SIZE, tb->insert_size[0]); - tb->insert_size[0] = 0; - } else { - /* new directory item doesn't fall into L[0] */ - /* Shift lnum[0]-1 items in whole. Shift lbytes directory entries from directory item number lnum[0] */ - leaf_shift_left(tb, tb->lnum[0], tb->lbytes); - } - /* Calculate new position to append in item body */ - tb->pos_in_item -= tb->lbytes; - } else { - /* regular object */ - RFALSE(tb->lbytes <= 0, "PAP-12095: there is nothing to shift to L[0]. lbytes=%d", tb->lbytes); - RFALSE(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); - - if (tb->lbytes >= tb->pos_in_item) { - /* appended item will be in L[0] in whole */ - int l_n; - - /* this bytes number must be appended to the last item of L[h] */ - l_n = tb->lbytes - 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_val = leaf_shift_left(tb, tb->lnum[0], ih_item_len - (item_head(tbS0, tb->item_pos))); - /* Append to body of item in L[0] */ - buffer_info_init_left(tb, &bi); - leaf_paste_in_buffer - (&bi, n + tb->item_pos - ret_val, ih_item_len - (item_head(tb->L[0], n + tb->item_pos - ret_val)), - l_n, body, - tb->zeroes_num > l_n ? l_n : tb->zeroes_num); - /* 0-th item in S0 can be only of DIRECT type when l_n != 0 */ - { - int version; - int temp_l = l_n; - - RFALSE(ih_item_len(item_head(tbS0, 0)), - "PAP-12106: item length must be 0"); - RFALSE(comp_short_le_keys(leaf_key(tbS0, 0), leaf_key - (tb->L[0], n + tb->item_pos - ret_val)), - "PAP-12107: items must be of the same file"); - if (is_indirect_le_ih(item_head(tb->L[0], n + tb->item_pos - ret_val))) { - temp_l = l_n << (tb->tb_sb-> s_blocksize_bits - UNFM_P_SHIFT); - } - /* update key of first item in S0 */ - version = ih_version(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); - /* update left delimiting key */ - 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); - } + /* Calculate new insert_size[0] */ + tb->insert_size[0] -= l_n; - /* Calculate new body, position in item and insert_size[0] */ - if (l_n > tb->zeroes_num) { - body += (l_n - tb->zeroes_num); - tb->zeroes_num = 0; - } else - tb->zeroes_num -= l_n; - tb->pos_in_item = 0; + RFALSE(tb->insert_size[0] <= 0, + "PAP-12105: there is nothing to paste into " + "L[0]. insert_size=%d", tb->insert_size[0]); - 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), - "PAP-12120: item must be merge-able with left neighboring item"); - } else { /* only part of the appended item will be in L[0] */ + ret = leaf_shift_left(tb, tb->lnum[0], + ih_item_len(tbS0_pos_ih)); - /* Calculate position in item for append in S[0] */ - tb->pos_in_item -= tb->lbytes; + tbL0_ih = item_head(tb->L[0], n + tb->item_pos - ret); - RFALSE(tb->pos_in_item <= 0, "PAP-12125: no place for paste. pos_in_item=%d", tb->pos_in_item); + /* 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)); - /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */ - leaf_shift_left(tb, tb->lnum[0], tb->lbytes); - } - } - } else { /* appended item will be in L[0] in whole */ + /* + * 0-th item in S0 can be only of DIRECT type + * when l_n != 0 + */ + temp_l = l_n; - struct item_head *pasted; + 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 (!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 */ - /* 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); - } + 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); - /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */ - ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes); - /* Append to body of item in L[0] */ - buffer_info_init_left(tb, &bi); - leaf_paste_in_buffer(&bi, n + tb->item_pos - ret_val, - tb->pos_in_item, - tb->insert_size[0], - body, tb->zeroes_num); + /* 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); - /* if appended item is directory, paste entry */ - pasted = item_head(tb->L[0], n + tb->item_pos - ret_val); - if (is_direntry_le_ih(pasted)) - leaf_paste_entries(&bi, n + tb->item_pos - ret_val, - 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); - tb->insert_size[0] = 0; - tb->zeroes_num = 0; - } + /* + * Calculate new body, position in item and + * insert_size[0] + */ + if (l_n > tb->zeroes_num) { + body += (l_n - tb->zeroes_num); + 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); + } +} + + +/* appended item will be in L[0] in whole */ +static void balance_leaf_paste_left_whole(struct tree_balance *tb, + struct item_head *ih, + const char *body) +{ + struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path); + int n = B_NR_ITEMS(tb->L[0]); + struct buffer_info bi; + struct item_head *pasted; + int ret; + + /* 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); + + tb->insert_size[0] = 0; + tb->zeroes_num = 0; +} + +static void balance_leaf_paste_left(struct tree_balance *tb, + struct item_head *ih, const char *body) +{ + /* we must shift the part of the appended item */ + if (tb->item_pos == tb->lnum[0] - 1 && tb->lbytes != -1) + balance_leaf_paste_left_shift(tb, ih, body); + else + balance_leaf_paste_left_whole(tb, ih, body); } /* Shift lnum[0] items from S[0] to the left neighbor L[0] */ |