2 * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
5 /* Now we have all buffers that must be used in balancing of the tree */
6 /* Further calculations can not cause schedule(), and thus the buffer */
7 /* tree will be stable until the balancing will be finished */
8 /* balance the tree according to the analysis made before, */
9 /* and using buffers obtained after all above. */
12 ** balance_leaf_when_delete
18 #include <asm/uaccess.h>
19 #include <linux/time.h>
20 #include <linux/reiserfs_fs.h>
21 #include <linux/buffer_head.h>
22 #include <linux/kernel.h>
24 static inline void buffer_info_init_left(struct tree_balance *tb,
25 struct buffer_info *bi)
29 bi->bi_parent = tb->FL[0];
30 bi->bi_position = get_left_neighbor_position(tb, 0);
33 static inline void buffer_info_init_right(struct tree_balance *tb,
34 struct buffer_info *bi)
38 bi->bi_parent = tb->FR[0];
39 bi->bi_position = get_right_neighbor_position(tb, 0);
42 static inline void buffer_info_init_tbS0(struct tree_balance *tb,
43 struct buffer_info *bi)
46 bi->bi_bh = PATH_PLAST_BUFFER(tb->tb_path);
47 bi->bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
48 bi->bi_position = PATH_H_POSITION(tb->tb_path, 1);
51 static inline void buffer_info_init_bh(struct tree_balance *tb,
52 struct buffer_info *bi,
53 struct buffer_head *bh)
61 inline void do_balance_mark_leaf_dirty(struct tree_balance *tb,
62 struct buffer_head *bh, int flag)
64 journal_mark_dirty(tb->transaction_handle,
65 tb->transaction_handle->t_super, bh);
68 #define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty
69 #define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty
72 if deleting something ( tb->insert_size[0] < 0 )
73 return(balance_leaf_when_delete()); (flag d handled here)
75 if lnum is larger than 0 we put items into the left node
76 if rnum is larger than 0 we put items into the right node
77 if snum1 is larger than 0 we put items into the new node s1
78 if snum2 is larger than 0 we put items into the new node s2
79 Note that all *num* count new items being created.
81 It would be easier to read balance_leaf() if each of these summary
82 lines was a separate procedure rather than being inlined. I think
83 that there are many passages here and in balance_leaf_when_delete() in
84 which two calls to one procedure can replace two passages, and it
85 might save cache space and improve software maintenance costs to do so.
87 Vladimir made the perceptive comment that we should offload most of
88 the decision making in this function into fix_nodes/check_balance, and
89 then create some sort of structure in tb that says what actions should
90 be performed by do_balance.
94 /* Balance leaf node in case of delete or cut: insert_size[0] < 0
96 * lnum, rnum can have values >= -1
97 * -1 means that the neighbor must be joined with S
98 * 0 means that nothing should be done with the neighbor
99 * >0 means to shift entirely or partly the specified number of items to the neighbor
101 static int balance_leaf_when_delete(struct tree_balance *tb, int flag)
103 struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
104 int item_pos = PATH_LAST_POSITION(tb->tb_path);
105 int pos_in_item = tb->tb_path->pos_in_item;
106 struct buffer_info bi;
108 struct item_head *ih;
110 RFALSE(tb->FR[0] && B_LEVEL(tb->FR[0]) != DISK_LEAF_NODE_LEVEL + 1,
111 "vs- 12000: level: wrong FR %z", tb->FR[0]);
112 RFALSE(tb->blknum[0] > 1,
113 "PAP-12005: tb->blknum == %d, can not be > 1", tb->blknum[0]);
114 RFALSE(!tb->blknum[0] && !PATH_H_PPARENT(tb->tb_path, 0),
115 "PAP-12010: tree can not be empty");
117 ih = B_N_PITEM_HEAD(tbS0, item_pos);
118 buffer_info_init_tbS0(tb, &bi);
120 /* Delete or truncate the item */
123 case M_DELETE: /* delete item in S[0] */
125 RFALSE(ih_item_len(ih) + IH_SIZE != -tb->insert_size[0],
126 "vs-12013: mode Delete, insert size %d, ih to be deleted %h",
127 -tb->insert_size[0], ih);
129 leaf_delete_items(&bi, 0, item_pos, 1, -1);
131 if (!item_pos && tb->CFL[0]) {
132 if (B_NR_ITEMS(tbS0)) {
133 replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0,
136 if (!PATH_H_POSITION(tb->tb_path, 1))
137 replace_key(tb, tb->CFL[0], tb->lkey[0],
138 PATH_H_PPARENT(tb->tb_path,
143 RFALSE(!item_pos && !tb->CFL[0],
144 "PAP-12020: tb->CFL[0]==%p, tb->L[0]==%p", tb->CFL[0],
149 case M_CUT:{ /* cut item in S[0] */
150 if (is_direntry_le_ih(ih)) {
152 /* UFS unlink semantics are such that you can only delete one directory entry at a time. */
153 /* when we cut a directory tb->insert_size[0] means number of entries to be cut (always 1) */
154 tb->insert_size[0] = -1;
155 leaf_cut_from_buffer(&bi, item_pos, pos_in_item,
156 -tb->insert_size[0]);
158 RFALSE(!item_pos && !pos_in_item && !tb->CFL[0],
159 "PAP-12030: can not change delimiting key. CFL[0]=%p",
162 if (!item_pos && !pos_in_item && tb->CFL[0]) {
163 replace_key(tb, tb->CFL[0], tb->lkey[0],
167 leaf_cut_from_buffer(&bi, item_pos, pos_in_item,
168 -tb->insert_size[0]);
170 RFALSE(!ih_item_len(ih),
171 "PAP-12035: cut must leave non-zero dynamic length of item");
177 print_cur_tb("12040");
178 reiserfs_panic(tb->tb_sb, "PAP-12040",
179 "unexpected mode: %s(%d)",
181 M_PASTE) ? "PASTE" : ((flag ==
182 M_INSERT) ? "INSERT" :
186 /* the rule is that no shifting occurs unless by shifting a node can be freed */
187 n = B_NR_ITEMS(tbS0);
188 if (tb->lnum[0]) { /* L[0] takes part in balancing */
189 if (tb->lnum[0] == -1) { /* L[0] must be joined with S[0] */
190 if (tb->rnum[0] == -1) { /* R[0] must be also joined with S[0] */
191 if (tb->FR[0] == PATH_H_PPARENT(tb->tb_path, 0)) {
192 /* all contents of all the 3 buffers will be in L[0] */
193 if (PATH_H_POSITION(tb->tb_path, 1) == 0
194 && 1 < B_NR_ITEMS(tb->FR[0]))
195 replace_key(tb, tb->CFL[0],
199 leaf_move_items(LEAF_FROM_S_TO_L, tb, n,
201 leaf_move_items(LEAF_FROM_R_TO_L, tb,
202 B_NR_ITEMS(tb->R[0]),
205 reiserfs_invalidate_buffer(tb, tbS0);
206 reiserfs_invalidate_buffer(tb,
211 /* all contents of all the 3 buffers will be in R[0] */
212 leaf_move_items(LEAF_FROM_S_TO_R, tb, n, -1,
214 leaf_move_items(LEAF_FROM_L_TO_R, tb,
215 B_NR_ITEMS(tb->L[0]), -1, NULL);
217 /* right_delimiting_key is correct in R[0] */
218 replace_key(tb, tb->CFR[0], tb->rkey[0],
221 reiserfs_invalidate_buffer(tb, tbS0);
222 reiserfs_invalidate_buffer(tb, tb->L[0]);
227 RFALSE(tb->rnum[0] != 0,
228 "PAP-12045: rnum must be 0 (%d)", tb->rnum[0]);
229 /* all contents of L[0] and S[0] will be in L[0] */
230 leaf_shift_left(tb, n, -1);
232 reiserfs_invalidate_buffer(tb, tbS0);
236 /* a part of contents of S[0] will be in L[0] and the rest part of S[0] will be in R[0] */
238 RFALSE((tb->lnum[0] + tb->rnum[0] < n) ||
239 (tb->lnum[0] + tb->rnum[0] > n + 1),
240 "PAP-12050: rnum(%d) and lnum(%d) and item number(%d) in S[0] are not consistent",
241 tb->rnum[0], tb->lnum[0], n);
242 RFALSE((tb->lnum[0] + tb->rnum[0] == n) &&
243 (tb->lbytes != -1 || tb->rbytes != -1),
244 "PAP-12055: bad rbytes (%d)/lbytes (%d) parameters when items are not split",
245 tb->rbytes, tb->lbytes);
246 RFALSE((tb->lnum[0] + tb->rnum[0] == n + 1) &&
247 (tb->lbytes < 1 || tb->rbytes != -1),
248 "PAP-12060: bad rbytes (%d)/lbytes (%d) parameters when items are split",
249 tb->rbytes, tb->lbytes);
251 leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
252 leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
254 reiserfs_invalidate_buffer(tb, tbS0);
259 if (tb->rnum[0] == -1) {
260 /* all contents of R[0] and S[0] will be in R[0] */
261 leaf_shift_right(tb, n, -1);
262 reiserfs_invalidate_buffer(tb, tbS0);
267 "PAP-12065: bad rnum parameter must be 0 (%d)", tb->rnum[0]);
271 static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item header of inserted item (this is on little endian) */
272 const char *body, /* body of inserted item or bytes to paste */
273 int flag, /* i - insert, d - delete, c - cut, p - paste
274 (see comment to do_balance) */
275 struct item_head *insert_key, /* in our processing of one level we sometimes determine what
276 must be inserted into the next higher level. This insertion
277 consists of a key or two keys and their corresponding
279 struct buffer_head **insert_ptr /* inserted node-ptrs for the next level */
282 struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
283 int item_pos = PATH_LAST_POSITION(tb->tb_path); /* index into the array of item headers in S[0]
284 of the affected item */
285 struct buffer_info bi;
286 struct buffer_head *S_new[2]; /* new nodes allocated to hold what could not fit into S */
287 int snum[2]; /* number of items that will be placed
288 into S_new (includes partially shifted
290 int sbytes[2]; /* if an item is partially shifted into S_new then
291 if it is a directory item
292 it is the number of entries from the item that are shifted into S_new
294 it is the number of bytes from the item that are shifted into S_new
301 PROC_INFO_INC(tb->tb_sb, balance_at[0]);
303 /* Make balance in case insert_size[0] < 0 */
304 if (tb->insert_size[0] < 0)
305 return balance_leaf_when_delete(tb, flag);
308 if (flag == M_INSERT && !body)
309 zeros_num = ih_item_len(ih);
311 pos_in_item = tb->tb_path->pos_in_item;
312 /* for indirect item pos_in_item is measured in unformatted node
313 pointers. Recalculate to bytes */
315 && is_indirect_le_ih(B_N_PITEM_HEAD(tbS0, item_pos)))
316 pos_in_item *= UNFM_P_SIZE;
318 if (tb->lnum[0] > 0) {
319 /* Shift lnum[0] items from S[0] to the left neighbor L[0] */
320 if (item_pos < tb->lnum[0]) {
321 /* new item or it part falls to L[0], shift it too */
322 n = B_NR_ITEMS(tb->L[0]);
325 case M_INSERT: /* insert item into L[0] */
327 if (item_pos == tb->lnum[0] - 1
328 && tb->lbytes != -1) {
329 /* part of new item falls into L[0] */
334 leaf_shift_left(tb, tb->lnum[0] - 1,
337 /* Calculate item length to insert to S[0] */
339 ih_item_len(ih) - tb->lbytes;
340 /* Calculate and check item length to insert to L[0] */
345 RFALSE(ih_item_len(ih) <= 0,
346 "PAP-12080: there is nothing to insert into L[0]: ih_item_len=%d",
349 /* Insert new item into L[0] */
350 buffer_info_init_left(tb, &bi);
351 leaf_insert_into_buf(&bi,
359 version = ih_version(ih);
361 /* Calculate key component, item length and body to insert into S[0] */
362 set_le_ih_k_offset(ih,
372 put_ih_item_len(ih, new_item_len);
373 if (tb->lbytes > zeros_num) {
375 (tb->lbytes - zeros_num);
378 zeros_num -= tb->lbytes;
380 RFALSE(ih_item_len(ih) <= 0,
381 "PAP-12085: there is nothing to insert into S[0]: ih_item_len=%d",
384 /* new item in whole falls into L[0] */
385 /* Shift lnum[0]-1 items to L[0] */
387 leaf_shift_left(tb, tb->lnum[0] - 1,
389 /* Insert new item into L[0] */
390 buffer_info_init_left(tb, &bi);
391 leaf_insert_into_buf(&bi,
395 tb->insert_size[0] = 0;
400 case M_PASTE: /* append item in L[0] */
402 if (item_pos == tb->lnum[0] - 1
403 && tb->lbytes != -1) {
404 /* we must shift the part of the appended item */
405 if (is_direntry_le_ih
406 (B_N_PITEM_HEAD(tbS0, item_pos))) {
409 "PAP-12090: invalid parameter in case of a directory");
411 if (tb->lbytes > pos_in_item) {
412 /* new directory entry falls into L[0] */
418 /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 entries from given directory item */
445 /* Append given directory entry to directory item */
446 buffer_info_init_left(tb, &bi);
455 /* previous string prepared space for pasting new entry, following string pastes this entry */
457 /* when we have merge directory item, pos_in_item has been changed too */
459 /* paste new directory entry. 1 is entry number */
460 leaf_paste_entries(&bi,
478 tb->insert_size[0] = 0;
480 /* new directory item doesn't fall into L[0] */
481 /* Shift lnum[0]-1 items in whole. Shift lbytes directory entries from directory item number lnum[0] */
488 /* Calculate new position to append in item body */
489 pos_in_item -= tb->lbytes;
492 RFALSE(tb->lbytes <= 0,
493 "PAP-12095: there is nothing to shift to L[0]. lbytes=%d",
495 RFALSE(pos_in_item !=
499 "PAP-12100: incorrect position to paste: item_len=%d, pos_in_item=%d",
505 if (tb->lbytes >= pos_in_item) {
506 /* appended item will be in L[0] in whole */
509 /* this bytes number must be appended to the last item of L[h] */
514 /* Calculate new insert_size[0] */
515 tb->insert_size[0] -=
521 "PAP-12105: there is nothing to paste into L[0]. insert_size=%d",
533 /* Append to body of item in L[0] */
534 buffer_info_init_left(tb, &bi);
548 /* 0-th item in S0 can be only of DIRECT type when l_n != 0 */
559 "PAP-12106: item length must be 0");
570 "PAP-12107: items must be of the same file");
571 if (is_indirect_le_ih(B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val))) {
581 /* update key of first item in S0 */
596 /* update left delimiting key */
614 /* Calculate new body, position in item and insert_size[0] */
615 if (l_n > zeros_num) {
634 !op_is_left_mergeable
638 !op_is_left_mergeable
643 "PAP-12120: item must be merge-able with left neighboring item");
644 } else { /* only part of the appended item will be in L[0] */
646 /* Calculate position in item for append in S[0] */
650 RFALSE(pos_in_item <= 0,
651 "PAP-12125: no place for paste. pos_in_item=%d",
654 /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
662 } else { /* appended item will be in L[0] in whole */
664 struct item_head *pasted;
666 if (!item_pos && op_is_left_mergeable(B_N_PKEY(tbS0, 0), tbS0->b_size)) { /* if we paste into first item of S[0] and it is left mergable */
667 /* then increment pos_in_item by the size of the last item in L[0] */
669 B_N_PITEM_HEAD(tb->L[0],
671 if (is_direntry_le_ih(pasted))
680 /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
682 leaf_shift_left(tb, tb->lnum[0],
684 /* Append to body of item in L[0] */
685 buffer_info_init_left(tb, &bi);
686 leaf_paste_in_buffer(&bi,
693 /* if appended item is directory, paste entry */
695 B_N_PITEM_HEAD(tb->L[0],
698 if (is_direntry_le_ih(pasted))
699 leaf_paste_entries(&bi,
714 /* if appended item is indirect item, put unformatted node into un list */
715 if (is_indirect_le_ih(pasted))
716 set_ih_free_space(pasted, 0);
717 tb->insert_size[0] = 0;
721 default: /* cases d and t */
722 reiserfs_panic(tb->tb_sb, "PAP-12130",
723 "lnum > 0: unexpected mode: "
726 M_DELETE) ? "DELETE" : ((flag ==
734 /* new item doesn't fall into L[0] */
735 leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
739 /* tb->lnum[0] > 0 */
740 /* Calculate new item position */
741 item_pos -= (tb->lnum[0] - ((tb->lbytes != -1) ? 1 : 0));
743 if (tb->rnum[0] > 0) {
744 /* shift rnum[0] items from S[0] to the right neighbor R[0] */
745 n = B_NR_ITEMS(tbS0);
748 case M_INSERT: /* insert item */
749 if (n - tb->rnum[0] < item_pos) { /* new item or its part falls to R[0] */
750 if (item_pos == n - tb->rnum[0] + 1 && tb->rbytes != -1) { /* part of new item falls into R[0] */
751 loff_t old_key_comp, old_len,
757 leaf_shift_right(tb, tb->rnum[0] - 1,
760 version = ih_version(ih);
761 /* Remember key component and item length */
762 old_key_comp = le_ih_k_offset(ih);
763 old_len = ih_item_len(ih);
765 /* Calculate key component and item length to insert into R[0] */
770 rbytes) << (is_indirect_le_ih(ih)
774 set_le_ih_k_offset(ih, offset);
775 put_ih_item_len(ih, tb->rbytes);
776 /* Insert part of the item into R[0] */
777 buffer_info_init_right(tb, &bi);
778 if ((old_len - tb->rbytes) > zeros_num) {
787 zeros_num - (old_len -
789 zeros_num -= r_zeros_number;
792 leaf_insert_into_buf(&bi, 0, ih, r_body,
795 /* Replace right delimiting key by first key in R[0] */
796 replace_key(tb, tb->CFR[0], tb->rkey[0],
799 /* Calculate key component and item length to insert into S[0] */
800 set_le_ih_k_offset(ih, old_key_comp);
802 old_len - tb->rbytes);
804 tb->insert_size[0] -= tb->rbytes;
806 } else { /* whole new item falls into R[0] */
808 /* Shift rnum[0]-1 items to R[0] */
813 /* Insert new item into R[0] */
814 buffer_info_init_right(tb, &bi);
815 leaf_insert_into_buf(&bi,
821 if (item_pos - n + tb->rnum[0] - 1 == 0) {
822 replace_key(tb, tb->CFR[0],
827 zeros_num = tb->insert_size[0] = 0;
829 } else { /* new item or part of it doesn't fall into R[0] */
831 leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
835 case M_PASTE: /* append item */
837 if (n - tb->rnum[0] <= item_pos) { /* pasted item or part of it falls to R[0] */
838 if (item_pos == n - tb->rnum[0] && tb->rbytes != -1) { /* we must shift the part of the appended item */
839 if (is_direntry_le_ih(B_N_PITEM_HEAD(tbS0, item_pos))) { /* we append to directory item */
843 "PAP-12145: invalid parameter in case of a directory");
845 I_ENTRY_COUNT(B_N_PITEM_HEAD
848 if (entry_count - tb->rbytes <
850 /* new directory entry falls into R[0] */
852 int paste_entry_position;
854 RFALSE(tb->rbytes - 1 >=
858 "PAP-12150: no enough of entries to shift to R[0]: rbytes=%d, entry_count=%d",
861 /* Shift rnum[0]-1 items in whole. Shift rbytes-1 directory entries from directory item number rnum[0] */
869 /* Paste given directory entry to directory item */
870 paste_entry_position =
874 buffer_info_init_right(tb, &bi);
877 paste_entry_position,
881 leaf_paste_entries(&bi,
883 paste_entry_position,
897 if (paste_entry_position
899 /* change delimiting keys */
913 tb->insert_size[0] = 0;
915 } else { /* new directory entry doesn't fall into R[0] */
924 } else { /* regular object */
930 /* Calculate number of bytes which must be shifted from appended item */
933 tb->insert_size[0]) < 0)
936 RFALSE(pos_in_item !=
940 "PAP-12155: invalid position to paste. ih_item_len=%d, pos_in_item=%d",
949 /* Calculate number of bytes which must remain in body after appending to R[0] */
957 unsigned long temp_rem =
964 if (is_indirect_le_key
999 /* k_offset (B_N_PKEY(tb->R[0],0)) += n_rem;
1000 k_offset (B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) += n_rem;*/
1001 do_balance_mark_internal_dirty
1002 (tb, tb->CFR[0], 0);
1004 /* Append part of body into R[0] */
1005 buffer_info_init_right(tb, &bi);
1006 if (n_rem > zeros_num) {
1019 leaf_paste_in_buffer(&bi, 0,
1028 if (is_indirect_le_ih
1033 "PAP-12160: paste more than one unformatted node pointer");
1039 tb->insert_size[0] = n_rem;
1043 } else { /* pasted item in whole falls into R[0] */
1045 struct item_head *pasted;
1048 leaf_shift_right(tb, tb->rnum[0],
1050 /* append item in R[0] */
1051 if (pos_in_item >= 0) {
1052 buffer_info_init_right(tb, &bi);
1053 leaf_paste_in_buffer(&bi,
1065 /* paste new entry, if item is directory item */
1067 B_N_PITEM_HEAD(tb->R[0],
1070 if (is_direntry_le_ih(pasted)
1071 && pos_in_item >= 0) {
1072 leaf_paste_entries(&bi,
1089 RFALSE(item_pos - n +
1091 "PAP-12165: directory item must be first item of node when pasting is in 0th position");
1093 /* update delimiting keys */
1102 if (is_indirect_le_ih(pasted))
1103 set_ih_free_space(pasted, 0);
1104 zeros_num = tb->insert_size[0] = 0;
1106 } else { /* new item doesn't fall into R[0] */
1108 leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
1111 default: /* cases d and t */
1112 reiserfs_panic(tb->tb_sb, "PAP-12175",
1113 "rnum > 0: unexpected mode: %s(%d)",
1115 M_DELETE) ? "DELETE" : ((flag ==
1123 /* tb->rnum[0] > 0 */
1124 RFALSE(tb->blknum[0] > 3,
1125 "PAP-12180: blknum can not be %d. It must be <= 3",
1127 RFALSE(tb->blknum[0] < 0,
1128 "PAP-12185: blknum can not be %d. It must be >= 0",
1131 /* if while adding to a node we discover that it is possible to split
1132 it in two, and merge the left part into the left neighbor and the
1133 right part into the right neighbor, eliminating the node */
1134 if (tb->blknum[0] == 0) { /* node S[0] is empty now */
1136 RFALSE(!tb->lnum[0] || !tb->rnum[0],
1137 "PAP-12190: lnum and rnum must not be zero");
1138 /* if insertion was done before 0-th position in R[0], right
1139 delimiting key of the tb->L[0]'s and left delimiting key are
1140 not set correctly */
1143 reiserfs_panic(tb->tb_sb, "vs-12195",
1144 "CFR not initialized");
1145 copy_key(B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0]),
1146 B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0]));
1147 do_balance_mark_internal_dirty(tb, tb->CFL[0], 0);
1150 reiserfs_invalidate_buffer(tb, tbS0);
1154 /* Fill new nodes that appear in place of S[0] */
1156 /* I am told that this copying is because we need an array to enable
1157 the looping code. -Hans */
1158 snum[0] = tb->s1num, snum[1] = tb->s2num;
1159 sbytes[0] = tb->s1bytes;
1160 sbytes[1] = tb->s2bytes;
1161 for (i = tb->blknum[0] - 2; i >= 0; i--) {
1163 RFALSE(!snum[i], "PAP-12200: snum[%d] == %d. Must be > 0", i,
1166 /* here we shift from S to S_new nodes */
1168 S_new[i] = get_FEB(tb);
1170 /* initialized block type and tree level */
1171 set_blkh_level(B_BLK_HEAD(S_new[i]), DISK_LEAF_NODE_LEVEL);
1173 n = B_NR_ITEMS(tbS0);
1176 case M_INSERT: /* insert item */
1178 if (n - snum[i] < item_pos) { /* new item or it's part falls to first new node S_new[i] */
1179 if (item_pos == n - snum[i] + 1 && sbytes[i] != -1) { /* part of new item falls into S_new[i] */
1180 int old_key_comp, old_len,
1185 /* Move snum[i]-1 items from S[0] to S_new[i] */
1186 leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
1189 /* Remember key component and item length */
1190 version = ih_version(ih);
1191 old_key_comp = le_ih_k_offset(ih);
1192 old_len = ih_item_len(ih);
1194 /* Calculate key component and item length to insert into S_new[i] */
1195 set_le_ih_k_offset(ih,
1196 le_ih_k_offset(ih) +
1205 put_ih_item_len(ih, sbytes[i]);
1207 /* Insert part of the item into S_new[i] before 0-th item */
1208 buffer_info_init_bh(tb, &bi, S_new[i]);
1210 if ((old_len - sbytes[i]) > zeros_num) {
1219 zeros_num - (old_len -
1221 zeros_num -= r_zeros_number;
1224 leaf_insert_into_buf(&bi, 0, ih, r_body,
1227 /* Calculate key component and item length to insert into S[i] */
1228 set_le_ih_k_offset(ih, old_key_comp);
1230 old_len - sbytes[i]);
1231 tb->insert_size[0] -= sbytes[i];
1232 } else { /* whole new item falls into S_new[i] */
1234 /* Shift snum[0] - 1 items to S_new[i] (sbytes[i] of split item) */
1235 leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
1236 snum[i] - 1, sbytes[i],
1239 /* Insert new item into S_new[i] */
1240 buffer_info_init_bh(tb, &bi, S_new[i]);
1241 leaf_insert_into_buf(&bi,
1246 zeros_num = tb->insert_size[0] = 0;
1250 else { /* new item or it part don't falls into S_new[i] */
1252 leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
1253 snum[i], sbytes[i], S_new[i]);
1257 case M_PASTE: /* append item */
1259 if (n - snum[i] <= item_pos) { /* pasted item or part if it falls to S_new[i] */
1260 if (item_pos == n - snum[i] && sbytes[i] != -1) { /* we must shift part of the appended item */
1261 struct item_head *aux_ih;
1263 RFALSE(ih, "PAP-12210: ih must be 0");
1265 aux_ih = B_N_PITEM_HEAD(tbS0, item_pos);
1266 if (is_direntry_le_ih(aux_ih)) {
1267 /* we append to directory item */
1272 ih_entry_count(aux_ih);
1274 if (entry_count - sbytes[i] <
1278 /* new directory entry falls into S_new[i] */
1282 "PAP-12215: insert_size is already 0");
1283 RFALSE(sbytes[i] - 1 >=
1285 "PAP-12220: there are no so much entries (%d), only %d",
1289 /* Shift snum[i]-1 items in whole. Shift sbytes[i] directory entries from directory item number snum[i] */
1291 (LEAF_FROM_S_TO_SNEW,
1295 /* Paste given directory entry to directory item */
1296 buffer_info_init_bh(tb, &bi, S_new[i]);
1297 leaf_paste_in_buffer
1304 /* paste new directory entry */
1305 leaf_paste_entries(&bi,
1325 tb->insert_size[0] = 0;
1327 } else { /* new directory entry doesn't fall into S_new[i] */
1329 (LEAF_FROM_S_TO_SNEW,
1334 } else { /* regular object */
1340 RFALSE(pos_in_item !=
1344 || tb->insert_size[0] <=
1346 "PAP-12225: item too short or insert_size <= 0");
1348 /* Calculate number of bytes which must be shifted from appended item */
1355 (LEAF_FROM_S_TO_SNEW, tb,
1359 /* Calculate number of bytes which must remain in body after append to S_new[i] */
1361 tb->insert_size[0] -
1365 /* Append part of body into S_new[0] */
1366 buffer_info_init_bh(tb, &bi, S_new[i]);
1367 if (n_rem > zeros_num) {
1380 leaf_paste_in_buffer(&bi, 0,
1389 struct item_head *tmp;
1392 B_N_PITEM_HEAD(S_new
1395 if (is_indirect_le_ih
1418 tb->insert_size[0] = n_rem;
1423 /* item falls wholly into S_new[i] */
1426 struct item_head *pasted;
1428 #ifdef CONFIG_REISERFS_CHECK
1429 struct item_head *ih_check =
1430 B_N_PITEM_HEAD(tbS0, item_pos);
1432 if (!is_direntry_le_ih(ih_check)
1433 && (pos_in_item != ih_item_len(ih_check)
1434 || tb->insert_size[0] <= 0))
1435 reiserfs_panic(tb->tb_sb,
1440 #endif /* CONFIG_REISERFS_CHECK */
1443 leaf_move_items(LEAF_FROM_S_TO_SNEW,
1449 "PAP-12240: unexpected value returned by leaf_move_items (%d)",
1452 /* paste into item */
1453 buffer_info_init_bh(tb, &bi, S_new[i]);
1454 leaf_paste_in_buffer(&bi,
1462 B_N_PITEM_HEAD(S_new[i],
1465 if (is_direntry_le_ih(pasted)) {
1466 leaf_paste_entries(&bi,
1482 /* if we paste to indirect item update ih_free_space */
1483 if (is_indirect_le_ih(pasted))
1484 set_ih_free_space(pasted, 0);
1485 zeros_num = tb->insert_size[0] = 0;
1489 else { /* pasted item doesn't fall into S_new[i] */
1491 leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
1492 snum[i], sbytes[i], S_new[i]);
1495 default: /* cases d and t */
1496 reiserfs_panic(tb->tb_sb, "PAP-12245",
1497 "blknum > 2: unexpected mode: %s(%d)",
1499 M_DELETE) ? "DELETE" : ((flag ==
1505 memcpy(insert_key + i, B_N_PKEY(S_new[i], 0), KEY_SIZE);
1506 insert_ptr[i] = S_new[i];
1508 RFALSE(!buffer_journaled(S_new[i])
1509 || buffer_journal_dirty(S_new[i])
1510 || buffer_dirty(S_new[i]), "PAP-12247: S_new[%d] : (%b)",
1514 /* if the affected item was not wholly shifted then we perform all necessary operations on that part or whole of the
1515 affected item which remains in S */
1516 if (0 <= item_pos && item_pos < tb->s0num) { /* if we must insert or append into buffer S[0] */
1519 case M_INSERT: /* insert item into S[0] */
1520 buffer_info_init_tbS0(tb, &bi);
1521 leaf_insert_into_buf(&bi, item_pos, ih, body,
1524 /* If we insert the first key change the delimiting key */
1525 if (item_pos == 0) {
1526 if (tb->CFL[0]) /* can be 0 in reiserfsck */
1527 replace_key(tb, tb->CFL[0], tb->lkey[0],
1533 case M_PASTE:{ /* append item in S[0] */
1534 struct item_head *pasted;
1536 pasted = B_N_PITEM_HEAD(tbS0, item_pos);
1537 /* when directory, may be new entry already pasted */
1538 if (is_direntry_le_ih(pasted)) {
1539 if (pos_in_item >= 0 &&
1541 ih_entry_count(pasted)) {
1543 RFALSE(!tb->insert_size[0],
1544 "PAP-12260: insert_size is 0 already");
1547 buffer_info_init_tbS0(tb, &bi);
1548 leaf_paste_in_buffer(&bi,
1557 leaf_paste_entries(&bi,
1570 if (!item_pos && !pos_in_item) {
1573 "PAP-12270: CFL[0]/L[0] must be specified");
1587 tb->insert_size[0] = 0;
1589 } else { /* regular object */
1590 if (pos_in_item == ih_item_len(pasted)) {
1592 RFALSE(tb->insert_size[0] <= 0,
1593 "PAP-12275: insert size must not be %d",
1594 tb->insert_size[0]);
1595 buffer_info_init_tbS0(tb, &bi);
1596 leaf_paste_in_buffer(&bi,
1604 if (is_indirect_le_ih(pasted)) {
1609 "PAP-12280: insert_size for indirect item must be %d, not %d",
1617 tb->insert_size[0] = 0;
1619 #ifdef CONFIG_REISERFS_CHECK
1621 if (tb->insert_size[0]) {
1622 print_cur_tb("12285");
1629 tb->insert_size[0]);
1632 #endif /* CONFIG_REISERFS_CHECK */
1635 } /* case M_PASTE: */
1638 #ifdef CONFIG_REISERFS_CHECK
1639 if (flag == M_PASTE && tb->insert_size[0]) {
1640 print_cur_tb("12290");
1641 reiserfs_panic(tb->tb_sb,
1642 "PAP-12290", "insert_size is still not 0 (%d)",
1643 tb->insert_size[0]);
1645 #endif /* CONFIG_REISERFS_CHECK */
1647 } /* Leaf level of the tree is balanced (end of balance_leaf) */
1649 /* Make empty node */
1650 void make_empty_node(struct buffer_info *bi)
1652 struct block_head *blkh;
1654 RFALSE(bi->bi_bh == NULL, "PAP-12295: pointer to the buffer is NULL");
1656 blkh = B_BLK_HEAD(bi->bi_bh);
1657 set_blkh_nr_item(blkh, 0);
1658 set_blkh_free_space(blkh, MAX_CHILD_SIZE(bi->bi_bh));
1661 B_N_CHILD(bi->bi_parent, bi->bi_position)->dc_size = 0; /* Endian safe if 0 */
1664 /* Get first empty buffer */
1665 struct buffer_head *get_FEB(struct tree_balance *tb)
1668 struct buffer_info bi;
1670 for (i = 0; i < MAX_FEB_SIZE; i++)
1671 if (tb->FEB[i] != NULL)
1674 if (i == MAX_FEB_SIZE)
1675 reiserfs_panic(tb->tb_sb, "vs-12300", "FEB list is empty");
1677 buffer_info_init_bh(tb, &bi, tb->FEB[i]);
1678 make_empty_node(&bi);
1679 set_buffer_uptodate(tb->FEB[i]);
1680 tb->used[i] = tb->FEB[i];
1686 /* This is now used because reiserfs_free_block has to be able to
1689 static void store_thrown(struct tree_balance *tb, struct buffer_head *bh)
1693 if (buffer_dirty(bh))
1694 reiserfs_warning(tb->tb_sb, "reiserfs-12320",
1695 "called with dirty buffer");
1696 for (i = 0; i < ARRAY_SIZE(tb->thrown); i++)
1697 if (!tb->thrown[i]) {
1699 get_bh(bh); /* free_thrown puts this */
1702 reiserfs_warning(tb->tb_sb, "reiserfs-12321",
1703 "too many thrown buffers");
1706 static void free_thrown(struct tree_balance *tb)
1709 b_blocknr_t blocknr;
1710 for (i = 0; i < ARRAY_SIZE(tb->thrown); i++) {
1711 if (tb->thrown[i]) {
1712 blocknr = tb->thrown[i]->b_blocknr;
1713 if (buffer_dirty(tb->thrown[i]))
1714 reiserfs_warning(tb->tb_sb, "reiserfs-12322",
1715 "called with dirty buffer %d",
1717 brelse(tb->thrown[i]); /* incremented in store_thrown */
1718 reiserfs_free_block(tb->transaction_handle, NULL,
1724 void reiserfs_invalidate_buffer(struct tree_balance *tb, struct buffer_head *bh)
1726 struct block_head *blkh;
1727 blkh = B_BLK_HEAD(bh);
1728 set_blkh_level(blkh, FREE_LEVEL);
1729 set_blkh_nr_item(blkh, 0);
1731 clear_buffer_dirty(bh);
1732 store_thrown(tb, bh);
1735 /* Replace n_dest'th key in buffer dest by n_src'th key of buffer src.*/
1736 void replace_key(struct tree_balance *tb, struct buffer_head *dest, int n_dest,
1737 struct buffer_head *src, int n_src)
1740 RFALSE(dest == NULL || src == NULL,
1741 "vs-12305: source or destination buffer is 0 (src=%p, dest=%p)",
1743 RFALSE(!B_IS_KEYS_LEVEL(dest),
1744 "vs-12310: invalid level (%z) for destination buffer. dest must be leaf",
1746 RFALSE(n_dest < 0 || n_src < 0,
1747 "vs-12315: src(%d) or dest(%d) key number < 0", n_src, n_dest);
1748 RFALSE(n_dest >= B_NR_ITEMS(dest) || n_src >= B_NR_ITEMS(src),
1749 "vs-12320: src(%d(%d)) or dest(%d(%d)) key number is too big",
1750 n_src, B_NR_ITEMS(src), n_dest, B_NR_ITEMS(dest));
1752 if (B_IS_ITEMS_LEVEL(src))
1753 /* source buffer contains leaf node */
1754 memcpy(B_N_PDELIM_KEY(dest, n_dest), B_N_PITEM_HEAD(src, n_src),
1757 memcpy(B_N_PDELIM_KEY(dest, n_dest), B_N_PDELIM_KEY(src, n_src),
1760 do_balance_mark_internal_dirty(tb, dest, 0);
1763 int get_left_neighbor_position(struct tree_balance *tb, int h)
1765 int Sh_position = PATH_H_POSITION(tb->tb_path, h + 1);
1767 RFALSE(PATH_H_PPARENT(tb->tb_path, h) == NULL || tb->FL[h] == NULL,
1768 "vs-12325: FL[%d](%p) or F[%d](%p) does not exist",
1769 h, tb->FL[h], h, PATH_H_PPARENT(tb->tb_path, h));
1771 if (Sh_position == 0)
1772 return B_NR_ITEMS(tb->FL[h]);
1774 return Sh_position - 1;
1777 int get_right_neighbor_position(struct tree_balance *tb, int h)
1779 int Sh_position = PATH_H_POSITION(tb->tb_path, h + 1);
1781 RFALSE(PATH_H_PPARENT(tb->tb_path, h) == NULL || tb->FR[h] == NULL,
1782 "vs-12330: F[%d](%p) or FR[%d](%p) does not exist",
1783 h, PATH_H_PPARENT(tb->tb_path, h), h, tb->FR[h]);
1785 if (Sh_position == B_NR_ITEMS(PATH_H_PPARENT(tb->tb_path, h)))
1788 return Sh_position + 1;
1791 #ifdef CONFIG_REISERFS_CHECK
1793 int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value);
1794 static void check_internal_node(struct super_block *s, struct buffer_head *bh,
1797 struct disk_child *dc;
1800 RFALSE(!bh, "PAP-12336: bh == 0");
1802 if (!bh || !B_IS_IN_TREE(bh))
1805 RFALSE(!buffer_dirty(bh) &&
1806 !(buffer_journaled(bh) || buffer_journal_dirty(bh)),
1807 "PAP-12337: buffer (%b) must be dirty", bh);
1808 dc = B_N_CHILD(bh, 0);
1810 for (i = 0; i <= B_NR_ITEMS(bh); i++, dc++) {
1811 if (!is_reusable(s, dc_block_number(dc), 1)) {
1813 reiserfs_panic(s, "PAP-12338",
1814 "invalid child pointer %y in %b",
1820 static int locked_or_not_in_tree(struct tree_balance *tb,
1821 struct buffer_head *bh, char *which)
1823 if ((!buffer_journal_prepared(bh) && buffer_locked(bh)) ||
1824 !B_IS_IN_TREE(bh)) {
1825 reiserfs_warning(tb->tb_sb, "vs-12339", "%s (%b)", which, bh);
1831 static int check_before_balancing(struct tree_balance *tb)
1835 if (REISERFS_SB(tb->tb_sb)->cur_tb) {
1836 reiserfs_panic(tb->tb_sb, "vs-12335", "suspect that schedule "
1837 "occurred based on cur_tb not being null at "
1838 "this point in code. do_balance cannot properly "
1839 "handle concurrent tree accesses on a same "
1843 /* double check that buffers that we will modify are unlocked. (fix_nodes should already have
1844 prepped all of these for us). */
1846 retval |= locked_or_not_in_tree(tb, tb->L[0], "L[0]");
1847 retval |= locked_or_not_in_tree(tb, tb->FL[0], "FL[0]");
1848 retval |= locked_or_not_in_tree(tb, tb->CFL[0], "CFL[0]");
1849 check_leaf(tb->L[0]);
1852 retval |= locked_or_not_in_tree(tb, tb->R[0], "R[0]");
1853 retval |= locked_or_not_in_tree(tb, tb->FR[0], "FR[0]");
1854 retval |= locked_or_not_in_tree(tb, tb->CFR[0], "CFR[0]");
1855 check_leaf(tb->R[0]);
1857 retval |= locked_or_not_in_tree(tb, PATH_PLAST_BUFFER(tb->tb_path),
1859 check_leaf(PATH_PLAST_BUFFER(tb->tb_path));
1864 static void check_after_balance_leaf(struct tree_balance *tb)
1867 if (B_FREE_SPACE(tb->L[0]) !=
1868 MAX_CHILD_SIZE(tb->L[0]) -
1870 (tb->FL[0], get_left_neighbor_position(tb, 0)))) {
1871 print_cur_tb("12221");
1872 reiserfs_panic(tb->tb_sb, "PAP-12355",
1873 "shift to left was incorrect");
1877 if (B_FREE_SPACE(tb->R[0]) !=
1878 MAX_CHILD_SIZE(tb->R[0]) -
1880 (tb->FR[0], get_right_neighbor_position(tb, 0)))) {
1881 print_cur_tb("12222");
1882 reiserfs_panic(tb->tb_sb, "PAP-12360",
1883 "shift to right was incorrect");
1886 if (PATH_H_PBUFFER(tb->tb_path, 1) &&
1887 (B_FREE_SPACE(PATH_H_PBUFFER(tb->tb_path, 0)) !=
1888 (MAX_CHILD_SIZE(PATH_H_PBUFFER(tb->tb_path, 0)) -
1889 dc_size(B_N_CHILD(PATH_H_PBUFFER(tb->tb_path, 1),
1890 PATH_H_POSITION(tb->tb_path, 1)))))) {
1891 int left = B_FREE_SPACE(PATH_H_PBUFFER(tb->tb_path, 0));
1892 int right = (MAX_CHILD_SIZE(PATH_H_PBUFFER(tb->tb_path, 0)) -
1893 dc_size(B_N_CHILD(PATH_H_PBUFFER(tb->tb_path, 1),
1894 PATH_H_POSITION(tb->tb_path,
1896 print_cur_tb("12223");
1897 reiserfs_warning(tb->tb_sb, "reiserfs-12363",
1898 "B_FREE_SPACE (PATH_H_PBUFFER(tb->tb_path,0)) = %d; "
1899 "MAX_CHILD_SIZE (%d) - dc_size( %y, %d ) [%d] = %d",
1901 MAX_CHILD_SIZE(PATH_H_PBUFFER(tb->tb_path, 0)),
1902 PATH_H_PBUFFER(tb->tb_path, 1),
1903 PATH_H_POSITION(tb->tb_path, 1),
1905 (PATH_H_PBUFFER(tb->tb_path, 1),
1906 PATH_H_POSITION(tb->tb_path, 1))),
1908 reiserfs_panic(tb->tb_sb, "PAP-12365", "S is incorrect");
1912 static void check_leaf_level(struct tree_balance *tb)
1914 check_leaf(tb->L[0]);
1915 check_leaf(tb->R[0]);
1916 check_leaf(PATH_PLAST_BUFFER(tb->tb_path));
1919 static void check_internal_levels(struct tree_balance *tb)
1923 /* check all internal nodes */
1924 for (h = 1; tb->insert_size[h]; h++) {
1925 check_internal_node(tb->tb_sb, PATH_H_PBUFFER(tb->tb_path, h),
1926 "BAD BUFFER ON PATH");
1928 check_internal_node(tb->tb_sb, tb->L[h], "BAD L");
1930 check_internal_node(tb->tb_sb, tb->R[h], "BAD R");
1937 /* Now we have all of the buffers that must be used in balancing of
1938 the tree. We rely on the assumption that schedule() will not occur
1939 while do_balance works. ( Only interrupt handlers are acceptable.)
1940 We balance the tree according to the analysis made before this,
1941 using buffers already obtained. For SMP support it will someday be
1942 necessary to add ordered locking of tb. */
1944 /* Some interesting rules of balancing:
1946 we delete a maximum of two nodes per level per balancing: we never
1947 delete R, when we delete two of three nodes L, S, R then we move
1950 we only delete L if we are deleting two nodes, if we delete only
1951 one node we delete S
1953 if we shift leaves then we shift as much as we can: this is a
1954 deliberate policy of extremism in node packing which results in
1955 higher average utilization after repeated random balance operations
1956 at the cost of more memory copies and more balancing as a result of
1957 small insertions to full nodes.
1959 if we shift internal nodes we try to evenly balance the node
1960 utilization, with consequent less balancing at the cost of lower
1963 one could argue that the policy for directories in leaves should be
1964 that of internal nodes, but we will wait until another day to
1965 evaluate this.... It would be nice to someday measure and prove
1966 these assumptions as to what is optimal....
1970 static inline void do_balance_starts(struct tree_balance *tb)
1972 /* use print_cur_tb() to see initial state of struct
1975 /* store_print_tb (tb); */
1977 /* do not delete, just comment it out */
1978 /* print_tb(flag, PATH_LAST_POSITION(tb->tb_path), tb->tb_path->pos_in_item, tb,
1980 RFALSE(check_before_balancing(tb), "PAP-12340: locked buffers in TB");
1981 #ifdef CONFIG_REISERFS_CHECK
1982 REISERFS_SB(tb->tb_sb)->cur_tb = tb;
1986 static inline void do_balance_completed(struct tree_balance *tb)
1989 #ifdef CONFIG_REISERFS_CHECK
1990 check_leaf_level(tb);
1991 check_internal_levels(tb);
1992 REISERFS_SB(tb->tb_sb)->cur_tb = NULL;
1995 /* reiserfs_free_block is no longer schedule safe. So, we need to
1996 ** put the buffers we want freed on the thrown list during do_balance,
1997 ** and then free them now
2000 REISERFS_SB(tb->tb_sb)->s_do_balance++;
2002 /* release all nodes hold to perform the balancing */
2008 void do_balance(struct tree_balance *tb, /* tree_balance structure */
2009 struct item_head *ih, /* item header of inserted item */
2010 const char *body, /* body of inserted item or bytes to paste */
2012 { /* i - insert, d - delete
2015 Cut means delete part of an item
2016 (includes removing an entry from a
2019 Delete means delete whole item.
2021 Insert means add a new item into the
2024 Paste means to append to the end of an
2025 existing file or to insert a directory
2027 int child_pos, /* position of a child node in its parent */
2028 h; /* level of the tree being processed */
2029 struct item_head insert_key[2]; /* in our processing of one level
2030 we sometimes determine what
2031 must be inserted into the next
2032 higher level. This insertion
2033 consists of a key or two keys
2034 and their corresponding
2036 struct buffer_head *insert_ptr[2]; /* inserted node-ptrs for the next
2040 tb->need_balance_dirty = 0;
2042 if (FILESYSTEM_CHANGED_TB(tb)) {
2043 reiserfs_panic(tb->tb_sb, "clm-6000", "fs generation has "
2046 /* if we have no real work to do */
2047 if (!tb->insert_size[0]) {
2048 reiserfs_warning(tb->tb_sb, "PAP-12350",
2049 "insert_size == 0, mode == %c", flag);
2054 atomic_inc(&(fs_generation(tb->tb_sb)));
2055 do_balance_starts(tb);
2057 /* balance leaf returns 0 except if combining L R and S into
2058 one node. see balance_internal() for explanation of this
2060 child_pos = PATH_H_B_ITEM_ORDER(tb->tb_path, 0) +
2061 balance_leaf(tb, ih, body, flag, insert_key, insert_ptr);
2063 #ifdef CONFIG_REISERFS_CHECK
2064 check_after_balance_leaf(tb);
2067 /* Balance internal level of the tree. */
2068 for (h = 1; h < MAX_HEIGHT && tb->insert_size[h]; h++)
2070 balance_internal(tb, h, child_pos, insert_key, insert_ptr);
2072 do_balance_completed(tb);