162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
362306a36Sopenharmony_ci */
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci/*
662306a36Sopenharmony_ci * Now we have all buffers that must be used in balancing of the tree
762306a36Sopenharmony_ci * Further calculations can not cause schedule(), and thus the buffer
862306a36Sopenharmony_ci * tree will be stable until the balancing will be finished
962306a36Sopenharmony_ci * balance the tree according to the analysis made before,
1062306a36Sopenharmony_ci * and using buffers obtained after all above.
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/uaccess.h>
1462306a36Sopenharmony_ci#include <linux/time.h>
1562306a36Sopenharmony_ci#include "reiserfs.h"
1662306a36Sopenharmony_ci#include <linux/buffer_head.h>
1762306a36Sopenharmony_ci#include <linux/kernel.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic inline void buffer_info_init_left(struct tree_balance *tb,
2062306a36Sopenharmony_ci                                         struct buffer_info *bi)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	bi->tb          = tb;
2362306a36Sopenharmony_ci	bi->bi_bh       = tb->L[0];
2462306a36Sopenharmony_ci	bi->bi_parent   = tb->FL[0];
2562306a36Sopenharmony_ci	bi->bi_position = get_left_neighbor_position(tb, 0);
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic inline void buffer_info_init_right(struct tree_balance *tb,
2962306a36Sopenharmony_ci                                          struct buffer_info *bi)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	bi->tb          = tb;
3262306a36Sopenharmony_ci	bi->bi_bh       = tb->R[0];
3362306a36Sopenharmony_ci	bi->bi_parent   = tb->FR[0];
3462306a36Sopenharmony_ci	bi->bi_position = get_right_neighbor_position(tb, 0);
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic inline void buffer_info_init_tbS0(struct tree_balance *tb,
3862306a36Sopenharmony_ci                                         struct buffer_info *bi)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	bi->tb          = tb;
4162306a36Sopenharmony_ci	bi->bi_bh        = PATH_PLAST_BUFFER(tb->tb_path);
4262306a36Sopenharmony_ci	bi->bi_parent   = PATH_H_PPARENT(tb->tb_path, 0);
4362306a36Sopenharmony_ci	bi->bi_position = PATH_H_POSITION(tb->tb_path, 1);
4462306a36Sopenharmony_ci}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistatic inline void buffer_info_init_bh(struct tree_balance *tb,
4762306a36Sopenharmony_ci                                       struct buffer_info *bi,
4862306a36Sopenharmony_ci                                       struct buffer_head *bh)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	bi->tb          = tb;
5162306a36Sopenharmony_ci	bi->bi_bh       = bh;
5262306a36Sopenharmony_ci	bi->bi_parent   = NULL;
5362306a36Sopenharmony_ci	bi->bi_position = 0;
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ciinline void do_balance_mark_leaf_dirty(struct tree_balance *tb,
5762306a36Sopenharmony_ci				       struct buffer_head *bh, int flag)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	journal_mark_dirty(tb->transaction_handle, bh);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci#define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty
6362306a36Sopenharmony_ci#define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/*
6662306a36Sopenharmony_ci * summary:
6762306a36Sopenharmony_ci *  if deleting something ( tb->insert_size[0] < 0 )
6862306a36Sopenharmony_ci *    return(balance_leaf_when_delete()); (flag d handled here)
6962306a36Sopenharmony_ci *  else
7062306a36Sopenharmony_ci *    if lnum is larger than 0 we put items into the left node
7162306a36Sopenharmony_ci *    if rnum is larger than 0 we put items into the right node
7262306a36Sopenharmony_ci *    if snum1 is larger than 0 we put items into the new node s1
7362306a36Sopenharmony_ci *    if snum2 is larger than 0 we put items into the new node s2
7462306a36Sopenharmony_ci * Note that all *num* count new items being created.
7562306a36Sopenharmony_ci */
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic void balance_leaf_when_delete_del(struct tree_balance *tb)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
8062306a36Sopenharmony_ci	int item_pos = PATH_LAST_POSITION(tb->tb_path);
8162306a36Sopenharmony_ci	struct buffer_info bi;
8262306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
8362306a36Sopenharmony_ci	struct item_head *ih = item_head(tbS0, item_pos);
8462306a36Sopenharmony_ci#endif
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	RFALSE(ih_item_len(ih) + IH_SIZE != -tb->insert_size[0],
8762306a36Sopenharmony_ci	       "vs-12013: mode Delete, insert size %d, ih to be deleted %h",
8862306a36Sopenharmony_ci	       -tb->insert_size[0], ih);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	buffer_info_init_tbS0(tb, &bi);
9162306a36Sopenharmony_ci	leaf_delete_items(&bi, 0, item_pos, 1, -1);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (!item_pos && tb->CFL[0]) {
9462306a36Sopenharmony_ci		if (B_NR_ITEMS(tbS0)) {
9562306a36Sopenharmony_ci			replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0);
9662306a36Sopenharmony_ci		} else {
9762306a36Sopenharmony_ci			if (!PATH_H_POSITION(tb->tb_path, 1))
9862306a36Sopenharmony_ci				replace_key(tb, tb->CFL[0], tb->lkey[0],
9962306a36Sopenharmony_ci					    PATH_H_PPARENT(tb->tb_path, 0), 0);
10062306a36Sopenharmony_ci		}
10162306a36Sopenharmony_ci	}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	RFALSE(!item_pos && !tb->CFL[0],
10462306a36Sopenharmony_ci	       "PAP-12020: tb->CFL[0]==%p, tb->L[0]==%p", tb->CFL[0],
10562306a36Sopenharmony_ci	       tb->L[0]);
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci/* cut item in S[0] */
10962306a36Sopenharmony_cistatic void balance_leaf_when_delete_cut(struct tree_balance *tb)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
11262306a36Sopenharmony_ci	int item_pos = PATH_LAST_POSITION(tb->tb_path);
11362306a36Sopenharmony_ci	struct item_head *ih = item_head(tbS0, item_pos);
11462306a36Sopenharmony_ci	int pos_in_item = tb->tb_path->pos_in_item;
11562306a36Sopenharmony_ci	struct buffer_info bi;
11662306a36Sopenharmony_ci	buffer_info_init_tbS0(tb, &bi);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	if (is_direntry_le_ih(ih)) {
11962306a36Sopenharmony_ci		/*
12062306a36Sopenharmony_ci		 * UFS unlink semantics are such that you can only
12162306a36Sopenharmony_ci		 * delete one directory entry at a time.
12262306a36Sopenharmony_ci		 *
12362306a36Sopenharmony_ci		 * when we cut a directory tb->insert_size[0] means
12462306a36Sopenharmony_ci		 * number of entries to be cut (always 1)
12562306a36Sopenharmony_ci		 */
12662306a36Sopenharmony_ci		tb->insert_size[0] = -1;
12762306a36Sopenharmony_ci		leaf_cut_from_buffer(&bi, item_pos, pos_in_item,
12862306a36Sopenharmony_ci				     -tb->insert_size[0]);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		RFALSE(!item_pos && !pos_in_item && !tb->CFL[0],
13162306a36Sopenharmony_ci		       "PAP-12030: can not change delimiting key. CFL[0]=%p",
13262306a36Sopenharmony_ci		       tb->CFL[0]);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci		if (!item_pos && !pos_in_item && tb->CFL[0])
13562306a36Sopenharmony_ci			replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0);
13662306a36Sopenharmony_ci	} else {
13762306a36Sopenharmony_ci		leaf_cut_from_buffer(&bi, item_pos, pos_in_item,
13862306a36Sopenharmony_ci				     -tb->insert_size[0]);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci		RFALSE(!ih_item_len(ih),
14162306a36Sopenharmony_ci		       "PAP-12035: cut must leave non-zero dynamic "
14262306a36Sopenharmony_ci		       "length of item");
14362306a36Sopenharmony_ci	}
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic int balance_leaf_when_delete_left(struct tree_balance *tb)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
14962306a36Sopenharmony_ci	int n = B_NR_ITEMS(tbS0);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/* L[0] must be joined with S[0] */
15262306a36Sopenharmony_ci	if (tb->lnum[0] == -1) {
15362306a36Sopenharmony_ci		/* R[0] must be also joined with S[0] */
15462306a36Sopenharmony_ci		if (tb->rnum[0] == -1) {
15562306a36Sopenharmony_ci			if (tb->FR[0] == PATH_H_PPARENT(tb->tb_path, 0)) {
15662306a36Sopenharmony_ci				/*
15762306a36Sopenharmony_ci				 * all contents of all the
15862306a36Sopenharmony_ci				 * 3 buffers will be in L[0]
15962306a36Sopenharmony_ci				 */
16062306a36Sopenharmony_ci				if (PATH_H_POSITION(tb->tb_path, 1) == 0 &&
16162306a36Sopenharmony_ci				    1 < B_NR_ITEMS(tb->FR[0]))
16262306a36Sopenharmony_ci					replace_key(tb, tb->CFL[0],
16362306a36Sopenharmony_ci						    tb->lkey[0], tb->FR[0], 1);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci				leaf_move_items(LEAF_FROM_S_TO_L, tb, n, -1,
16662306a36Sopenharmony_ci						NULL);
16762306a36Sopenharmony_ci				leaf_move_items(LEAF_FROM_R_TO_L, tb,
16862306a36Sopenharmony_ci						B_NR_ITEMS(tb->R[0]), -1,
16962306a36Sopenharmony_ci						NULL);
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci				reiserfs_invalidate_buffer(tb, tbS0);
17262306a36Sopenharmony_ci				reiserfs_invalidate_buffer(tb, tb->R[0]);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci				return 0;
17562306a36Sopenharmony_ci			}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci			/* all contents of all the 3 buffers will be in R[0] */
17862306a36Sopenharmony_ci			leaf_move_items(LEAF_FROM_S_TO_R, tb, n, -1, NULL);
17962306a36Sopenharmony_ci			leaf_move_items(LEAF_FROM_L_TO_R, tb,
18062306a36Sopenharmony_ci					B_NR_ITEMS(tb->L[0]), -1, NULL);
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci			/* right_delimiting_key is correct in R[0] */
18362306a36Sopenharmony_ci			replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci			reiserfs_invalidate_buffer(tb, tbS0);
18662306a36Sopenharmony_ci			reiserfs_invalidate_buffer(tb, tb->L[0]);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci			return -1;
18962306a36Sopenharmony_ci		}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci		RFALSE(tb->rnum[0] != 0,
19262306a36Sopenharmony_ci		       "PAP-12045: rnum must be 0 (%d)", tb->rnum[0]);
19362306a36Sopenharmony_ci		/* all contents of L[0] and S[0] will be in L[0] */
19462306a36Sopenharmony_ci		leaf_shift_left(tb, n, -1);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		reiserfs_invalidate_buffer(tb, tbS0);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		return 0;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/*
20262306a36Sopenharmony_ci	 * a part of contents of S[0] will be in L[0] and
20362306a36Sopenharmony_ci	 * the rest part of S[0] will be in R[0]
20462306a36Sopenharmony_ci	 */
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	RFALSE((tb->lnum[0] + tb->rnum[0] < n) ||
20762306a36Sopenharmony_ci	       (tb->lnum[0] + tb->rnum[0] > n + 1),
20862306a36Sopenharmony_ci	       "PAP-12050: rnum(%d) and lnum(%d) and item "
20962306a36Sopenharmony_ci	       "number(%d) in S[0] are not consistent",
21062306a36Sopenharmony_ci	       tb->rnum[0], tb->lnum[0], n);
21162306a36Sopenharmony_ci	RFALSE((tb->lnum[0] + tb->rnum[0] == n) &&
21262306a36Sopenharmony_ci	       (tb->lbytes != -1 || tb->rbytes != -1),
21362306a36Sopenharmony_ci	       "PAP-12055: bad rbytes (%d)/lbytes (%d) "
21462306a36Sopenharmony_ci	       "parameters when items are not split",
21562306a36Sopenharmony_ci	       tb->rbytes, tb->lbytes);
21662306a36Sopenharmony_ci	RFALSE((tb->lnum[0] + tb->rnum[0] == n + 1) &&
21762306a36Sopenharmony_ci	       (tb->lbytes < 1 || tb->rbytes != -1),
21862306a36Sopenharmony_ci	       "PAP-12060: bad rbytes (%d)/lbytes (%d) "
21962306a36Sopenharmony_ci	       "parameters when items are split",
22062306a36Sopenharmony_ci	       tb->rbytes, tb->lbytes);
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
22362306a36Sopenharmony_ci	leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	reiserfs_invalidate_buffer(tb, tbS0);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	return 0;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci/*
23162306a36Sopenharmony_ci * Balance leaf node in case of delete or cut: insert_size[0] < 0
23262306a36Sopenharmony_ci *
23362306a36Sopenharmony_ci * lnum, rnum can have values >= -1
23462306a36Sopenharmony_ci *	-1 means that the neighbor must be joined with S
23562306a36Sopenharmony_ci *	 0 means that nothing should be done with the neighbor
23662306a36Sopenharmony_ci *	>0 means to shift entirely or partly the specified number of items
23762306a36Sopenharmony_ci *         to the neighbor
23862306a36Sopenharmony_ci */
23962306a36Sopenharmony_cistatic int balance_leaf_when_delete(struct tree_balance *tb, int flag)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
24262306a36Sopenharmony_ci	struct buffer_info bi;
24362306a36Sopenharmony_ci	int n;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	RFALSE(tb->FR[0] && B_LEVEL(tb->FR[0]) != DISK_LEAF_NODE_LEVEL + 1,
24662306a36Sopenharmony_ci	       "vs- 12000: level: wrong FR %z", tb->FR[0]);
24762306a36Sopenharmony_ci	RFALSE(tb->blknum[0] > 1,
24862306a36Sopenharmony_ci	       "PAP-12005: tb->blknum == %d, can not be > 1", tb->blknum[0]);
24962306a36Sopenharmony_ci	RFALSE(!tb->blknum[0] && !PATH_H_PPARENT(tb->tb_path, 0),
25062306a36Sopenharmony_ci	       "PAP-12010: tree can not be empty");
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	buffer_info_init_tbS0(tb, &bi);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/* Delete or truncate the item */
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	BUG_ON(flag != M_DELETE && flag != M_CUT);
25762306a36Sopenharmony_ci	if (flag == M_DELETE)
25862306a36Sopenharmony_ci		balance_leaf_when_delete_del(tb);
25962306a36Sopenharmony_ci	else /* M_CUT */
26062306a36Sopenharmony_ci		balance_leaf_when_delete_cut(tb);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/*
26462306a36Sopenharmony_ci	 * the rule is that no shifting occurs unless by shifting
26562306a36Sopenharmony_ci	 * a node can be freed
26662306a36Sopenharmony_ci	 */
26762306a36Sopenharmony_ci	n = B_NR_ITEMS(tbS0);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	/* L[0] takes part in balancing */
27162306a36Sopenharmony_ci	if (tb->lnum[0])
27262306a36Sopenharmony_ci		return balance_leaf_when_delete_left(tb);
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	if (tb->rnum[0] == -1) {
27562306a36Sopenharmony_ci		/* all contents of R[0] and S[0] will be in R[0] */
27662306a36Sopenharmony_ci		leaf_shift_right(tb, n, -1);
27762306a36Sopenharmony_ci		reiserfs_invalidate_buffer(tb, tbS0);
27862306a36Sopenharmony_ci		return 0;
27962306a36Sopenharmony_ci	}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	RFALSE(tb->rnum[0],
28262306a36Sopenharmony_ci	       "PAP-12065: bad rnum parameter must be 0 (%d)", tb->rnum[0]);
28362306a36Sopenharmony_ci	return 0;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic unsigned int balance_leaf_insert_left(struct tree_balance *tb,
28762306a36Sopenharmony_ci					     struct item_head *const ih,
28862306a36Sopenharmony_ci					     const char * const body)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	int ret;
29162306a36Sopenharmony_ci	struct buffer_info bi;
29262306a36Sopenharmony_ci	int n = B_NR_ITEMS(tb->L[0]);
29362306a36Sopenharmony_ci	unsigned body_shift_bytes = 0;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (tb->item_pos == tb->lnum[0] - 1 && tb->lbytes != -1) {
29662306a36Sopenharmony_ci		/* part of new item falls into L[0] */
29762306a36Sopenharmony_ci		int new_item_len, shift;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci		ret = leaf_shift_left(tb, tb->lnum[0] - 1, -1);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		/* Calculate item length to insert to S[0] */
30262306a36Sopenharmony_ci		new_item_len = ih_item_len(ih) - tb->lbytes;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci		/* Calculate and check item length to insert to L[0] */
30562306a36Sopenharmony_ci		put_ih_item_len(ih, ih_item_len(ih) - new_item_len);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci		RFALSE(ih_item_len(ih) <= 0,
30862306a36Sopenharmony_ci		       "PAP-12080: there is nothing to insert into L[0]: "
30962306a36Sopenharmony_ci		       "ih_item_len=%d", ih_item_len(ih));
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci		/* Insert new item into L[0] */
31262306a36Sopenharmony_ci		buffer_info_init_left(tb, &bi);
31362306a36Sopenharmony_ci		leaf_insert_into_buf(&bi, n + tb->item_pos - ret, ih, body,
31462306a36Sopenharmony_ci			     min_t(int, tb->zeroes_num, ih_item_len(ih)));
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci		/*
31762306a36Sopenharmony_ci		 * Calculate key component, item length and body to
31862306a36Sopenharmony_ci		 * insert into S[0]
31962306a36Sopenharmony_ci		 */
32062306a36Sopenharmony_ci		shift = 0;
32162306a36Sopenharmony_ci		if (is_indirect_le_ih(ih))
32262306a36Sopenharmony_ci			shift = tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci		add_le_ih_k_offset(ih, tb->lbytes << shift);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		put_ih_item_len(ih, new_item_len);
32762306a36Sopenharmony_ci		if (tb->lbytes > tb->zeroes_num) {
32862306a36Sopenharmony_ci			body_shift_bytes = tb->lbytes - tb->zeroes_num;
32962306a36Sopenharmony_ci			tb->zeroes_num = 0;
33062306a36Sopenharmony_ci		} else
33162306a36Sopenharmony_ci			tb->zeroes_num -= tb->lbytes;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci		RFALSE(ih_item_len(ih) <= 0,
33462306a36Sopenharmony_ci		       "PAP-12085: there is nothing to insert into S[0]: "
33562306a36Sopenharmony_ci		       "ih_item_len=%d", ih_item_len(ih));
33662306a36Sopenharmony_ci	} else {
33762306a36Sopenharmony_ci		/* new item in whole falls into L[0] */
33862306a36Sopenharmony_ci		/* Shift lnum[0]-1 items to L[0] */
33962306a36Sopenharmony_ci		ret = leaf_shift_left(tb, tb->lnum[0] - 1, tb->lbytes);
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci		/* Insert new item into L[0] */
34262306a36Sopenharmony_ci		buffer_info_init_left(tb, &bi);
34362306a36Sopenharmony_ci		leaf_insert_into_buf(&bi, n + tb->item_pos - ret, ih, body,
34462306a36Sopenharmony_ci				     tb->zeroes_num);
34562306a36Sopenharmony_ci		tb->insert_size[0] = 0;
34662306a36Sopenharmony_ci		tb->zeroes_num = 0;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci	return body_shift_bytes;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_cistatic void balance_leaf_paste_left_shift_dirent(struct tree_balance *tb,
35262306a36Sopenharmony_ci						 struct item_head * const ih,
35362306a36Sopenharmony_ci						 const char * const body)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	int n = B_NR_ITEMS(tb->L[0]);
35662306a36Sopenharmony_ci	struct buffer_info bi;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	RFALSE(tb->zeroes_num,
35962306a36Sopenharmony_ci	       "PAP-12090: invalid parameter in case of a directory");
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/* directory item */
36262306a36Sopenharmony_ci	if (tb->lbytes > tb->pos_in_item) {
36362306a36Sopenharmony_ci		/* new directory entry falls into L[0] */
36462306a36Sopenharmony_ci		struct item_head *pasted;
36562306a36Sopenharmony_ci		int ret, l_pos_in_item = tb->pos_in_item;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		/*
36862306a36Sopenharmony_ci		 * Shift lnum[0] - 1 items in whole.
36962306a36Sopenharmony_ci		 * Shift lbytes - 1 entries from given directory item
37062306a36Sopenharmony_ci		 */
37162306a36Sopenharmony_ci		ret = leaf_shift_left(tb, tb->lnum[0], tb->lbytes - 1);
37262306a36Sopenharmony_ci		if (ret && !tb->item_pos) {
37362306a36Sopenharmony_ci			pasted = item_head(tb->L[0], B_NR_ITEMS(tb->L[0]) - 1);
37462306a36Sopenharmony_ci			l_pos_in_item += ih_entry_count(pasted) -
37562306a36Sopenharmony_ci					 (tb->lbytes - 1);
37662306a36Sopenharmony_ci		}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci		/* Append given directory entry to directory item */
37962306a36Sopenharmony_ci		buffer_info_init_left(tb, &bi);
38062306a36Sopenharmony_ci		leaf_paste_in_buffer(&bi, n + tb->item_pos - ret,
38162306a36Sopenharmony_ci				     l_pos_in_item, tb->insert_size[0],
38262306a36Sopenharmony_ci				     body, tb->zeroes_num);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci		/*
38562306a36Sopenharmony_ci		 * previous string prepared space for pasting new entry,
38662306a36Sopenharmony_ci		 * following string pastes this entry
38762306a36Sopenharmony_ci		 */
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci		/*
39062306a36Sopenharmony_ci		 * when we have merge directory item, pos_in_item
39162306a36Sopenharmony_ci		 * has been changed too
39262306a36Sopenharmony_ci		 */
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci		/* paste new directory entry. 1 is entry number */
39562306a36Sopenharmony_ci		leaf_paste_entries(&bi, n + tb->item_pos - ret,
39662306a36Sopenharmony_ci				   l_pos_in_item, 1,
39762306a36Sopenharmony_ci				   (struct reiserfs_de_head *) body,
39862306a36Sopenharmony_ci				   body + DEH_SIZE, tb->insert_size[0]);
39962306a36Sopenharmony_ci		tb->insert_size[0] = 0;
40062306a36Sopenharmony_ci	} else {
40162306a36Sopenharmony_ci		/* new directory item doesn't fall into L[0] */
40262306a36Sopenharmony_ci		/*
40362306a36Sopenharmony_ci		 * Shift lnum[0]-1 items in whole. Shift lbytes
40462306a36Sopenharmony_ci		 * directory entries from directory item number lnum[0]
40562306a36Sopenharmony_ci		 */
40662306a36Sopenharmony_ci		leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/* Calculate new position to append in item body */
41062306a36Sopenharmony_ci	tb->pos_in_item -= tb->lbytes;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic unsigned int balance_leaf_paste_left_shift(struct tree_balance *tb,
41462306a36Sopenharmony_ci						  struct item_head * const ih,
41562306a36Sopenharmony_ci						  const char * const body)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
41862306a36Sopenharmony_ci	int n = B_NR_ITEMS(tb->L[0]);
41962306a36Sopenharmony_ci	struct buffer_info bi;
42062306a36Sopenharmony_ci	int body_shift_bytes = 0;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	if (is_direntry_le_ih(item_head(tbS0, tb->item_pos))) {
42362306a36Sopenharmony_ci		balance_leaf_paste_left_shift_dirent(tb, ih, body);
42462306a36Sopenharmony_ci		return 0;
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	RFALSE(tb->lbytes <= 0,
42862306a36Sopenharmony_ci	       "PAP-12095: there is nothing to shift to L[0]. "
42962306a36Sopenharmony_ci	       "lbytes=%d", tb->lbytes);
43062306a36Sopenharmony_ci	RFALSE(tb->pos_in_item != ih_item_len(item_head(tbS0, tb->item_pos)),
43162306a36Sopenharmony_ci	       "PAP-12100: incorrect position to paste: "
43262306a36Sopenharmony_ci	       "item_len=%d, pos_in_item=%d",
43362306a36Sopenharmony_ci	       ih_item_len(item_head(tbS0, tb->item_pos)), tb->pos_in_item);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	/* appended item will be in L[0] in whole */
43662306a36Sopenharmony_ci	if (tb->lbytes >= tb->pos_in_item) {
43762306a36Sopenharmony_ci		struct item_head *tbS0_pos_ih, *tbL0_ih;
43862306a36Sopenharmony_ci		struct item_head *tbS0_0_ih;
43962306a36Sopenharmony_ci		struct reiserfs_key *left_delim_key;
44062306a36Sopenharmony_ci		int ret, l_n, version, temp_l;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci		tbS0_pos_ih = item_head(tbS0, tb->item_pos);
44362306a36Sopenharmony_ci		tbS0_0_ih = item_head(tbS0, 0);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		/*
44662306a36Sopenharmony_ci		 * this bytes number must be appended
44762306a36Sopenharmony_ci		 * to the last item of L[h]
44862306a36Sopenharmony_ci		 */
44962306a36Sopenharmony_ci		l_n = tb->lbytes - tb->pos_in_item;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci		/* Calculate new insert_size[0] */
45262306a36Sopenharmony_ci		tb->insert_size[0] -= l_n;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci		RFALSE(tb->insert_size[0] <= 0,
45562306a36Sopenharmony_ci		       "PAP-12105: there is nothing to paste into "
45662306a36Sopenharmony_ci		       "L[0]. insert_size=%d", tb->insert_size[0]);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci		ret = leaf_shift_left(tb, tb->lnum[0],
45962306a36Sopenharmony_ci				      ih_item_len(tbS0_pos_ih));
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci		tbL0_ih = item_head(tb->L[0], n + tb->item_pos - ret);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci		/* Append to body of item in L[0] */
46462306a36Sopenharmony_ci		buffer_info_init_left(tb, &bi);
46562306a36Sopenharmony_ci		leaf_paste_in_buffer(&bi, n + tb->item_pos - ret,
46662306a36Sopenharmony_ci				     ih_item_len(tbL0_ih), l_n, body,
46762306a36Sopenharmony_ci				     min_t(int, l_n, tb->zeroes_num));
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci		/*
47062306a36Sopenharmony_ci		 * 0-th item in S0 can be only of DIRECT type
47162306a36Sopenharmony_ci		 * when l_n != 0
47262306a36Sopenharmony_ci		 */
47362306a36Sopenharmony_ci		temp_l = l_n;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		RFALSE(ih_item_len(tbS0_0_ih),
47662306a36Sopenharmony_ci		       "PAP-12106: item length must be 0");
47762306a36Sopenharmony_ci		RFALSE(comp_short_le_keys(&tbS0_0_ih->ih_key,
47862306a36Sopenharmony_ci		       leaf_key(tb->L[0], n + tb->item_pos - ret)),
47962306a36Sopenharmony_ci		       "PAP-12107: items must be of the same file");
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci		if (is_indirect_le_ih(tbL0_ih)) {
48262306a36Sopenharmony_ci			int shift = tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT;
48362306a36Sopenharmony_ci			temp_l = l_n << shift;
48462306a36Sopenharmony_ci		}
48562306a36Sopenharmony_ci		/* update key of first item in S0 */
48662306a36Sopenharmony_ci		version = ih_version(tbS0_0_ih);
48762306a36Sopenharmony_ci		add_le_key_k_offset(version, &tbS0_0_ih->ih_key, temp_l);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci		/* update left delimiting key */
49062306a36Sopenharmony_ci		left_delim_key = internal_key(tb->CFL[0], tb->lkey[0]);
49162306a36Sopenharmony_ci		add_le_key_k_offset(version, left_delim_key, temp_l);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci		/*
49462306a36Sopenharmony_ci		 * Calculate new body, position in item and
49562306a36Sopenharmony_ci		 * insert_size[0]
49662306a36Sopenharmony_ci		 */
49762306a36Sopenharmony_ci		if (l_n > tb->zeroes_num) {
49862306a36Sopenharmony_ci			body_shift_bytes = l_n - tb->zeroes_num;
49962306a36Sopenharmony_ci			tb->zeroes_num = 0;
50062306a36Sopenharmony_ci		} else
50162306a36Sopenharmony_ci			tb->zeroes_num -= l_n;
50262306a36Sopenharmony_ci		tb->pos_in_item = 0;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci		RFALSE(comp_short_le_keys(&tbS0_0_ih->ih_key,
50562306a36Sopenharmony_ci					  leaf_key(tb->L[0],
50662306a36Sopenharmony_ci						 B_NR_ITEMS(tb->L[0]) - 1)) ||
50762306a36Sopenharmony_ci		       !op_is_left_mergeable(leaf_key(tbS0, 0), tbS0->b_size) ||
50862306a36Sopenharmony_ci		       !op_is_left_mergeable(left_delim_key, tbS0->b_size),
50962306a36Sopenharmony_ci		       "PAP-12120: item must be merge-able with left "
51062306a36Sopenharmony_ci		       "neighboring item");
51162306a36Sopenharmony_ci	} else {
51262306a36Sopenharmony_ci		/* only part of the appended item will be in L[0] */
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		/* Calculate position in item for append in S[0] */
51562306a36Sopenharmony_ci		tb->pos_in_item -= tb->lbytes;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci		RFALSE(tb->pos_in_item <= 0,
51862306a36Sopenharmony_ci		       "PAP-12125: no place for paste. pos_in_item=%d",
51962306a36Sopenharmony_ci		       tb->pos_in_item);
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci		/*
52262306a36Sopenharmony_ci		 * Shift lnum[0] - 1 items in whole.
52362306a36Sopenharmony_ci		 * Shift lbytes - 1 byte from item number lnum[0]
52462306a36Sopenharmony_ci		 */
52562306a36Sopenharmony_ci		leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci	return body_shift_bytes;
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci/* appended item will be in L[0] in whole */
53262306a36Sopenharmony_cistatic void balance_leaf_paste_left_whole(struct tree_balance *tb,
53362306a36Sopenharmony_ci					  struct item_head * const ih,
53462306a36Sopenharmony_ci					  const char * const body)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
53762306a36Sopenharmony_ci	int n = B_NR_ITEMS(tb->L[0]);
53862306a36Sopenharmony_ci	struct buffer_info bi;
53962306a36Sopenharmony_ci	struct item_head *pasted;
54062306a36Sopenharmony_ci	int ret;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	/* if we paste into first item of S[0] and it is left mergable */
54362306a36Sopenharmony_ci	if (!tb->item_pos &&
54462306a36Sopenharmony_ci	    op_is_left_mergeable(leaf_key(tbS0, 0), tbS0->b_size)) {
54562306a36Sopenharmony_ci		/*
54662306a36Sopenharmony_ci		 * then increment pos_in_item by the size of the
54762306a36Sopenharmony_ci		 * last item in L[0]
54862306a36Sopenharmony_ci		 */
54962306a36Sopenharmony_ci		pasted = item_head(tb->L[0], n - 1);
55062306a36Sopenharmony_ci		if (is_direntry_le_ih(pasted))
55162306a36Sopenharmony_ci			tb->pos_in_item += ih_entry_count(pasted);
55262306a36Sopenharmony_ci		else
55362306a36Sopenharmony_ci			tb->pos_in_item += ih_item_len(pasted);
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	/*
55762306a36Sopenharmony_ci	 * Shift lnum[0] - 1 items in whole.
55862306a36Sopenharmony_ci	 * Shift lbytes - 1 byte from item number lnum[0]
55962306a36Sopenharmony_ci	 */
56062306a36Sopenharmony_ci	ret = leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	/* Append to body of item in L[0] */
56362306a36Sopenharmony_ci	buffer_info_init_left(tb, &bi);
56462306a36Sopenharmony_ci	leaf_paste_in_buffer(&bi, n + tb->item_pos - ret, tb->pos_in_item,
56562306a36Sopenharmony_ci			     tb->insert_size[0], body, tb->zeroes_num);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	/* if appended item is directory, paste entry */
56862306a36Sopenharmony_ci	pasted = item_head(tb->L[0], n + tb->item_pos - ret);
56962306a36Sopenharmony_ci	if (is_direntry_le_ih(pasted))
57062306a36Sopenharmony_ci		leaf_paste_entries(&bi, n + tb->item_pos - ret,
57162306a36Sopenharmony_ci				   tb->pos_in_item, 1,
57262306a36Sopenharmony_ci				   (struct reiserfs_de_head *)body,
57362306a36Sopenharmony_ci				   body + DEH_SIZE, tb->insert_size[0]);
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	/*
57662306a36Sopenharmony_ci	 * if appended item is indirect item, put unformatted node
57762306a36Sopenharmony_ci	 * into un list
57862306a36Sopenharmony_ci	 */
57962306a36Sopenharmony_ci	if (is_indirect_le_ih(pasted))
58062306a36Sopenharmony_ci		set_ih_free_space(pasted, 0);
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	tb->insert_size[0] = 0;
58362306a36Sopenharmony_ci	tb->zeroes_num = 0;
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_cistatic unsigned int balance_leaf_paste_left(struct tree_balance *tb,
58762306a36Sopenharmony_ci					    struct item_head * const ih,
58862306a36Sopenharmony_ci					    const char * const body)
58962306a36Sopenharmony_ci{
59062306a36Sopenharmony_ci	/* we must shift the part of the appended item */
59162306a36Sopenharmony_ci	if (tb->item_pos == tb->lnum[0] - 1 && tb->lbytes != -1)
59262306a36Sopenharmony_ci		return balance_leaf_paste_left_shift(tb, ih, body);
59362306a36Sopenharmony_ci	else
59462306a36Sopenharmony_ci		balance_leaf_paste_left_whole(tb, ih, body);
59562306a36Sopenharmony_ci	return 0;
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci/* Shift lnum[0] items from S[0] to the left neighbor L[0] */
59962306a36Sopenharmony_cistatic unsigned int balance_leaf_left(struct tree_balance *tb,
60062306a36Sopenharmony_ci				      struct item_head * const ih,
60162306a36Sopenharmony_ci				      const char * const body, int flag)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	if (tb->lnum[0] <= 0)
60462306a36Sopenharmony_ci		return 0;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	/* new item or it part falls to L[0], shift it too */
60762306a36Sopenharmony_ci	if (tb->item_pos < tb->lnum[0]) {
60862306a36Sopenharmony_ci		BUG_ON(flag != M_INSERT && flag != M_PASTE);
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci		if (flag == M_INSERT)
61162306a36Sopenharmony_ci			return balance_leaf_insert_left(tb, ih, body);
61262306a36Sopenharmony_ci		else /* M_PASTE */
61362306a36Sopenharmony_ci			return balance_leaf_paste_left(tb, ih, body);
61462306a36Sopenharmony_ci	} else
61562306a36Sopenharmony_ci		/* new item doesn't fall into L[0] */
61662306a36Sopenharmony_ci		leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
61762306a36Sopenharmony_ci	return 0;
61862306a36Sopenharmony_ci}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_cistatic void balance_leaf_insert_right(struct tree_balance *tb,
62262306a36Sopenharmony_ci				      struct item_head * const ih,
62362306a36Sopenharmony_ci				      const char * const body)
62462306a36Sopenharmony_ci{
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
62762306a36Sopenharmony_ci	int n = B_NR_ITEMS(tbS0);
62862306a36Sopenharmony_ci	struct buffer_info bi;
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	/* new item or part of it doesn't fall into R[0] */
63162306a36Sopenharmony_ci	if (n - tb->rnum[0] >= tb->item_pos) {
63262306a36Sopenharmony_ci		leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
63362306a36Sopenharmony_ci		return;
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	/* new item or its part falls to R[0] */
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	/* part of new item falls into R[0] */
63962306a36Sopenharmony_ci	if (tb->item_pos == n - tb->rnum[0] + 1 && tb->rbytes != -1) {
64062306a36Sopenharmony_ci		loff_t old_key_comp, old_len, r_zeroes_number;
64162306a36Sopenharmony_ci		const char *r_body;
64262306a36Sopenharmony_ci		int shift;
64362306a36Sopenharmony_ci		loff_t offset;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		leaf_shift_right(tb, tb->rnum[0] - 1, -1);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci		/* Remember key component and item length */
64862306a36Sopenharmony_ci		old_key_comp = le_ih_k_offset(ih);
64962306a36Sopenharmony_ci		old_len = ih_item_len(ih);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci		/*
65262306a36Sopenharmony_ci		 * Calculate key component and item length to insert
65362306a36Sopenharmony_ci		 * into R[0]
65462306a36Sopenharmony_ci		 */
65562306a36Sopenharmony_ci		shift = 0;
65662306a36Sopenharmony_ci		if (is_indirect_le_ih(ih))
65762306a36Sopenharmony_ci			shift = tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT;
65862306a36Sopenharmony_ci		offset = le_ih_k_offset(ih) + ((old_len - tb->rbytes) << shift);
65962306a36Sopenharmony_ci		set_le_ih_k_offset(ih, offset);
66062306a36Sopenharmony_ci		put_ih_item_len(ih, tb->rbytes);
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci		/* Insert part of the item into R[0] */
66362306a36Sopenharmony_ci		buffer_info_init_right(tb, &bi);
66462306a36Sopenharmony_ci		if ((old_len - tb->rbytes) > tb->zeroes_num) {
66562306a36Sopenharmony_ci			r_zeroes_number = 0;
66662306a36Sopenharmony_ci			r_body = body + (old_len - tb->rbytes) - tb->zeroes_num;
66762306a36Sopenharmony_ci		} else {
66862306a36Sopenharmony_ci			r_body = body;
66962306a36Sopenharmony_ci			r_zeroes_number = tb->zeroes_num -
67062306a36Sopenharmony_ci					  (old_len - tb->rbytes);
67162306a36Sopenharmony_ci			tb->zeroes_num -= r_zeroes_number;
67262306a36Sopenharmony_ci		}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci		leaf_insert_into_buf(&bi, 0, ih, r_body, r_zeroes_number);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci		/* Replace right delimiting key by first key in R[0] */
67762306a36Sopenharmony_ci		replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci		/*
68062306a36Sopenharmony_ci		 * Calculate key component and item length to
68162306a36Sopenharmony_ci		 * insert into S[0]
68262306a36Sopenharmony_ci		 */
68362306a36Sopenharmony_ci		set_le_ih_k_offset(ih, old_key_comp);
68462306a36Sopenharmony_ci		put_ih_item_len(ih, old_len - tb->rbytes);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci		tb->insert_size[0] -= tb->rbytes;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	} else {
68962306a36Sopenharmony_ci		/* whole new item falls into R[0] */
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci		/* Shift rnum[0]-1 items to R[0] */
69262306a36Sopenharmony_ci		leaf_shift_right(tb, tb->rnum[0] - 1, tb->rbytes);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci		/* Insert new item into R[0] */
69562306a36Sopenharmony_ci		buffer_info_init_right(tb, &bi);
69662306a36Sopenharmony_ci		leaf_insert_into_buf(&bi, tb->item_pos - n + tb->rnum[0] - 1,
69762306a36Sopenharmony_ci				     ih, body, tb->zeroes_num);
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci		if (tb->item_pos - n + tb->rnum[0] - 1 == 0)
70062306a36Sopenharmony_ci			replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci		tb->zeroes_num = tb->insert_size[0] = 0;
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_cistatic void balance_leaf_paste_right_shift_dirent(struct tree_balance *tb,
70862306a36Sopenharmony_ci				     struct item_head * const ih,
70962306a36Sopenharmony_ci				     const char * const body)
71062306a36Sopenharmony_ci{
71162306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
71262306a36Sopenharmony_ci	struct buffer_info bi;
71362306a36Sopenharmony_ci	int entry_count;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	RFALSE(tb->zeroes_num,
71662306a36Sopenharmony_ci	       "PAP-12145: invalid parameter in case of a directory");
71762306a36Sopenharmony_ci	entry_count = ih_entry_count(item_head(tbS0, tb->item_pos));
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	/* new directory entry falls into R[0] */
72062306a36Sopenharmony_ci	if (entry_count - tb->rbytes < tb->pos_in_item) {
72162306a36Sopenharmony_ci		int paste_entry_position;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci		RFALSE(tb->rbytes - 1 >= entry_count || !tb->insert_size[0],
72462306a36Sopenharmony_ci		       "PAP-12150: no enough of entries to shift to R[0]: "
72562306a36Sopenharmony_ci		       "rbytes=%d, entry_count=%d", tb->rbytes, entry_count);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_ci		/*
72862306a36Sopenharmony_ci		 * Shift rnum[0]-1 items in whole.
72962306a36Sopenharmony_ci		 * Shift rbytes-1 directory entries from directory
73062306a36Sopenharmony_ci		 * item number rnum[0]
73162306a36Sopenharmony_ci		 */
73262306a36Sopenharmony_ci		leaf_shift_right(tb, tb->rnum[0], tb->rbytes - 1);
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci		/* Paste given directory entry to directory item */
73562306a36Sopenharmony_ci		paste_entry_position = tb->pos_in_item - entry_count +
73662306a36Sopenharmony_ci				       tb->rbytes - 1;
73762306a36Sopenharmony_ci		buffer_info_init_right(tb, &bi);
73862306a36Sopenharmony_ci		leaf_paste_in_buffer(&bi, 0, paste_entry_position,
73962306a36Sopenharmony_ci				     tb->insert_size[0], body, tb->zeroes_num);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci		/* paste entry */
74262306a36Sopenharmony_ci		leaf_paste_entries(&bi, 0, paste_entry_position, 1,
74362306a36Sopenharmony_ci				   (struct reiserfs_de_head *) body,
74462306a36Sopenharmony_ci				   body + DEH_SIZE, tb->insert_size[0]);
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci		/* change delimiting keys */
74762306a36Sopenharmony_ci		if (paste_entry_position == 0)
74862306a36Sopenharmony_ci			replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci		tb->insert_size[0] = 0;
75162306a36Sopenharmony_ci		tb->pos_in_item++;
75262306a36Sopenharmony_ci	} else {
75362306a36Sopenharmony_ci		/* new directory entry doesn't fall into R[0] */
75462306a36Sopenharmony_ci		leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cistatic void balance_leaf_paste_right_shift(struct tree_balance *tb,
75962306a36Sopenharmony_ci				     struct item_head * const ih,
76062306a36Sopenharmony_ci				     const char * const body)
76162306a36Sopenharmony_ci{
76262306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
76362306a36Sopenharmony_ci	int n_shift, n_rem, r_zeroes_number, version;
76462306a36Sopenharmony_ci	unsigned long temp_rem;
76562306a36Sopenharmony_ci	const char *r_body;
76662306a36Sopenharmony_ci	struct buffer_info bi;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	/* we append to directory item */
76962306a36Sopenharmony_ci	if (is_direntry_le_ih(item_head(tbS0, tb->item_pos))) {
77062306a36Sopenharmony_ci		balance_leaf_paste_right_shift_dirent(tb, ih, body);
77162306a36Sopenharmony_ci		return;
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	/* regular object */
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	/*
77762306a36Sopenharmony_ci	 * Calculate number of bytes which must be shifted
77862306a36Sopenharmony_ci	 * from appended item
77962306a36Sopenharmony_ci	 */
78062306a36Sopenharmony_ci	n_shift = tb->rbytes - tb->insert_size[0];
78162306a36Sopenharmony_ci	if (n_shift < 0)
78262306a36Sopenharmony_ci		n_shift = 0;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	RFALSE(tb->pos_in_item != ih_item_len(item_head(tbS0, tb->item_pos)),
78562306a36Sopenharmony_ci	       "PAP-12155: invalid position to paste. ih_item_len=%d, "
78662306a36Sopenharmony_ci	       "pos_in_item=%d", tb->pos_in_item,
78762306a36Sopenharmony_ci	       ih_item_len(item_head(tbS0, tb->item_pos)));
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	leaf_shift_right(tb, tb->rnum[0], n_shift);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	/*
79262306a36Sopenharmony_ci	 * Calculate number of bytes which must remain in body
79362306a36Sopenharmony_ci	 * after appending to R[0]
79462306a36Sopenharmony_ci	 */
79562306a36Sopenharmony_ci	n_rem = tb->insert_size[0] - tb->rbytes;
79662306a36Sopenharmony_ci	if (n_rem < 0)
79762306a36Sopenharmony_ci		n_rem = 0;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	temp_rem = n_rem;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	version = ih_version(item_head(tb->R[0], 0));
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	if (is_indirect_le_key(version, leaf_key(tb->R[0], 0))) {
80462306a36Sopenharmony_ci		int shift = tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT;
80562306a36Sopenharmony_ci		temp_rem = n_rem << shift;
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	add_le_key_k_offset(version, leaf_key(tb->R[0], 0), temp_rem);
80962306a36Sopenharmony_ci	add_le_key_k_offset(version, internal_key(tb->CFR[0], tb->rkey[0]),
81062306a36Sopenharmony_ci			    temp_rem);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	do_balance_mark_internal_dirty(tb, tb->CFR[0], 0);
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci	/* Append part of body into R[0] */
81562306a36Sopenharmony_ci	buffer_info_init_right(tb, &bi);
81662306a36Sopenharmony_ci	if (n_rem > tb->zeroes_num) {
81762306a36Sopenharmony_ci		r_zeroes_number = 0;
81862306a36Sopenharmony_ci		r_body = body + n_rem - tb->zeroes_num;
81962306a36Sopenharmony_ci	} else {
82062306a36Sopenharmony_ci		r_body = body;
82162306a36Sopenharmony_ci		r_zeroes_number = tb->zeroes_num - n_rem;
82262306a36Sopenharmony_ci		tb->zeroes_num -= r_zeroes_number;
82362306a36Sopenharmony_ci	}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	leaf_paste_in_buffer(&bi, 0, n_shift, tb->insert_size[0] - n_rem,
82662306a36Sopenharmony_ci			     r_body, r_zeroes_number);
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	if (is_indirect_le_ih(item_head(tb->R[0], 0)))
82962306a36Sopenharmony_ci		set_ih_free_space(item_head(tb->R[0], 0), 0);
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	tb->insert_size[0] = n_rem;
83262306a36Sopenharmony_ci	if (!n_rem)
83362306a36Sopenharmony_ci		tb->pos_in_item++;
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic void balance_leaf_paste_right_whole(struct tree_balance *tb,
83762306a36Sopenharmony_ci				     struct item_head * const ih,
83862306a36Sopenharmony_ci				     const char * const body)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
84162306a36Sopenharmony_ci	int n = B_NR_ITEMS(tbS0);
84262306a36Sopenharmony_ci	struct item_head *pasted;
84362306a36Sopenharmony_ci	struct buffer_info bi;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	buffer_info_init_right(tb, &bi);
84662306a36Sopenharmony_ci	leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	/* append item in R[0] */
84962306a36Sopenharmony_ci	if (tb->pos_in_item >= 0) {
85062306a36Sopenharmony_ci		buffer_info_init_right(tb, &bi);
85162306a36Sopenharmony_ci		leaf_paste_in_buffer(&bi, tb->item_pos - n + tb->rnum[0],
85262306a36Sopenharmony_ci				     tb->pos_in_item, tb->insert_size[0], body,
85362306a36Sopenharmony_ci				     tb->zeroes_num);
85462306a36Sopenharmony_ci	}
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	/* paste new entry, if item is directory item */
85762306a36Sopenharmony_ci	pasted = item_head(tb->R[0], tb->item_pos - n + tb->rnum[0]);
85862306a36Sopenharmony_ci	if (is_direntry_le_ih(pasted) && tb->pos_in_item >= 0) {
85962306a36Sopenharmony_ci		leaf_paste_entries(&bi, tb->item_pos - n + tb->rnum[0],
86062306a36Sopenharmony_ci				   tb->pos_in_item, 1,
86162306a36Sopenharmony_ci				   (struct reiserfs_de_head *)body,
86262306a36Sopenharmony_ci				   body + DEH_SIZE, tb->insert_size[0]);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci		if (!tb->pos_in_item) {
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci			RFALSE(tb->item_pos - n + tb->rnum[0],
86762306a36Sopenharmony_ci			       "PAP-12165: directory item must be first "
86862306a36Sopenharmony_ci			       "item of node when pasting is in 0th position");
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci			/* update delimiting keys */
87162306a36Sopenharmony_ci			replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
87262306a36Sopenharmony_ci		}
87362306a36Sopenharmony_ci	}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	if (is_indirect_le_ih(pasted))
87662306a36Sopenharmony_ci		set_ih_free_space(pasted, 0);
87762306a36Sopenharmony_ci	tb->zeroes_num = tb->insert_size[0] = 0;
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_cistatic void balance_leaf_paste_right(struct tree_balance *tb,
88162306a36Sopenharmony_ci				     struct item_head * const ih,
88262306a36Sopenharmony_ci				     const char * const body)
88362306a36Sopenharmony_ci{
88462306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
88562306a36Sopenharmony_ci	int n = B_NR_ITEMS(tbS0);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	/* new item doesn't fall into R[0] */
88862306a36Sopenharmony_ci	if (n - tb->rnum[0] > tb->item_pos) {
88962306a36Sopenharmony_ci		leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
89062306a36Sopenharmony_ci		return;
89162306a36Sopenharmony_ci	}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	/* pasted item or part of it falls to R[0] */
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	if (tb->item_pos == n - tb->rnum[0] && tb->rbytes != -1)
89662306a36Sopenharmony_ci		/* we must shift the part of the appended item */
89762306a36Sopenharmony_ci		balance_leaf_paste_right_shift(tb, ih, body);
89862306a36Sopenharmony_ci	else
89962306a36Sopenharmony_ci		/* pasted item in whole falls into R[0] */
90062306a36Sopenharmony_ci		balance_leaf_paste_right_whole(tb, ih, body);
90162306a36Sopenharmony_ci}
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci/* shift rnum[0] items from S[0] to the right neighbor R[0] */
90462306a36Sopenharmony_cistatic void balance_leaf_right(struct tree_balance *tb,
90562306a36Sopenharmony_ci			       struct item_head * const ih,
90662306a36Sopenharmony_ci			       const char * const body, int flag)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	if (tb->rnum[0] <= 0)
90962306a36Sopenharmony_ci		return;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	BUG_ON(flag != M_INSERT && flag != M_PASTE);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	if (flag == M_INSERT)
91462306a36Sopenharmony_ci		balance_leaf_insert_right(tb, ih, body);
91562306a36Sopenharmony_ci	else /* M_PASTE */
91662306a36Sopenharmony_ci		balance_leaf_paste_right(tb, ih, body);
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_cistatic void balance_leaf_new_nodes_insert(struct tree_balance *tb,
92062306a36Sopenharmony_ci					  struct item_head * const ih,
92162306a36Sopenharmony_ci					  const char * const body,
92262306a36Sopenharmony_ci					  struct item_head *insert_key,
92362306a36Sopenharmony_ci					  struct buffer_head **insert_ptr,
92462306a36Sopenharmony_ci					  int i)
92562306a36Sopenharmony_ci{
92662306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
92762306a36Sopenharmony_ci	int n = B_NR_ITEMS(tbS0);
92862306a36Sopenharmony_ci	struct buffer_info bi;
92962306a36Sopenharmony_ci	int shift;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	/* new item or it part don't falls into S_new[i] */
93262306a36Sopenharmony_ci	if (n - tb->snum[i] >= tb->item_pos) {
93362306a36Sopenharmony_ci		leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
93462306a36Sopenharmony_ci				tb->snum[i], tb->sbytes[i], tb->S_new[i]);
93562306a36Sopenharmony_ci		return;
93662306a36Sopenharmony_ci	}
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	/* new item or it's part falls to first new node S_new[i] */
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	/* part of new item falls into S_new[i] */
94162306a36Sopenharmony_ci	if (tb->item_pos == n - tb->snum[i] + 1 && tb->sbytes[i] != -1) {
94262306a36Sopenharmony_ci		int old_key_comp, old_len, r_zeroes_number;
94362306a36Sopenharmony_ci		const char *r_body;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci		/* Move snum[i]-1 items from S[0] to S_new[i] */
94662306a36Sopenharmony_ci		leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, tb->snum[i] - 1, -1,
94762306a36Sopenharmony_ci				tb->S_new[i]);
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci		/* Remember key component and item length */
95062306a36Sopenharmony_ci		old_key_comp = le_ih_k_offset(ih);
95162306a36Sopenharmony_ci		old_len = ih_item_len(ih);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci		/*
95462306a36Sopenharmony_ci		 * Calculate key component and item length to insert
95562306a36Sopenharmony_ci		 * into S_new[i]
95662306a36Sopenharmony_ci		 */
95762306a36Sopenharmony_ci		shift = 0;
95862306a36Sopenharmony_ci		if (is_indirect_le_ih(ih))
95962306a36Sopenharmony_ci			shift = tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT;
96062306a36Sopenharmony_ci		set_le_ih_k_offset(ih,
96162306a36Sopenharmony_ci				   le_ih_k_offset(ih) +
96262306a36Sopenharmony_ci				   ((old_len - tb->sbytes[i]) << shift));
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci		put_ih_item_len(ih, tb->sbytes[i]);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci		/* Insert part of the item into S_new[i] before 0-th item */
96762306a36Sopenharmony_ci		buffer_info_init_bh(tb, &bi, tb->S_new[i]);
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci		if ((old_len - tb->sbytes[i]) > tb->zeroes_num) {
97062306a36Sopenharmony_ci			r_zeroes_number = 0;
97162306a36Sopenharmony_ci			r_body = body + (old_len - tb->sbytes[i]) -
97262306a36Sopenharmony_ci					 tb->zeroes_num;
97362306a36Sopenharmony_ci		} else {
97462306a36Sopenharmony_ci			r_body = body;
97562306a36Sopenharmony_ci			r_zeroes_number = tb->zeroes_num - (old_len -
97662306a36Sopenharmony_ci					  tb->sbytes[i]);
97762306a36Sopenharmony_ci			tb->zeroes_num -= r_zeroes_number;
97862306a36Sopenharmony_ci		}
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci		leaf_insert_into_buf(&bi, 0, ih, r_body, r_zeroes_number);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci		/*
98362306a36Sopenharmony_ci		 * Calculate key component and item length to
98462306a36Sopenharmony_ci		 * insert into S[i]
98562306a36Sopenharmony_ci		 */
98662306a36Sopenharmony_ci		set_le_ih_k_offset(ih, old_key_comp);
98762306a36Sopenharmony_ci		put_ih_item_len(ih, old_len - tb->sbytes[i]);
98862306a36Sopenharmony_ci		tb->insert_size[0] -= tb->sbytes[i];
98962306a36Sopenharmony_ci	} else {
99062306a36Sopenharmony_ci		/* whole new item falls into S_new[i] */
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		/*
99362306a36Sopenharmony_ci		 * Shift snum[0] - 1 items to S_new[i]
99462306a36Sopenharmony_ci		 * (sbytes[i] of split item)
99562306a36Sopenharmony_ci		 */
99662306a36Sopenharmony_ci		leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
99762306a36Sopenharmony_ci				tb->snum[i] - 1, tb->sbytes[i], tb->S_new[i]);
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci		/* Insert new item into S_new[i] */
100062306a36Sopenharmony_ci		buffer_info_init_bh(tb, &bi, tb->S_new[i]);
100162306a36Sopenharmony_ci		leaf_insert_into_buf(&bi, tb->item_pos - n + tb->snum[i] - 1,
100262306a36Sopenharmony_ci				     ih, body, tb->zeroes_num);
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_ci		tb->zeroes_num = tb->insert_size[0] = 0;
100562306a36Sopenharmony_ci	}
100662306a36Sopenharmony_ci}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci/* we append to directory item */
100962306a36Sopenharmony_cistatic void balance_leaf_new_nodes_paste_dirent(struct tree_balance *tb,
101062306a36Sopenharmony_ci					 struct item_head * const ih,
101162306a36Sopenharmony_ci					 const char * const body,
101262306a36Sopenharmony_ci					 struct item_head *insert_key,
101362306a36Sopenharmony_ci					 struct buffer_head **insert_ptr,
101462306a36Sopenharmony_ci					 int i)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
101762306a36Sopenharmony_ci	struct item_head *aux_ih = item_head(tbS0, tb->item_pos);
101862306a36Sopenharmony_ci	int entry_count = ih_entry_count(aux_ih);
101962306a36Sopenharmony_ci	struct buffer_info bi;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	if (entry_count - tb->sbytes[i] < tb->pos_in_item &&
102262306a36Sopenharmony_ci	    tb->pos_in_item <= entry_count) {
102362306a36Sopenharmony_ci		/* new directory entry falls into S_new[i] */
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci		RFALSE(!tb->insert_size[0],
102662306a36Sopenharmony_ci		       "PAP-12215: insert_size is already 0");
102762306a36Sopenharmony_ci		RFALSE(tb->sbytes[i] - 1 >= entry_count,
102862306a36Sopenharmony_ci		       "PAP-12220: there are no so much entries (%d), only %d",
102962306a36Sopenharmony_ci		       tb->sbytes[i] - 1, entry_count);
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci		/*
103262306a36Sopenharmony_ci		 * Shift snum[i]-1 items in whole.
103362306a36Sopenharmony_ci		 * Shift sbytes[i] directory entries
103462306a36Sopenharmony_ci		 * from directory item number snum[i]
103562306a36Sopenharmony_ci		 */
103662306a36Sopenharmony_ci		leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, tb->snum[i],
103762306a36Sopenharmony_ci				tb->sbytes[i] - 1, tb->S_new[i]);
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci		/*
104062306a36Sopenharmony_ci		 * Paste given directory entry to
104162306a36Sopenharmony_ci		 * directory item
104262306a36Sopenharmony_ci		 */
104362306a36Sopenharmony_ci		buffer_info_init_bh(tb, &bi, tb->S_new[i]);
104462306a36Sopenharmony_ci		leaf_paste_in_buffer(&bi, 0, tb->pos_in_item - entry_count +
104562306a36Sopenharmony_ci				     tb->sbytes[i] - 1, tb->insert_size[0],
104662306a36Sopenharmony_ci				     body, tb->zeroes_num);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci		/* paste new directory entry */
104962306a36Sopenharmony_ci		leaf_paste_entries(&bi, 0, tb->pos_in_item - entry_count +
105062306a36Sopenharmony_ci				   tb->sbytes[i] - 1, 1,
105162306a36Sopenharmony_ci				   (struct reiserfs_de_head *) body,
105262306a36Sopenharmony_ci				   body + DEH_SIZE, tb->insert_size[0]);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci		tb->insert_size[0] = 0;
105562306a36Sopenharmony_ci		tb->pos_in_item++;
105662306a36Sopenharmony_ci	} else {
105762306a36Sopenharmony_ci		/* new directory entry doesn't fall into S_new[i] */
105862306a36Sopenharmony_ci		leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, tb->snum[i],
105962306a36Sopenharmony_ci				tb->sbytes[i], tb->S_new[i]);
106062306a36Sopenharmony_ci	}
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_cistatic void balance_leaf_new_nodes_paste_shift(struct tree_balance *tb,
106562306a36Sopenharmony_ci					 struct item_head * const ih,
106662306a36Sopenharmony_ci					 const char * const body,
106762306a36Sopenharmony_ci					 struct item_head *insert_key,
106862306a36Sopenharmony_ci					 struct buffer_head **insert_ptr,
106962306a36Sopenharmony_ci					 int i)
107062306a36Sopenharmony_ci{
107162306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
107262306a36Sopenharmony_ci	struct item_head *aux_ih = item_head(tbS0, tb->item_pos);
107362306a36Sopenharmony_ci	int n_shift, n_rem, r_zeroes_number, shift;
107462306a36Sopenharmony_ci	const char *r_body;
107562306a36Sopenharmony_ci	struct item_head *tmp;
107662306a36Sopenharmony_ci	struct buffer_info bi;
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	RFALSE(ih, "PAP-12210: ih must be 0");
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	if (is_direntry_le_ih(aux_ih)) {
108162306a36Sopenharmony_ci		balance_leaf_new_nodes_paste_dirent(tb, ih, body, insert_key,
108262306a36Sopenharmony_ci						    insert_ptr, i);
108362306a36Sopenharmony_ci		return;
108462306a36Sopenharmony_ci	}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	/* regular object */
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	RFALSE(tb->pos_in_item != ih_item_len(item_head(tbS0, tb->item_pos)) ||
109062306a36Sopenharmony_ci	       tb->insert_size[0] <= 0,
109162306a36Sopenharmony_ci	       "PAP-12225: item too short or insert_size <= 0");
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	/*
109462306a36Sopenharmony_ci	 * Calculate number of bytes which must be shifted from appended item
109562306a36Sopenharmony_ci	 */
109662306a36Sopenharmony_ci	n_shift = tb->sbytes[i] - tb->insert_size[0];
109762306a36Sopenharmony_ci	if (n_shift < 0)
109862306a36Sopenharmony_ci		n_shift = 0;
109962306a36Sopenharmony_ci	leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, tb->snum[i], n_shift,
110062306a36Sopenharmony_ci			tb->S_new[i]);
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	/*
110362306a36Sopenharmony_ci	 * Calculate number of bytes which must remain in body after
110462306a36Sopenharmony_ci	 * append to S_new[i]
110562306a36Sopenharmony_ci	 */
110662306a36Sopenharmony_ci	n_rem = tb->insert_size[0] - tb->sbytes[i];
110762306a36Sopenharmony_ci	if (n_rem < 0)
110862306a36Sopenharmony_ci		n_rem = 0;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	/* Append part of body into S_new[0] */
111162306a36Sopenharmony_ci	buffer_info_init_bh(tb, &bi, tb->S_new[i]);
111262306a36Sopenharmony_ci	if (n_rem > tb->zeroes_num) {
111362306a36Sopenharmony_ci		r_zeroes_number = 0;
111462306a36Sopenharmony_ci		r_body = body + n_rem - tb->zeroes_num;
111562306a36Sopenharmony_ci	} else {
111662306a36Sopenharmony_ci		r_body = body;
111762306a36Sopenharmony_ci		r_zeroes_number = tb->zeroes_num - n_rem;
111862306a36Sopenharmony_ci		tb->zeroes_num -= r_zeroes_number;
111962306a36Sopenharmony_ci	}
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	leaf_paste_in_buffer(&bi, 0, n_shift, tb->insert_size[0] - n_rem,
112262306a36Sopenharmony_ci			     r_body, r_zeroes_number);
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	tmp = item_head(tb->S_new[i], 0);
112562306a36Sopenharmony_ci	shift = 0;
112662306a36Sopenharmony_ci	if (is_indirect_le_ih(tmp)) {
112762306a36Sopenharmony_ci		set_ih_free_space(tmp, 0);
112862306a36Sopenharmony_ci		shift = tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT;
112962306a36Sopenharmony_ci	}
113062306a36Sopenharmony_ci	add_le_ih_k_offset(tmp, n_rem << shift);
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	tb->insert_size[0] = n_rem;
113362306a36Sopenharmony_ci	if (!n_rem)
113462306a36Sopenharmony_ci		tb->pos_in_item++;
113562306a36Sopenharmony_ci}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_cistatic void balance_leaf_new_nodes_paste_whole(struct tree_balance *tb,
113862306a36Sopenharmony_ci					       struct item_head * const ih,
113962306a36Sopenharmony_ci					       const char * const body,
114062306a36Sopenharmony_ci					       struct item_head *insert_key,
114162306a36Sopenharmony_ci					       struct buffer_head **insert_ptr,
114262306a36Sopenharmony_ci					       int i)
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci{
114562306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
114662306a36Sopenharmony_ci	int n = B_NR_ITEMS(tbS0);
114762306a36Sopenharmony_ci	int leaf_mi;
114862306a36Sopenharmony_ci	struct item_head *pasted;
114962306a36Sopenharmony_ci	struct buffer_info bi;
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
115262306a36Sopenharmony_ci	struct item_head *ih_check = item_head(tbS0, tb->item_pos);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	if (!is_direntry_le_ih(ih_check) &&
115562306a36Sopenharmony_ci	    (tb->pos_in_item != ih_item_len(ih_check) ||
115662306a36Sopenharmony_ci	    tb->insert_size[0] <= 0))
115762306a36Sopenharmony_ci		reiserfs_panic(tb->tb_sb,
115862306a36Sopenharmony_ci			     "PAP-12235",
115962306a36Sopenharmony_ci			     "pos_in_item must be equal to ih_item_len");
116062306a36Sopenharmony_ci#endif
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	leaf_mi = leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, tb->snum[i],
116362306a36Sopenharmony_ci				  tb->sbytes[i], tb->S_new[i]);
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	RFALSE(leaf_mi,
116662306a36Sopenharmony_ci	       "PAP-12240: unexpected value returned by leaf_move_items (%d)",
116762306a36Sopenharmony_ci	       leaf_mi);
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	/* paste into item */
117062306a36Sopenharmony_ci	buffer_info_init_bh(tb, &bi, tb->S_new[i]);
117162306a36Sopenharmony_ci	leaf_paste_in_buffer(&bi, tb->item_pos - n + tb->snum[i],
117262306a36Sopenharmony_ci			     tb->pos_in_item, tb->insert_size[0],
117362306a36Sopenharmony_ci			     body, tb->zeroes_num);
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	pasted = item_head(tb->S_new[i], tb->item_pos - n +
117662306a36Sopenharmony_ci			   tb->snum[i]);
117762306a36Sopenharmony_ci	if (is_direntry_le_ih(pasted))
117862306a36Sopenharmony_ci		leaf_paste_entries(&bi, tb->item_pos - n + tb->snum[i],
117962306a36Sopenharmony_ci				   tb->pos_in_item, 1,
118062306a36Sopenharmony_ci				   (struct reiserfs_de_head *)body,
118162306a36Sopenharmony_ci				   body + DEH_SIZE, tb->insert_size[0]);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	/* if we paste to indirect item update ih_free_space */
118462306a36Sopenharmony_ci	if (is_indirect_le_ih(pasted))
118562306a36Sopenharmony_ci		set_ih_free_space(pasted, 0);
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	tb->zeroes_num = tb->insert_size[0] = 0;
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci}
119062306a36Sopenharmony_cistatic void balance_leaf_new_nodes_paste(struct tree_balance *tb,
119162306a36Sopenharmony_ci					 struct item_head * const ih,
119262306a36Sopenharmony_ci					 const char * const body,
119362306a36Sopenharmony_ci					 struct item_head *insert_key,
119462306a36Sopenharmony_ci					 struct buffer_head **insert_ptr,
119562306a36Sopenharmony_ci					 int i)
119662306a36Sopenharmony_ci{
119762306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
119862306a36Sopenharmony_ci	int n = B_NR_ITEMS(tbS0);
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	/* pasted item doesn't fall into S_new[i] */
120162306a36Sopenharmony_ci	if (n - tb->snum[i] > tb->item_pos) {
120262306a36Sopenharmony_ci		leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
120362306a36Sopenharmony_ci				tb->snum[i], tb->sbytes[i], tb->S_new[i]);
120462306a36Sopenharmony_ci		return;
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	/* pasted item or part if it falls to S_new[i] */
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	if (tb->item_pos == n - tb->snum[i] && tb->sbytes[i] != -1)
121062306a36Sopenharmony_ci		/* we must shift part of the appended item */
121162306a36Sopenharmony_ci		balance_leaf_new_nodes_paste_shift(tb, ih, body, insert_key,
121262306a36Sopenharmony_ci						   insert_ptr, i);
121362306a36Sopenharmony_ci	else
121462306a36Sopenharmony_ci		/* item falls wholly into S_new[i] */
121562306a36Sopenharmony_ci		balance_leaf_new_nodes_paste_whole(tb, ih, body, insert_key,
121662306a36Sopenharmony_ci						   insert_ptr, i);
121762306a36Sopenharmony_ci}
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci/* Fill new nodes that appear in place of S[0] */
122062306a36Sopenharmony_cistatic void balance_leaf_new_nodes(struct tree_balance *tb,
122162306a36Sopenharmony_ci				   struct item_head * const ih,
122262306a36Sopenharmony_ci				   const char * const body,
122362306a36Sopenharmony_ci				   struct item_head *insert_key,
122462306a36Sopenharmony_ci				   struct buffer_head **insert_ptr,
122562306a36Sopenharmony_ci				   int flag)
122662306a36Sopenharmony_ci{
122762306a36Sopenharmony_ci	int i;
122862306a36Sopenharmony_ci	for (i = tb->blknum[0] - 2; i >= 0; i--) {
122962306a36Sopenharmony_ci		BUG_ON(flag != M_INSERT && flag != M_PASTE);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci		RFALSE(!tb->snum[i],
123262306a36Sopenharmony_ci		       "PAP-12200: snum[%d] == %d. Must be > 0", i,
123362306a36Sopenharmony_ci		       tb->snum[i]);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci		/* here we shift from S to S_new nodes */
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci		tb->S_new[i] = get_FEB(tb);
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci		/* initialized block type and tree level */
124062306a36Sopenharmony_ci		set_blkh_level(B_BLK_HEAD(tb->S_new[i]), DISK_LEAF_NODE_LEVEL);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci		if (flag == M_INSERT)
124362306a36Sopenharmony_ci			balance_leaf_new_nodes_insert(tb, ih, body, insert_key,
124462306a36Sopenharmony_ci						      insert_ptr, i);
124562306a36Sopenharmony_ci		else /* M_PASTE */
124662306a36Sopenharmony_ci			balance_leaf_new_nodes_paste(tb, ih, body, insert_key,
124762306a36Sopenharmony_ci						     insert_ptr, i);
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci		memcpy(insert_key + i, leaf_key(tb->S_new[i], 0), KEY_SIZE);
125062306a36Sopenharmony_ci		insert_ptr[i] = tb->S_new[i];
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci		RFALSE(!buffer_journaled(tb->S_new[i])
125362306a36Sopenharmony_ci		       || buffer_journal_dirty(tb->S_new[i])
125462306a36Sopenharmony_ci		       || buffer_dirty(tb->S_new[i]),
125562306a36Sopenharmony_ci		       "PAP-12247: S_new[%d] : (%b)",
125662306a36Sopenharmony_ci		       i, tb->S_new[i]);
125762306a36Sopenharmony_ci	}
125862306a36Sopenharmony_ci}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_cistatic void balance_leaf_finish_node_insert(struct tree_balance *tb,
126162306a36Sopenharmony_ci					    struct item_head * const ih,
126262306a36Sopenharmony_ci					    const char * const body)
126362306a36Sopenharmony_ci{
126462306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
126562306a36Sopenharmony_ci	struct buffer_info bi;
126662306a36Sopenharmony_ci	buffer_info_init_tbS0(tb, &bi);
126762306a36Sopenharmony_ci	leaf_insert_into_buf(&bi, tb->item_pos, ih, body, tb->zeroes_num);
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	/* If we insert the first key change the delimiting key */
127062306a36Sopenharmony_ci	if (tb->item_pos == 0) {
127162306a36Sopenharmony_ci		if (tb->CFL[0])	/* can be 0 in reiserfsck */
127262306a36Sopenharmony_ci			replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	}
127562306a36Sopenharmony_ci}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_cistatic void balance_leaf_finish_node_paste_dirent(struct tree_balance *tb,
127862306a36Sopenharmony_ci						  struct item_head * const ih,
127962306a36Sopenharmony_ci						  const char * const body)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
128262306a36Sopenharmony_ci	struct item_head *pasted = item_head(tbS0, tb->item_pos);
128362306a36Sopenharmony_ci	struct buffer_info bi;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	if (tb->pos_in_item >= 0 && tb->pos_in_item <= ih_entry_count(pasted)) {
128662306a36Sopenharmony_ci		RFALSE(!tb->insert_size[0],
128762306a36Sopenharmony_ci		       "PAP-12260: insert_size is 0 already");
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci		/* prepare space */
129062306a36Sopenharmony_ci		buffer_info_init_tbS0(tb, &bi);
129162306a36Sopenharmony_ci		leaf_paste_in_buffer(&bi, tb->item_pos, tb->pos_in_item,
129262306a36Sopenharmony_ci				     tb->insert_size[0], body, tb->zeroes_num);
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci		/* paste entry */
129562306a36Sopenharmony_ci		leaf_paste_entries(&bi, tb->item_pos, tb->pos_in_item, 1,
129662306a36Sopenharmony_ci				   (struct reiserfs_de_head *)body,
129762306a36Sopenharmony_ci				   body + DEH_SIZE, tb->insert_size[0]);
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci		if (!tb->item_pos && !tb->pos_in_item) {
130062306a36Sopenharmony_ci			RFALSE(!tb->CFL[0] || !tb->L[0],
130162306a36Sopenharmony_ci			       "PAP-12270: CFL[0]/L[0] must  be specified");
130262306a36Sopenharmony_ci			if (tb->CFL[0])
130362306a36Sopenharmony_ci				replace_key(tb, tb->CFL[0], tb->lkey[0],
130462306a36Sopenharmony_ci					    tbS0, 0);
130562306a36Sopenharmony_ci		}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci		tb->insert_size[0] = 0;
130862306a36Sopenharmony_ci	}
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_cistatic void balance_leaf_finish_node_paste(struct tree_balance *tb,
131262306a36Sopenharmony_ci					   struct item_head * const ih,
131362306a36Sopenharmony_ci					   const char * const body)
131462306a36Sopenharmony_ci{
131562306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
131662306a36Sopenharmony_ci	struct buffer_info bi;
131762306a36Sopenharmony_ci	struct item_head *pasted = item_head(tbS0, tb->item_pos);
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	/* when directory, may be new entry already pasted */
132062306a36Sopenharmony_ci	if (is_direntry_le_ih(pasted)) {
132162306a36Sopenharmony_ci		balance_leaf_finish_node_paste_dirent(tb, ih, body);
132262306a36Sopenharmony_ci		return;
132362306a36Sopenharmony_ci	}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	/* regular object */
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	if (tb->pos_in_item == ih_item_len(pasted)) {
132862306a36Sopenharmony_ci		RFALSE(tb->insert_size[0] <= 0,
132962306a36Sopenharmony_ci		       "PAP-12275: insert size must not be %d",
133062306a36Sopenharmony_ci		       tb->insert_size[0]);
133162306a36Sopenharmony_ci		buffer_info_init_tbS0(tb, &bi);
133262306a36Sopenharmony_ci		leaf_paste_in_buffer(&bi, tb->item_pos,
133362306a36Sopenharmony_ci				     tb->pos_in_item, tb->insert_size[0], body,
133462306a36Sopenharmony_ci				     tb->zeroes_num);
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci		if (is_indirect_le_ih(pasted))
133762306a36Sopenharmony_ci			set_ih_free_space(pasted, 0);
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci		tb->insert_size[0] = 0;
134062306a36Sopenharmony_ci	}
134162306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
134262306a36Sopenharmony_ci	else if (tb->insert_size[0]) {
134362306a36Sopenharmony_ci		print_cur_tb("12285");
134462306a36Sopenharmony_ci		reiserfs_panic(tb->tb_sb, "PAP-12285",
134562306a36Sopenharmony_ci		    "insert_size must be 0 (%d)", tb->insert_size[0]);
134662306a36Sopenharmony_ci	}
134762306a36Sopenharmony_ci#endif
134862306a36Sopenharmony_ci}
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci/*
135162306a36Sopenharmony_ci * if the affected item was not wholly shifted then we
135262306a36Sopenharmony_ci * perform all necessary operations on that part or whole
135362306a36Sopenharmony_ci * of the affected item which remains in S
135462306a36Sopenharmony_ci */
135562306a36Sopenharmony_cistatic void balance_leaf_finish_node(struct tree_balance *tb,
135662306a36Sopenharmony_ci				      struct item_head * const ih,
135762306a36Sopenharmony_ci				      const char * const body, int flag)
135862306a36Sopenharmony_ci{
135962306a36Sopenharmony_ci	/* if we must insert or append into buffer S[0] */
136062306a36Sopenharmony_ci	if (0 <= tb->item_pos && tb->item_pos < tb->s0num) {
136162306a36Sopenharmony_ci		if (flag == M_INSERT)
136262306a36Sopenharmony_ci			balance_leaf_finish_node_insert(tb, ih, body);
136362306a36Sopenharmony_ci		else /* M_PASTE */
136462306a36Sopenharmony_ci			balance_leaf_finish_node_paste(tb, ih, body);
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci}
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci/**
136962306a36Sopenharmony_ci * balance_leaf - reiserfs tree balancing algorithm
137062306a36Sopenharmony_ci * @tb: tree balance state
137162306a36Sopenharmony_ci * @ih: item header of inserted item (little endian)
137262306a36Sopenharmony_ci * @body: body of inserted item or bytes to paste
137362306a36Sopenharmony_ci * @flag: i - insert, d - delete, c - cut, p - paste (see do_balance)
137462306a36Sopenharmony_ci * passed back:
137562306a36Sopenharmony_ci * @insert_key: key to insert new nodes
137662306a36Sopenharmony_ci * @insert_ptr: array of nodes to insert at the next level
137762306a36Sopenharmony_ci *
137862306a36Sopenharmony_ci * In our processing of one level we sometimes determine what must be
137962306a36Sopenharmony_ci * inserted into the next higher level.  This insertion consists of a
138062306a36Sopenharmony_ci * key or two keys and their corresponding pointers.
138162306a36Sopenharmony_ci */
138262306a36Sopenharmony_cistatic int balance_leaf(struct tree_balance *tb, struct item_head *ih,
138362306a36Sopenharmony_ci			const char *body, int flag,
138462306a36Sopenharmony_ci			struct item_head *insert_key,
138562306a36Sopenharmony_ci			struct buffer_head **insert_ptr)
138662306a36Sopenharmony_ci{
138762306a36Sopenharmony_ci	struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	PROC_INFO_INC(tb->tb_sb, balance_at[0]);
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	/* Make balance in case insert_size[0] < 0 */
139262306a36Sopenharmony_ci	if (tb->insert_size[0] < 0)
139362306a36Sopenharmony_ci		return balance_leaf_when_delete(tb, flag);
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	tb->item_pos = PATH_LAST_POSITION(tb->tb_path),
139662306a36Sopenharmony_ci	tb->pos_in_item = tb->tb_path->pos_in_item,
139762306a36Sopenharmony_ci	tb->zeroes_num = 0;
139862306a36Sopenharmony_ci	if (flag == M_INSERT && !body)
139962306a36Sopenharmony_ci		tb->zeroes_num = ih_item_len(ih);
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	/*
140262306a36Sopenharmony_ci	 * for indirect item pos_in_item is measured in unformatted node
140362306a36Sopenharmony_ci	 * pointers. Recalculate to bytes
140462306a36Sopenharmony_ci	 */
140562306a36Sopenharmony_ci	if (flag != M_INSERT
140662306a36Sopenharmony_ci	    && is_indirect_le_ih(item_head(tbS0, tb->item_pos)))
140762306a36Sopenharmony_ci		tb->pos_in_item *= UNFM_P_SIZE;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	body += balance_leaf_left(tb, ih, body, flag);
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	/* tb->lnum[0] > 0 */
141262306a36Sopenharmony_ci	/* Calculate new item position */
141362306a36Sopenharmony_ci	tb->item_pos -= (tb->lnum[0] - ((tb->lbytes != -1) ? 1 : 0));
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	balance_leaf_right(tb, ih, body, flag);
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	/* tb->rnum[0] > 0 */
141862306a36Sopenharmony_ci	RFALSE(tb->blknum[0] > 3,
141962306a36Sopenharmony_ci	       "PAP-12180: blknum can not be %d. It must be <= 3", tb->blknum[0]);
142062306a36Sopenharmony_ci	RFALSE(tb->blknum[0] < 0,
142162306a36Sopenharmony_ci	       "PAP-12185: blknum can not be %d. It must be >= 0", tb->blknum[0]);
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	/*
142462306a36Sopenharmony_ci	 * if while adding to a node we discover that it is possible to split
142562306a36Sopenharmony_ci	 * it in two, and merge the left part into the left neighbor and the
142662306a36Sopenharmony_ci	 * right part into the right neighbor, eliminating the node
142762306a36Sopenharmony_ci	 */
142862306a36Sopenharmony_ci	if (tb->blknum[0] == 0) {	/* node S[0] is empty now */
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci		RFALSE(!tb->lnum[0] || !tb->rnum[0],
143162306a36Sopenharmony_ci		       "PAP-12190: lnum and rnum must not be zero");
143262306a36Sopenharmony_ci		/*
143362306a36Sopenharmony_ci		 * if insertion was done before 0-th position in R[0], right
143462306a36Sopenharmony_ci		 * delimiting key of the tb->L[0]'s and left delimiting key are
143562306a36Sopenharmony_ci		 * not set correctly
143662306a36Sopenharmony_ci		 */
143762306a36Sopenharmony_ci		if (tb->CFL[0]) {
143862306a36Sopenharmony_ci			if (!tb->CFR[0])
143962306a36Sopenharmony_ci				reiserfs_panic(tb->tb_sb, "vs-12195",
144062306a36Sopenharmony_ci					       "CFR not initialized");
144162306a36Sopenharmony_ci			copy_key(internal_key(tb->CFL[0], tb->lkey[0]),
144262306a36Sopenharmony_ci				 internal_key(tb->CFR[0], tb->rkey[0]));
144362306a36Sopenharmony_ci			do_balance_mark_internal_dirty(tb, tb->CFL[0], 0);
144462306a36Sopenharmony_ci		}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci		reiserfs_invalidate_buffer(tb, tbS0);
144762306a36Sopenharmony_ci		return 0;
144862306a36Sopenharmony_ci	}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	balance_leaf_new_nodes(tb, ih, body, insert_key, insert_ptr, flag);
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	balance_leaf_finish_node(tb, ih, body, flag);
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
145562306a36Sopenharmony_ci	if (flag == M_PASTE && tb->insert_size[0]) {
145662306a36Sopenharmony_ci		print_cur_tb("12290");
145762306a36Sopenharmony_ci		reiserfs_panic(tb->tb_sb,
145862306a36Sopenharmony_ci			       "PAP-12290", "insert_size is still not 0 (%d)",
145962306a36Sopenharmony_ci			       tb->insert_size[0]);
146062306a36Sopenharmony_ci	}
146162306a36Sopenharmony_ci#endif
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	/* Leaf level of the tree is balanced (end of balance_leaf) */
146462306a36Sopenharmony_ci	return 0;
146562306a36Sopenharmony_ci}
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci/* Make empty node */
146862306a36Sopenharmony_civoid make_empty_node(struct buffer_info *bi)
146962306a36Sopenharmony_ci{
147062306a36Sopenharmony_ci	struct block_head *blkh;
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	RFALSE(bi->bi_bh == NULL, "PAP-12295: pointer to the buffer is NULL");
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	blkh = B_BLK_HEAD(bi->bi_bh);
147562306a36Sopenharmony_ci	set_blkh_nr_item(blkh, 0);
147662306a36Sopenharmony_ci	set_blkh_free_space(blkh, MAX_CHILD_SIZE(bi->bi_bh));
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	if (bi->bi_parent)
147962306a36Sopenharmony_ci		B_N_CHILD(bi->bi_parent, bi->bi_position)->dc_size = 0;	/* Endian safe if 0 */
148062306a36Sopenharmony_ci}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci/* Get first empty buffer */
148362306a36Sopenharmony_cistruct buffer_head *get_FEB(struct tree_balance *tb)
148462306a36Sopenharmony_ci{
148562306a36Sopenharmony_ci	int i;
148662306a36Sopenharmony_ci	struct buffer_info bi;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	for (i = 0; i < MAX_FEB_SIZE; i++)
148962306a36Sopenharmony_ci		if (tb->FEB[i] != NULL)
149062306a36Sopenharmony_ci			break;
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	if (i == MAX_FEB_SIZE)
149362306a36Sopenharmony_ci		reiserfs_panic(tb->tb_sb, "vs-12300", "FEB list is empty");
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	buffer_info_init_bh(tb, &bi, tb->FEB[i]);
149662306a36Sopenharmony_ci	make_empty_node(&bi);
149762306a36Sopenharmony_ci	set_buffer_uptodate(tb->FEB[i]);
149862306a36Sopenharmony_ci	tb->used[i] = tb->FEB[i];
149962306a36Sopenharmony_ci	tb->FEB[i] = NULL;
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	return tb->used[i];
150262306a36Sopenharmony_ci}
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ci/* This is now used because reiserfs_free_block has to be able to schedule. */
150562306a36Sopenharmony_cistatic void store_thrown(struct tree_balance *tb, struct buffer_head *bh)
150662306a36Sopenharmony_ci{
150762306a36Sopenharmony_ci	int i;
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci	if (buffer_dirty(bh))
151062306a36Sopenharmony_ci		reiserfs_warning(tb->tb_sb, "reiserfs-12320",
151162306a36Sopenharmony_ci				 "called with dirty buffer");
151262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tb->thrown); i++)
151362306a36Sopenharmony_ci		if (!tb->thrown[i]) {
151462306a36Sopenharmony_ci			tb->thrown[i] = bh;
151562306a36Sopenharmony_ci			get_bh(bh);	/* free_thrown puts this */
151662306a36Sopenharmony_ci			return;
151762306a36Sopenharmony_ci		}
151862306a36Sopenharmony_ci	reiserfs_warning(tb->tb_sb, "reiserfs-12321",
151962306a36Sopenharmony_ci			 "too many thrown buffers");
152062306a36Sopenharmony_ci}
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_cistatic void free_thrown(struct tree_balance *tb)
152362306a36Sopenharmony_ci{
152462306a36Sopenharmony_ci	int i;
152562306a36Sopenharmony_ci	b_blocknr_t blocknr;
152662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tb->thrown); i++) {
152762306a36Sopenharmony_ci		if (tb->thrown[i]) {
152862306a36Sopenharmony_ci			blocknr = tb->thrown[i]->b_blocknr;
152962306a36Sopenharmony_ci			if (buffer_dirty(tb->thrown[i]))
153062306a36Sopenharmony_ci				reiserfs_warning(tb->tb_sb, "reiserfs-12322",
153162306a36Sopenharmony_ci						 "called with dirty buffer %d",
153262306a36Sopenharmony_ci						 blocknr);
153362306a36Sopenharmony_ci			brelse(tb->thrown[i]);	/* incremented in store_thrown */
153462306a36Sopenharmony_ci			reiserfs_free_block(tb->transaction_handle, NULL,
153562306a36Sopenharmony_ci					    blocknr, 0);
153662306a36Sopenharmony_ci		}
153762306a36Sopenharmony_ci	}
153862306a36Sopenharmony_ci}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_civoid reiserfs_invalidate_buffer(struct tree_balance *tb, struct buffer_head *bh)
154162306a36Sopenharmony_ci{
154262306a36Sopenharmony_ci	struct block_head *blkh;
154362306a36Sopenharmony_ci	blkh = B_BLK_HEAD(bh);
154462306a36Sopenharmony_ci	set_blkh_level(blkh, FREE_LEVEL);
154562306a36Sopenharmony_ci	set_blkh_nr_item(blkh, 0);
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	clear_buffer_dirty(bh);
154862306a36Sopenharmony_ci	store_thrown(tb, bh);
154962306a36Sopenharmony_ci}
155062306a36Sopenharmony_ci
155162306a36Sopenharmony_ci/* Replace n_dest'th key in buffer dest by n_src'th key of buffer src.*/
155262306a36Sopenharmony_civoid replace_key(struct tree_balance *tb, struct buffer_head *dest, int n_dest,
155362306a36Sopenharmony_ci		 struct buffer_head *src, int n_src)
155462306a36Sopenharmony_ci{
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	RFALSE(dest == NULL || src == NULL,
155762306a36Sopenharmony_ci	       "vs-12305: source or destination buffer is 0 (src=%p, dest=%p)",
155862306a36Sopenharmony_ci	       src, dest);
155962306a36Sopenharmony_ci	RFALSE(!B_IS_KEYS_LEVEL(dest),
156062306a36Sopenharmony_ci	       "vs-12310: invalid level (%z) for destination buffer. dest must be leaf",
156162306a36Sopenharmony_ci	       dest);
156262306a36Sopenharmony_ci	RFALSE(n_dest < 0 || n_src < 0,
156362306a36Sopenharmony_ci	       "vs-12315: src(%d) or dest(%d) key number < 0", n_src, n_dest);
156462306a36Sopenharmony_ci	RFALSE(n_dest >= B_NR_ITEMS(dest) || n_src >= B_NR_ITEMS(src),
156562306a36Sopenharmony_ci	       "vs-12320: src(%d(%d)) or dest(%d(%d)) key number is too big",
156662306a36Sopenharmony_ci	       n_src, B_NR_ITEMS(src), n_dest, B_NR_ITEMS(dest));
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	if (B_IS_ITEMS_LEVEL(src))
156962306a36Sopenharmony_ci		/* source buffer contains leaf node */
157062306a36Sopenharmony_ci		memcpy(internal_key(dest, n_dest), item_head(src, n_src),
157162306a36Sopenharmony_ci		       KEY_SIZE);
157262306a36Sopenharmony_ci	else
157362306a36Sopenharmony_ci		memcpy(internal_key(dest, n_dest), internal_key(src, n_src),
157462306a36Sopenharmony_ci		       KEY_SIZE);
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	do_balance_mark_internal_dirty(tb, dest, 0);
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ciint get_left_neighbor_position(struct tree_balance *tb, int h)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci	int Sh_position = PATH_H_POSITION(tb->tb_path, h + 1);
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	RFALSE(PATH_H_PPARENT(tb->tb_path, h) == NULL || tb->FL[h] == NULL,
158462306a36Sopenharmony_ci	       "vs-12325: FL[%d](%p) or F[%d](%p) does not exist",
158562306a36Sopenharmony_ci	       h, tb->FL[h], h, PATH_H_PPARENT(tb->tb_path, h));
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	if (Sh_position == 0)
158862306a36Sopenharmony_ci		return B_NR_ITEMS(tb->FL[h]);
158962306a36Sopenharmony_ci	else
159062306a36Sopenharmony_ci		return Sh_position - 1;
159162306a36Sopenharmony_ci}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ciint get_right_neighbor_position(struct tree_balance *tb, int h)
159462306a36Sopenharmony_ci{
159562306a36Sopenharmony_ci	int Sh_position = PATH_H_POSITION(tb->tb_path, h + 1);
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	RFALSE(PATH_H_PPARENT(tb->tb_path, h) == NULL || tb->FR[h] == NULL,
159862306a36Sopenharmony_ci	       "vs-12330: F[%d](%p) or FR[%d](%p) does not exist",
159962306a36Sopenharmony_ci	       h, PATH_H_PPARENT(tb->tb_path, h), h, tb->FR[h]);
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	if (Sh_position == B_NR_ITEMS(PATH_H_PPARENT(tb->tb_path, h)))
160262306a36Sopenharmony_ci		return 0;
160362306a36Sopenharmony_ci	else
160462306a36Sopenharmony_ci		return Sh_position + 1;
160562306a36Sopenharmony_ci}
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ciint is_reusable(struct super_block *s, b_blocknr_t block, int bit_value);
161062306a36Sopenharmony_cistatic void check_internal_node(struct super_block *s, struct buffer_head *bh,
161162306a36Sopenharmony_ci				char *mes)
161262306a36Sopenharmony_ci{
161362306a36Sopenharmony_ci	struct disk_child *dc;
161462306a36Sopenharmony_ci	int i;
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	RFALSE(!bh, "PAP-12336: bh == 0");
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci	if (!bh || !B_IS_IN_TREE(bh))
161962306a36Sopenharmony_ci		return;
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	RFALSE(!buffer_dirty(bh) &&
162262306a36Sopenharmony_ci	       !(buffer_journaled(bh) || buffer_journal_dirty(bh)),
162362306a36Sopenharmony_ci	       "PAP-12337: buffer (%b) must be dirty", bh);
162462306a36Sopenharmony_ci	dc = B_N_CHILD(bh, 0);
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	for (i = 0; i <= B_NR_ITEMS(bh); i++, dc++) {
162762306a36Sopenharmony_ci		if (!is_reusable(s, dc_block_number(dc), 1)) {
162862306a36Sopenharmony_ci			print_cur_tb(mes);
162962306a36Sopenharmony_ci			reiserfs_panic(s, "PAP-12338",
163062306a36Sopenharmony_ci				       "invalid child pointer %y in %b",
163162306a36Sopenharmony_ci				       dc, bh);
163262306a36Sopenharmony_ci		}
163362306a36Sopenharmony_ci	}
163462306a36Sopenharmony_ci}
163562306a36Sopenharmony_ci
163662306a36Sopenharmony_cistatic int locked_or_not_in_tree(struct tree_balance *tb,
163762306a36Sopenharmony_ci				  struct buffer_head *bh, char *which)
163862306a36Sopenharmony_ci{
163962306a36Sopenharmony_ci	if ((!buffer_journal_prepared(bh) && buffer_locked(bh)) ||
164062306a36Sopenharmony_ci	    !B_IS_IN_TREE(bh)) {
164162306a36Sopenharmony_ci		reiserfs_warning(tb->tb_sb, "vs-12339", "%s (%b)", which, bh);
164262306a36Sopenharmony_ci		return 1;
164362306a36Sopenharmony_ci	}
164462306a36Sopenharmony_ci	return 0;
164562306a36Sopenharmony_ci}
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_cistatic int check_before_balancing(struct tree_balance *tb)
164862306a36Sopenharmony_ci{
164962306a36Sopenharmony_ci	int retval = 0;
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	if (REISERFS_SB(tb->tb_sb)->cur_tb) {
165262306a36Sopenharmony_ci		reiserfs_panic(tb->tb_sb, "vs-12335", "suspect that schedule "
165362306a36Sopenharmony_ci			       "occurred based on cur_tb not being null at "
165462306a36Sopenharmony_ci			       "this point in code. do_balance cannot properly "
165562306a36Sopenharmony_ci			       "handle concurrent tree accesses on a same "
165662306a36Sopenharmony_ci			       "mount point.");
165762306a36Sopenharmony_ci	}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	/*
166062306a36Sopenharmony_ci	 * double check that buffers that we will modify are unlocked.
166162306a36Sopenharmony_ci	 * (fix_nodes should already have prepped all of these for us).
166262306a36Sopenharmony_ci	 */
166362306a36Sopenharmony_ci	if (tb->lnum[0]) {
166462306a36Sopenharmony_ci		retval |= locked_or_not_in_tree(tb, tb->L[0], "L[0]");
166562306a36Sopenharmony_ci		retval |= locked_or_not_in_tree(tb, tb->FL[0], "FL[0]");
166662306a36Sopenharmony_ci		retval |= locked_or_not_in_tree(tb, tb->CFL[0], "CFL[0]");
166762306a36Sopenharmony_ci		check_leaf(tb->L[0]);
166862306a36Sopenharmony_ci	}
166962306a36Sopenharmony_ci	if (tb->rnum[0]) {
167062306a36Sopenharmony_ci		retval |= locked_or_not_in_tree(tb, tb->R[0], "R[0]");
167162306a36Sopenharmony_ci		retval |= locked_or_not_in_tree(tb, tb->FR[0], "FR[0]");
167262306a36Sopenharmony_ci		retval |= locked_or_not_in_tree(tb, tb->CFR[0], "CFR[0]");
167362306a36Sopenharmony_ci		check_leaf(tb->R[0]);
167462306a36Sopenharmony_ci	}
167562306a36Sopenharmony_ci	retval |= locked_or_not_in_tree(tb, PATH_PLAST_BUFFER(tb->tb_path),
167662306a36Sopenharmony_ci					"S[0]");
167762306a36Sopenharmony_ci	check_leaf(PATH_PLAST_BUFFER(tb->tb_path));
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	return retval;
168062306a36Sopenharmony_ci}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_cistatic void check_after_balance_leaf(struct tree_balance *tb)
168362306a36Sopenharmony_ci{
168462306a36Sopenharmony_ci	if (tb->lnum[0]) {
168562306a36Sopenharmony_ci		if (B_FREE_SPACE(tb->L[0]) !=
168662306a36Sopenharmony_ci		    MAX_CHILD_SIZE(tb->L[0]) -
168762306a36Sopenharmony_ci		    dc_size(B_N_CHILD
168862306a36Sopenharmony_ci			    (tb->FL[0], get_left_neighbor_position(tb, 0)))) {
168962306a36Sopenharmony_ci			print_cur_tb("12221");
169062306a36Sopenharmony_ci			reiserfs_panic(tb->tb_sb, "PAP-12355",
169162306a36Sopenharmony_ci				       "shift to left was incorrect");
169262306a36Sopenharmony_ci		}
169362306a36Sopenharmony_ci	}
169462306a36Sopenharmony_ci	if (tb->rnum[0]) {
169562306a36Sopenharmony_ci		if (B_FREE_SPACE(tb->R[0]) !=
169662306a36Sopenharmony_ci		    MAX_CHILD_SIZE(tb->R[0]) -
169762306a36Sopenharmony_ci		    dc_size(B_N_CHILD
169862306a36Sopenharmony_ci			    (tb->FR[0], get_right_neighbor_position(tb, 0)))) {
169962306a36Sopenharmony_ci			print_cur_tb("12222");
170062306a36Sopenharmony_ci			reiserfs_panic(tb->tb_sb, "PAP-12360",
170162306a36Sopenharmony_ci				       "shift to right was incorrect");
170262306a36Sopenharmony_ci		}
170362306a36Sopenharmony_ci	}
170462306a36Sopenharmony_ci	if (PATH_H_PBUFFER(tb->tb_path, 1) &&
170562306a36Sopenharmony_ci	    (B_FREE_SPACE(PATH_H_PBUFFER(tb->tb_path, 0)) !=
170662306a36Sopenharmony_ci	     (MAX_CHILD_SIZE(PATH_H_PBUFFER(tb->tb_path, 0)) -
170762306a36Sopenharmony_ci	      dc_size(B_N_CHILD(PATH_H_PBUFFER(tb->tb_path, 1),
170862306a36Sopenharmony_ci				PATH_H_POSITION(tb->tb_path, 1)))))) {
170962306a36Sopenharmony_ci		int left = B_FREE_SPACE(PATH_H_PBUFFER(tb->tb_path, 0));
171062306a36Sopenharmony_ci		int right = (MAX_CHILD_SIZE(PATH_H_PBUFFER(tb->tb_path, 0)) -
171162306a36Sopenharmony_ci			     dc_size(B_N_CHILD(PATH_H_PBUFFER(tb->tb_path, 1),
171262306a36Sopenharmony_ci					       PATH_H_POSITION(tb->tb_path,
171362306a36Sopenharmony_ci							       1))));
171462306a36Sopenharmony_ci		print_cur_tb("12223");
171562306a36Sopenharmony_ci		reiserfs_warning(tb->tb_sb, "reiserfs-12363",
171662306a36Sopenharmony_ci				 "B_FREE_SPACE (PATH_H_PBUFFER(tb->tb_path,0)) = %d; "
171762306a36Sopenharmony_ci				 "MAX_CHILD_SIZE (%d) - dc_size( %y, %d ) [%d] = %d",
171862306a36Sopenharmony_ci				 left,
171962306a36Sopenharmony_ci				 MAX_CHILD_SIZE(PATH_H_PBUFFER(tb->tb_path, 0)),
172062306a36Sopenharmony_ci				 PATH_H_PBUFFER(tb->tb_path, 1),
172162306a36Sopenharmony_ci				 PATH_H_POSITION(tb->tb_path, 1),
172262306a36Sopenharmony_ci				 dc_size(B_N_CHILD
172362306a36Sopenharmony_ci					 (PATH_H_PBUFFER(tb->tb_path, 1),
172462306a36Sopenharmony_ci					  PATH_H_POSITION(tb->tb_path, 1))),
172562306a36Sopenharmony_ci				 right);
172662306a36Sopenharmony_ci		reiserfs_panic(tb->tb_sb, "PAP-12365", "S is incorrect");
172762306a36Sopenharmony_ci	}
172862306a36Sopenharmony_ci}
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_cistatic void check_leaf_level(struct tree_balance *tb)
173162306a36Sopenharmony_ci{
173262306a36Sopenharmony_ci	check_leaf(tb->L[0]);
173362306a36Sopenharmony_ci	check_leaf(tb->R[0]);
173462306a36Sopenharmony_ci	check_leaf(PATH_PLAST_BUFFER(tb->tb_path));
173562306a36Sopenharmony_ci}
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_cistatic void check_internal_levels(struct tree_balance *tb)
173862306a36Sopenharmony_ci{
173962306a36Sopenharmony_ci	int h;
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	/* check all internal nodes */
174262306a36Sopenharmony_ci	for (h = 1; tb->insert_size[h]; h++) {
174362306a36Sopenharmony_ci		check_internal_node(tb->tb_sb, PATH_H_PBUFFER(tb->tb_path, h),
174462306a36Sopenharmony_ci				    "BAD BUFFER ON PATH");
174562306a36Sopenharmony_ci		if (tb->lnum[h])
174662306a36Sopenharmony_ci			check_internal_node(tb->tb_sb, tb->L[h], "BAD L");
174762306a36Sopenharmony_ci		if (tb->rnum[h])
174862306a36Sopenharmony_ci			check_internal_node(tb->tb_sb, tb->R[h], "BAD R");
174962306a36Sopenharmony_ci	}
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_ci#endif
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci/*
175662306a36Sopenharmony_ci * Now we have all of the buffers that must be used in balancing of
175762306a36Sopenharmony_ci * the tree.  We rely on the assumption that schedule() will not occur
175862306a36Sopenharmony_ci * while do_balance works. ( Only interrupt handlers are acceptable.)
175962306a36Sopenharmony_ci * We balance the tree according to the analysis made before this,
176062306a36Sopenharmony_ci * using buffers already obtained.  For SMP support it will someday be
176162306a36Sopenharmony_ci * necessary to add ordered locking of tb.
176262306a36Sopenharmony_ci */
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci/*
176562306a36Sopenharmony_ci * Some interesting rules of balancing:
176662306a36Sopenharmony_ci * we delete a maximum of two nodes per level per balancing: we never
176762306a36Sopenharmony_ci * delete R, when we delete two of three nodes L, S, R then we move
176862306a36Sopenharmony_ci * them into R.
176962306a36Sopenharmony_ci *
177062306a36Sopenharmony_ci * we only delete L if we are deleting two nodes, if we delete only
177162306a36Sopenharmony_ci * one node we delete S
177262306a36Sopenharmony_ci *
177362306a36Sopenharmony_ci * if we shift leaves then we shift as much as we can: this is a
177462306a36Sopenharmony_ci * deliberate policy of extremism in node packing which results in
177562306a36Sopenharmony_ci * higher average utilization after repeated random balance operations
177662306a36Sopenharmony_ci * at the cost of more memory copies and more balancing as a result of
177762306a36Sopenharmony_ci * small insertions to full nodes.
177862306a36Sopenharmony_ci *
177962306a36Sopenharmony_ci * if we shift internal nodes we try to evenly balance the node
178062306a36Sopenharmony_ci * utilization, with consequent less balancing at the cost of lower
178162306a36Sopenharmony_ci * utilization.
178262306a36Sopenharmony_ci *
178362306a36Sopenharmony_ci * one could argue that the policy for directories in leaves should be
178462306a36Sopenharmony_ci * that of internal nodes, but we will wait until another day to
178562306a36Sopenharmony_ci * evaluate this....  It would be nice to someday measure and prove
178662306a36Sopenharmony_ci * these assumptions as to what is optimal....
178762306a36Sopenharmony_ci */
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_cistatic inline void do_balance_starts(struct tree_balance *tb)
179062306a36Sopenharmony_ci{
179162306a36Sopenharmony_ci	/* use print_cur_tb() to see initial state of struct tree_balance */
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	/* store_print_tb (tb); */
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci	/* do not delete, just comment it out */
179662306a36Sopenharmony_ci	/*
179762306a36Sopenharmony_ci	print_tb(flag, PATH_LAST_POSITION(tb->tb_path),
179862306a36Sopenharmony_ci		 tb->tb_path->pos_in_item, tb, "check");
179962306a36Sopenharmony_ci	*/
180062306a36Sopenharmony_ci	RFALSE(check_before_balancing(tb), "PAP-12340: locked buffers in TB");
180162306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
180262306a36Sopenharmony_ci	REISERFS_SB(tb->tb_sb)->cur_tb = tb;
180362306a36Sopenharmony_ci#endif
180462306a36Sopenharmony_ci}
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_cistatic inline void do_balance_completed(struct tree_balance *tb)
180762306a36Sopenharmony_ci{
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
181062306a36Sopenharmony_ci	check_leaf_level(tb);
181162306a36Sopenharmony_ci	check_internal_levels(tb);
181262306a36Sopenharmony_ci	REISERFS_SB(tb->tb_sb)->cur_tb = NULL;
181362306a36Sopenharmony_ci#endif
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	/*
181662306a36Sopenharmony_ci	 * reiserfs_free_block is no longer schedule safe.  So, we need to
181762306a36Sopenharmony_ci	 * put the buffers we want freed on the thrown list during do_balance,
181862306a36Sopenharmony_ci	 * and then free them now
181962306a36Sopenharmony_ci	 */
182062306a36Sopenharmony_ci
182162306a36Sopenharmony_ci	REISERFS_SB(tb->tb_sb)->s_do_balance++;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	/* release all nodes hold to perform the balancing */
182462306a36Sopenharmony_ci	unfix_nodes(tb);
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	free_thrown(tb);
182762306a36Sopenharmony_ci}
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci/*
183062306a36Sopenharmony_ci * do_balance - balance the tree
183162306a36Sopenharmony_ci *
183262306a36Sopenharmony_ci * @tb: tree_balance structure
183362306a36Sopenharmony_ci * @ih: item header of inserted item
183462306a36Sopenharmony_ci * @body: body of inserted item or bytes to paste
183562306a36Sopenharmony_ci * @flag: 'i' - insert, 'd' - delete, 'c' - cut, 'p' paste
183662306a36Sopenharmony_ci *
183762306a36Sopenharmony_ci * Cut means delete part of an item (includes removing an entry from a
183862306a36Sopenharmony_ci * directory).
183962306a36Sopenharmony_ci *
184062306a36Sopenharmony_ci * Delete means delete whole item.
184162306a36Sopenharmony_ci *
184262306a36Sopenharmony_ci * Insert means add a new item into the tree.
184362306a36Sopenharmony_ci *
184462306a36Sopenharmony_ci * Paste means to append to the end of an existing file or to
184562306a36Sopenharmony_ci * insert a directory entry.
184662306a36Sopenharmony_ci */
184762306a36Sopenharmony_civoid do_balance(struct tree_balance *tb, struct item_head *ih,
184862306a36Sopenharmony_ci		const char *body, int flag)
184962306a36Sopenharmony_ci{
185062306a36Sopenharmony_ci	int child_pos;		/* position of a child node in its parent */
185162306a36Sopenharmony_ci	int h;			/* level of the tree being processed */
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	/*
185462306a36Sopenharmony_ci	 * in our processing of one level we sometimes determine what
185562306a36Sopenharmony_ci	 * must be inserted into the next higher level.  This insertion
185662306a36Sopenharmony_ci	 * consists of a key or two keys and their corresponding
185762306a36Sopenharmony_ci	 * pointers
185862306a36Sopenharmony_ci	 */
185962306a36Sopenharmony_ci	struct item_head insert_key[2];
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	/* inserted node-ptrs for the next level */
186262306a36Sopenharmony_ci	struct buffer_head *insert_ptr[2];
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	tb->tb_mode = flag;
186562306a36Sopenharmony_ci	tb->need_balance_dirty = 0;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	if (FILESYSTEM_CHANGED_TB(tb)) {
186862306a36Sopenharmony_ci		reiserfs_panic(tb->tb_sb, "clm-6000", "fs generation has "
186962306a36Sopenharmony_ci			       "changed");
187062306a36Sopenharmony_ci	}
187162306a36Sopenharmony_ci	/* if we have no real work to do  */
187262306a36Sopenharmony_ci	if (!tb->insert_size[0]) {
187362306a36Sopenharmony_ci		reiserfs_warning(tb->tb_sb, "PAP-12350",
187462306a36Sopenharmony_ci				 "insert_size == 0, mode == %c", flag);
187562306a36Sopenharmony_ci		unfix_nodes(tb);
187662306a36Sopenharmony_ci		return;
187762306a36Sopenharmony_ci	}
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci	atomic_inc(&fs_generation(tb->tb_sb));
188062306a36Sopenharmony_ci	do_balance_starts(tb);
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	/*
188362306a36Sopenharmony_ci	 * balance_leaf returns 0 except if combining L R and S into
188462306a36Sopenharmony_ci	 * one node.  see balance_internal() for explanation of this
188562306a36Sopenharmony_ci	 * line of code.
188662306a36Sopenharmony_ci	 */
188762306a36Sopenharmony_ci	child_pos = PATH_H_B_ITEM_ORDER(tb->tb_path, 0) +
188862306a36Sopenharmony_ci	    balance_leaf(tb, ih, body, flag, insert_key, insert_ptr);
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK
189162306a36Sopenharmony_ci	check_after_balance_leaf(tb);
189262306a36Sopenharmony_ci#endif
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	/* Balance internal level of the tree. */
189562306a36Sopenharmony_ci	for (h = 1; h < MAX_HEIGHT && tb->insert_size[h]; h++)
189662306a36Sopenharmony_ci		child_pos = balance_internal(tb, h, child_pos, insert_key,
189762306a36Sopenharmony_ci					     insert_ptr);
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	do_balance_completed(tb);
190062306a36Sopenharmony_ci}
1901