162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README 362306a36Sopenharmony_ci */ 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/time.h> 662306a36Sopenharmony_ci#include <linux/slab.h> 762306a36Sopenharmony_ci#include <linux/string.h> 862306a36Sopenharmony_ci#include "reiserfs.h" 962306a36Sopenharmony_ci#include <linux/buffer_head.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* 1262306a36Sopenharmony_ci * To make any changes in the tree we find a node that contains item 1362306a36Sopenharmony_ci * to be changed/deleted or position in the node we insert a new item 1462306a36Sopenharmony_ci * to. We call this node S. To do balancing we need to decide what we 1562306a36Sopenharmony_ci * will shift to left/right neighbor, or to a new node, where new item 1662306a36Sopenharmony_ci * will be etc. To make this analysis simpler we build virtual 1762306a36Sopenharmony_ci * node. Virtual node is an array of items, that will replace items of 1862306a36Sopenharmony_ci * node S. (For instance if we are going to delete an item, virtual 1962306a36Sopenharmony_ci * node does not contain it). Virtual node keeps information about 2062306a36Sopenharmony_ci * item sizes and types, mergeability of first and last items, sizes 2162306a36Sopenharmony_ci * of all entries in directory item. We use this array of items when 2262306a36Sopenharmony_ci * calculating what we can shift to neighbors and how many nodes we 2362306a36Sopenharmony_ci * have to have if we do not any shiftings, if we shift to left/right 2462306a36Sopenharmony_ci * neighbor or to both. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * Takes item number in virtual node, returns number of item 2962306a36Sopenharmony_ci * that it has in source buffer 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_cistatic inline int old_item_num(int new_num, int affected_item_num, int mode) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci if (mode == M_PASTE || mode == M_CUT || new_num < affected_item_num) 3462306a36Sopenharmony_ci return new_num; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (mode == M_INSERT) { 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci RFALSE(new_num == 0, 3962306a36Sopenharmony_ci "vs-8005: for INSERT mode and item number of inserted item"); 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci return new_num - 1; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci RFALSE(mode != M_DELETE, 4562306a36Sopenharmony_ci "vs-8010: old_item_num: mode must be M_DELETE (mode = \'%c\'", 4662306a36Sopenharmony_ci mode); 4762306a36Sopenharmony_ci /* delete mode */ 4862306a36Sopenharmony_ci return new_num + 1; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic void create_virtual_node(struct tree_balance *tb, int h) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct item_head *ih; 5462306a36Sopenharmony_ci struct virtual_node *vn = tb->tb_vn; 5562306a36Sopenharmony_ci int new_num; 5662306a36Sopenharmony_ci struct buffer_head *Sh; /* this comes from tb->S[h] */ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci Sh = PATH_H_PBUFFER(tb->tb_path, h); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* size of changed node */ 6162306a36Sopenharmony_ci vn->vn_size = 6262306a36Sopenharmony_ci MAX_CHILD_SIZE(Sh) - B_FREE_SPACE(Sh) + tb->insert_size[h]; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* for internal nodes array if virtual items is not created */ 6562306a36Sopenharmony_ci if (h) { 6662306a36Sopenharmony_ci vn->vn_nr_item = (vn->vn_size - DC_SIZE) / (DC_SIZE + KEY_SIZE); 6762306a36Sopenharmony_ci return; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* number of items in virtual node */ 7162306a36Sopenharmony_ci vn->vn_nr_item = 7262306a36Sopenharmony_ci B_NR_ITEMS(Sh) + ((vn->vn_mode == M_INSERT) ? 1 : 0) - 7362306a36Sopenharmony_ci ((vn->vn_mode == M_DELETE) ? 1 : 0); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* first virtual item */ 7662306a36Sopenharmony_ci vn->vn_vi = (struct virtual_item *)(tb->tb_vn + 1); 7762306a36Sopenharmony_ci memset(vn->vn_vi, 0, vn->vn_nr_item * sizeof(struct virtual_item)); 7862306a36Sopenharmony_ci vn->vn_free_ptr += vn->vn_nr_item * sizeof(struct virtual_item); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* first item in the node */ 8162306a36Sopenharmony_ci ih = item_head(Sh, 0); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* define the mergeability for 0-th item (if it is not being deleted) */ 8462306a36Sopenharmony_ci if (op_is_left_mergeable(&ih->ih_key, Sh->b_size) 8562306a36Sopenharmony_ci && (vn->vn_mode != M_DELETE || vn->vn_affected_item_num)) 8662306a36Sopenharmony_ci vn->vn_vi[0].vi_type |= VI_TYPE_LEFT_MERGEABLE; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* 8962306a36Sopenharmony_ci * go through all items that remain in the virtual 9062306a36Sopenharmony_ci * node (except for the new (inserted) one) 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci for (new_num = 0; new_num < vn->vn_nr_item; new_num++) { 9362306a36Sopenharmony_ci int j; 9462306a36Sopenharmony_ci struct virtual_item *vi = vn->vn_vi + new_num; 9562306a36Sopenharmony_ci int is_affected = 9662306a36Sopenharmony_ci ((new_num != vn->vn_affected_item_num) ? 0 : 1); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (is_affected && vn->vn_mode == M_INSERT) 9962306a36Sopenharmony_ci continue; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* get item number in source node */ 10262306a36Sopenharmony_ci j = old_item_num(new_num, vn->vn_affected_item_num, 10362306a36Sopenharmony_ci vn->vn_mode); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci vi->vi_item_len += ih_item_len(ih + j) + IH_SIZE; 10662306a36Sopenharmony_ci vi->vi_ih = ih + j; 10762306a36Sopenharmony_ci vi->vi_item = ih_item_body(Sh, ih + j); 10862306a36Sopenharmony_ci vi->vi_uarea = vn->vn_free_ptr; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* 11162306a36Sopenharmony_ci * FIXME: there is no check that item operation did not 11262306a36Sopenharmony_ci * consume too much memory 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_ci vn->vn_free_ptr += 11562306a36Sopenharmony_ci op_create_vi(vn, vi, is_affected, tb->insert_size[0]); 11662306a36Sopenharmony_ci if (tb->vn_buf + tb->vn_buf_size < vn->vn_free_ptr) 11762306a36Sopenharmony_ci reiserfs_panic(tb->tb_sb, "vs-8030", 11862306a36Sopenharmony_ci "virtual node space consumed"); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (!is_affected) 12162306a36Sopenharmony_ci /* this is not being changed */ 12262306a36Sopenharmony_ci continue; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (vn->vn_mode == M_PASTE || vn->vn_mode == M_CUT) { 12562306a36Sopenharmony_ci vn->vn_vi[new_num].vi_item_len += tb->insert_size[0]; 12662306a36Sopenharmony_ci /* pointer to data which is going to be pasted */ 12762306a36Sopenharmony_ci vi->vi_new_data = vn->vn_data; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* virtual inserted item is not defined yet */ 13262306a36Sopenharmony_ci if (vn->vn_mode == M_INSERT) { 13362306a36Sopenharmony_ci struct virtual_item *vi = vn->vn_vi + vn->vn_affected_item_num; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci RFALSE(vn->vn_ins_ih == NULL, 13662306a36Sopenharmony_ci "vs-8040: item header of inserted item is not specified"); 13762306a36Sopenharmony_ci vi->vi_item_len = tb->insert_size[0]; 13862306a36Sopenharmony_ci vi->vi_ih = vn->vn_ins_ih; 13962306a36Sopenharmony_ci vi->vi_item = vn->vn_data; 14062306a36Sopenharmony_ci vi->vi_uarea = vn->vn_free_ptr; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci op_create_vi(vn, vi, 0 /*not pasted or cut */ , 14362306a36Sopenharmony_ci tb->insert_size[0]); 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * set right merge flag we take right delimiting key and 14862306a36Sopenharmony_ci * check whether it is a mergeable item 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci if (tb->CFR[0]) { 15162306a36Sopenharmony_ci struct reiserfs_key *key; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci key = internal_key(tb->CFR[0], tb->rkey[0]); 15462306a36Sopenharmony_ci if (op_is_left_mergeable(key, Sh->b_size) 15562306a36Sopenharmony_ci && (vn->vn_mode != M_DELETE 15662306a36Sopenharmony_ci || vn->vn_affected_item_num != B_NR_ITEMS(Sh) - 1)) 15762306a36Sopenharmony_ci vn->vn_vi[vn->vn_nr_item - 1].vi_type |= 15862306a36Sopenharmony_ci VI_TYPE_RIGHT_MERGEABLE; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK 16162306a36Sopenharmony_ci if (op_is_left_mergeable(key, Sh->b_size) && 16262306a36Sopenharmony_ci !(vn->vn_mode != M_DELETE 16362306a36Sopenharmony_ci || vn->vn_affected_item_num != B_NR_ITEMS(Sh) - 1)) { 16462306a36Sopenharmony_ci /* 16562306a36Sopenharmony_ci * we delete last item and it could be merged 16662306a36Sopenharmony_ci * with right neighbor's first item 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci if (! 16962306a36Sopenharmony_ci (B_NR_ITEMS(Sh) == 1 17062306a36Sopenharmony_ci && is_direntry_le_ih(item_head(Sh, 0)) 17162306a36Sopenharmony_ci && ih_entry_count(item_head(Sh, 0)) == 1)) { 17262306a36Sopenharmony_ci /* 17362306a36Sopenharmony_ci * node contains more than 1 item, or item 17462306a36Sopenharmony_ci * is not directory item, or this item 17562306a36Sopenharmony_ci * contains more than 1 entry 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci print_block(Sh, 0, -1, -1); 17862306a36Sopenharmony_ci reiserfs_panic(tb->tb_sb, "vs-8045", 17962306a36Sopenharmony_ci "rdkey %k, affected item==%d " 18062306a36Sopenharmony_ci "(mode==%c) Must be %c", 18162306a36Sopenharmony_ci key, vn->vn_affected_item_num, 18262306a36Sopenharmony_ci vn->vn_mode, M_DELETE); 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci#endif 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* 19162306a36Sopenharmony_ci * Using virtual node check, how many items can be 19262306a36Sopenharmony_ci * shifted to left neighbor 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_cistatic void check_left(struct tree_balance *tb, int h, int cur_free) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci int i; 19762306a36Sopenharmony_ci struct virtual_node *vn = tb->tb_vn; 19862306a36Sopenharmony_ci struct virtual_item *vi; 19962306a36Sopenharmony_ci int d_size, ih_size; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci RFALSE(cur_free < 0, "vs-8050: cur_free (%d) < 0", cur_free); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* internal level */ 20462306a36Sopenharmony_ci if (h > 0) { 20562306a36Sopenharmony_ci tb->lnum[h] = cur_free / (DC_SIZE + KEY_SIZE); 20662306a36Sopenharmony_ci return; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* leaf level */ 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (!cur_free || !vn->vn_nr_item) { 21262306a36Sopenharmony_ci /* no free space or nothing to move */ 21362306a36Sopenharmony_ci tb->lnum[h] = 0; 21462306a36Sopenharmony_ci tb->lbytes = -1; 21562306a36Sopenharmony_ci return; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci RFALSE(!PATH_H_PPARENT(tb->tb_path, 0), 21962306a36Sopenharmony_ci "vs-8055: parent does not exist or invalid"); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci vi = vn->vn_vi; 22262306a36Sopenharmony_ci if ((unsigned int)cur_free >= 22362306a36Sopenharmony_ci (vn->vn_size - 22462306a36Sopenharmony_ci ((vi->vi_type & VI_TYPE_LEFT_MERGEABLE) ? IH_SIZE : 0))) { 22562306a36Sopenharmony_ci /* all contents of S[0] fits into L[0] */ 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci RFALSE(vn->vn_mode == M_INSERT || vn->vn_mode == M_PASTE, 22862306a36Sopenharmony_ci "vs-8055: invalid mode or balance condition failed"); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci tb->lnum[0] = vn->vn_nr_item; 23162306a36Sopenharmony_ci tb->lbytes = -1; 23262306a36Sopenharmony_ci return; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci d_size = 0, ih_size = IH_SIZE; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* first item may be merge with last item in left neighbor */ 23862306a36Sopenharmony_ci if (vi->vi_type & VI_TYPE_LEFT_MERGEABLE) 23962306a36Sopenharmony_ci d_size = -((int)IH_SIZE), ih_size = 0; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci tb->lnum[0] = 0; 24262306a36Sopenharmony_ci for (i = 0; i < vn->vn_nr_item; 24362306a36Sopenharmony_ci i++, ih_size = IH_SIZE, d_size = 0, vi++) { 24462306a36Sopenharmony_ci d_size += vi->vi_item_len; 24562306a36Sopenharmony_ci if (cur_free >= d_size) { 24662306a36Sopenharmony_ci /* the item can be shifted entirely */ 24762306a36Sopenharmony_ci cur_free -= d_size; 24862306a36Sopenharmony_ci tb->lnum[0]++; 24962306a36Sopenharmony_ci continue; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* the item cannot be shifted entirely, try to split it */ 25362306a36Sopenharmony_ci /* 25462306a36Sopenharmony_ci * check whether L[0] can hold ih and at least one byte 25562306a36Sopenharmony_ci * of the item body 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* cannot shift even a part of the current item */ 25962306a36Sopenharmony_ci if (cur_free <= ih_size) { 26062306a36Sopenharmony_ci tb->lbytes = -1; 26162306a36Sopenharmony_ci return; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci cur_free -= ih_size; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci tb->lbytes = op_check_left(vi, cur_free, 0, 0); 26662306a36Sopenharmony_ci if (tb->lbytes != -1) 26762306a36Sopenharmony_ci /* count partially shifted item */ 26862306a36Sopenharmony_ci tb->lnum[0]++; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci break; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci/* 27762306a36Sopenharmony_ci * Using virtual node check, how many items can be 27862306a36Sopenharmony_ci * shifted to right neighbor 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_cistatic void check_right(struct tree_balance *tb, int h, int cur_free) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci int i; 28362306a36Sopenharmony_ci struct virtual_node *vn = tb->tb_vn; 28462306a36Sopenharmony_ci struct virtual_item *vi; 28562306a36Sopenharmony_ci int d_size, ih_size; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci RFALSE(cur_free < 0, "vs-8070: cur_free < 0"); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* internal level */ 29062306a36Sopenharmony_ci if (h > 0) { 29162306a36Sopenharmony_ci tb->rnum[h] = cur_free / (DC_SIZE + KEY_SIZE); 29262306a36Sopenharmony_ci return; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* leaf level */ 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (!cur_free || !vn->vn_nr_item) { 29862306a36Sopenharmony_ci /* no free space */ 29962306a36Sopenharmony_ci tb->rnum[h] = 0; 30062306a36Sopenharmony_ci tb->rbytes = -1; 30162306a36Sopenharmony_ci return; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci RFALSE(!PATH_H_PPARENT(tb->tb_path, 0), 30562306a36Sopenharmony_ci "vs-8075: parent does not exist or invalid"); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci vi = vn->vn_vi + vn->vn_nr_item - 1; 30862306a36Sopenharmony_ci if ((unsigned int)cur_free >= 30962306a36Sopenharmony_ci (vn->vn_size - 31062306a36Sopenharmony_ci ((vi->vi_type & VI_TYPE_RIGHT_MERGEABLE) ? IH_SIZE : 0))) { 31162306a36Sopenharmony_ci /* all contents of S[0] fits into R[0] */ 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci RFALSE(vn->vn_mode == M_INSERT || vn->vn_mode == M_PASTE, 31462306a36Sopenharmony_ci "vs-8080: invalid mode or balance condition failed"); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci tb->rnum[h] = vn->vn_nr_item; 31762306a36Sopenharmony_ci tb->rbytes = -1; 31862306a36Sopenharmony_ci return; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci d_size = 0, ih_size = IH_SIZE; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* last item may be merge with first item in right neighbor */ 32462306a36Sopenharmony_ci if (vi->vi_type & VI_TYPE_RIGHT_MERGEABLE) 32562306a36Sopenharmony_ci d_size = -(int)IH_SIZE, ih_size = 0; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci tb->rnum[0] = 0; 32862306a36Sopenharmony_ci for (i = vn->vn_nr_item - 1; i >= 0; 32962306a36Sopenharmony_ci i--, d_size = 0, ih_size = IH_SIZE, vi--) { 33062306a36Sopenharmony_ci d_size += vi->vi_item_len; 33162306a36Sopenharmony_ci if (cur_free >= d_size) { 33262306a36Sopenharmony_ci /* the item can be shifted entirely */ 33362306a36Sopenharmony_ci cur_free -= d_size; 33462306a36Sopenharmony_ci tb->rnum[0]++; 33562306a36Sopenharmony_ci continue; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* 33962306a36Sopenharmony_ci * check whether R[0] can hold ih and at least one 34062306a36Sopenharmony_ci * byte of the item body 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* cannot shift even a part of the current item */ 34462306a36Sopenharmony_ci if (cur_free <= ih_size) { 34562306a36Sopenharmony_ci tb->rbytes = -1; 34662306a36Sopenharmony_ci return; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* 35062306a36Sopenharmony_ci * R[0] can hold the header of the item and at least 35162306a36Sopenharmony_ci * one byte of its body 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ci cur_free -= ih_size; /* cur_free is still > 0 */ 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci tb->rbytes = op_check_right(vi, cur_free); 35662306a36Sopenharmony_ci if (tb->rbytes != -1) 35762306a36Sopenharmony_ci /* count partially shifted item */ 35862306a36Sopenharmony_ci tb->rnum[0]++; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return; 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci/* 36762306a36Sopenharmony_ci * from - number of items, which are shifted to left neighbor entirely 36862306a36Sopenharmony_ci * to - number of item, which are shifted to right neighbor entirely 36962306a36Sopenharmony_ci * from_bytes - number of bytes of boundary item (or directory entries) 37062306a36Sopenharmony_ci * which are shifted to left neighbor 37162306a36Sopenharmony_ci * to_bytes - number of bytes of boundary item (or directory entries) 37262306a36Sopenharmony_ci * which are shifted to right neighbor 37362306a36Sopenharmony_ci */ 37462306a36Sopenharmony_cistatic int get_num_ver(int mode, struct tree_balance *tb, int h, 37562306a36Sopenharmony_ci int from, int from_bytes, 37662306a36Sopenharmony_ci int to, int to_bytes, short *snum012, int flow) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci int i; 37962306a36Sopenharmony_ci int units; 38062306a36Sopenharmony_ci struct virtual_node *vn = tb->tb_vn; 38162306a36Sopenharmony_ci int total_node_size, max_node_size, current_item_size; 38262306a36Sopenharmony_ci int needed_nodes; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* position of item we start filling node from */ 38562306a36Sopenharmony_ci int start_item; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* position of item we finish filling node by */ 38862306a36Sopenharmony_ci int end_item; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* 39162306a36Sopenharmony_ci * number of first bytes (entries for directory) of start_item-th item 39262306a36Sopenharmony_ci * we do not include into node that is being filled 39362306a36Sopenharmony_ci */ 39462306a36Sopenharmony_ci int start_bytes; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci * number of last bytes (entries for directory) of end_item-th item 39862306a36Sopenharmony_ci * we do node include into node that is being filled 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_ci int end_bytes; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* 40362306a36Sopenharmony_ci * these are positions in virtual item of items, that are split 40462306a36Sopenharmony_ci * between S[0] and S1new and S1new and S2new 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_ci int split_item_positions[2]; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci split_item_positions[0] = -1; 40962306a36Sopenharmony_ci split_item_positions[1] = -1; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci /* 41262306a36Sopenharmony_ci * We only create additional nodes if we are in insert or paste mode 41362306a36Sopenharmony_ci * or we are in replace mode at the internal level. If h is 0 and 41462306a36Sopenharmony_ci * the mode is M_REPLACE then in fix_nodes we change the mode to 41562306a36Sopenharmony_ci * paste or insert before we get here in the code. 41662306a36Sopenharmony_ci */ 41762306a36Sopenharmony_ci RFALSE(tb->insert_size[h] < 0 || (mode != M_INSERT && mode != M_PASTE), 41862306a36Sopenharmony_ci "vs-8100: insert_size < 0 in overflow"); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci max_node_size = MAX_CHILD_SIZE(PATH_H_PBUFFER(tb->tb_path, h)); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* 42362306a36Sopenharmony_ci * snum012 [0-2] - number of items, that lay 42462306a36Sopenharmony_ci * to S[0], first new node and second new node 42562306a36Sopenharmony_ci */ 42662306a36Sopenharmony_ci snum012[3] = -1; /* s1bytes */ 42762306a36Sopenharmony_ci snum012[4] = -1; /* s2bytes */ 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* internal level */ 43062306a36Sopenharmony_ci if (h > 0) { 43162306a36Sopenharmony_ci i = ((to - from) * (KEY_SIZE + DC_SIZE) + DC_SIZE); 43262306a36Sopenharmony_ci if (i == max_node_size) 43362306a36Sopenharmony_ci return 1; 43462306a36Sopenharmony_ci return (i / max_node_size + 1); 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* leaf level */ 43862306a36Sopenharmony_ci needed_nodes = 1; 43962306a36Sopenharmony_ci total_node_size = 0; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci /* start from 'from'-th item */ 44262306a36Sopenharmony_ci start_item = from; 44362306a36Sopenharmony_ci /* skip its first 'start_bytes' units */ 44462306a36Sopenharmony_ci start_bytes = ((from_bytes != -1) ? from_bytes : 0); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* last included item is the 'end_item'-th one */ 44762306a36Sopenharmony_ci end_item = vn->vn_nr_item - to - 1; 44862306a36Sopenharmony_ci /* do not count last 'end_bytes' units of 'end_item'-th item */ 44962306a36Sopenharmony_ci end_bytes = (to_bytes != -1) ? to_bytes : 0; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* 45262306a36Sopenharmony_ci * go through all item beginning from the start_item-th item 45362306a36Sopenharmony_ci * and ending by the end_item-th item. Do not count first 45462306a36Sopenharmony_ci * 'start_bytes' units of 'start_item'-th item and last 45562306a36Sopenharmony_ci * 'end_bytes' of 'end_item'-th item 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_ci for (i = start_item; i <= end_item; i++) { 45862306a36Sopenharmony_ci struct virtual_item *vi = vn->vn_vi + i; 45962306a36Sopenharmony_ci int skip_from_end = ((i == end_item) ? end_bytes : 0); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci RFALSE(needed_nodes > 3, "vs-8105: too many nodes are needed"); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* get size of current item */ 46462306a36Sopenharmony_ci current_item_size = vi->vi_item_len; 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* 46762306a36Sopenharmony_ci * do not take in calculation head part (from_bytes) 46862306a36Sopenharmony_ci * of from-th item 46962306a36Sopenharmony_ci */ 47062306a36Sopenharmony_ci current_item_size -= 47162306a36Sopenharmony_ci op_part_size(vi, 0 /*from start */ , start_bytes); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* do not take in calculation tail part of last item */ 47462306a36Sopenharmony_ci current_item_size -= 47562306a36Sopenharmony_ci op_part_size(vi, 1 /*from end */ , skip_from_end); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* if item fits into current node entierly */ 47862306a36Sopenharmony_ci if (total_node_size + current_item_size <= max_node_size) { 47962306a36Sopenharmony_ci snum012[needed_nodes - 1]++; 48062306a36Sopenharmony_ci total_node_size += current_item_size; 48162306a36Sopenharmony_ci start_bytes = 0; 48262306a36Sopenharmony_ci continue; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* 48662306a36Sopenharmony_ci * virtual item length is longer, than max size of item in 48762306a36Sopenharmony_ci * a node. It is impossible for direct item 48862306a36Sopenharmony_ci */ 48962306a36Sopenharmony_ci if (current_item_size > max_node_size) { 49062306a36Sopenharmony_ci RFALSE(is_direct_le_ih(vi->vi_ih), 49162306a36Sopenharmony_ci "vs-8110: " 49262306a36Sopenharmony_ci "direct item length is %d. It can not be longer than %d", 49362306a36Sopenharmony_ci current_item_size, max_node_size); 49462306a36Sopenharmony_ci /* we will try to split it */ 49562306a36Sopenharmony_ci flow = 1; 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* as we do not split items, take new node and continue */ 49962306a36Sopenharmony_ci if (!flow) { 50062306a36Sopenharmony_ci needed_nodes++; 50162306a36Sopenharmony_ci i--; 50262306a36Sopenharmony_ci total_node_size = 0; 50362306a36Sopenharmony_ci continue; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* 50762306a36Sopenharmony_ci * calculate number of item units which fit into node being 50862306a36Sopenharmony_ci * filled 50962306a36Sopenharmony_ci */ 51062306a36Sopenharmony_ci { 51162306a36Sopenharmony_ci int free_space; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci free_space = max_node_size - total_node_size - IH_SIZE; 51462306a36Sopenharmony_ci units = 51562306a36Sopenharmony_ci op_check_left(vi, free_space, start_bytes, 51662306a36Sopenharmony_ci skip_from_end); 51762306a36Sopenharmony_ci /* 51862306a36Sopenharmony_ci * nothing fits into current node, take new 51962306a36Sopenharmony_ci * node and continue 52062306a36Sopenharmony_ci */ 52162306a36Sopenharmony_ci if (units == -1) { 52262306a36Sopenharmony_ci needed_nodes++, i--, total_node_size = 0; 52362306a36Sopenharmony_ci continue; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* something fits into the current node */ 52862306a36Sopenharmony_ci start_bytes += units; 52962306a36Sopenharmony_ci snum012[needed_nodes - 1 + 3] = units; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (needed_nodes > 2) 53262306a36Sopenharmony_ci reiserfs_warning(tb->tb_sb, "vs-8111", 53362306a36Sopenharmony_ci "split_item_position is out of range"); 53462306a36Sopenharmony_ci snum012[needed_nodes - 1]++; 53562306a36Sopenharmony_ci split_item_positions[needed_nodes - 1] = i; 53662306a36Sopenharmony_ci needed_nodes++; 53762306a36Sopenharmony_ci /* continue from the same item with start_bytes != -1 */ 53862306a36Sopenharmony_ci start_item = i; 53962306a36Sopenharmony_ci i--; 54062306a36Sopenharmony_ci total_node_size = 0; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* 54462306a36Sopenharmony_ci * sum012[4] (if it is not -1) contains number of units of which 54562306a36Sopenharmony_ci * are to be in S1new, snum012[3] - to be in S0. They are supposed 54662306a36Sopenharmony_ci * to be S1bytes and S2bytes correspondingly, so recalculate 54762306a36Sopenharmony_ci */ 54862306a36Sopenharmony_ci if (snum012[4] > 0) { 54962306a36Sopenharmony_ci int split_item_num; 55062306a36Sopenharmony_ci int bytes_to_r, bytes_to_l; 55162306a36Sopenharmony_ci int bytes_to_S1new; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci split_item_num = split_item_positions[1]; 55462306a36Sopenharmony_ci bytes_to_l = 55562306a36Sopenharmony_ci ((from == split_item_num 55662306a36Sopenharmony_ci && from_bytes != -1) ? from_bytes : 0); 55762306a36Sopenharmony_ci bytes_to_r = 55862306a36Sopenharmony_ci ((end_item == split_item_num 55962306a36Sopenharmony_ci && end_bytes != -1) ? end_bytes : 0); 56062306a36Sopenharmony_ci bytes_to_S1new = 56162306a36Sopenharmony_ci ((split_item_positions[0] == 56262306a36Sopenharmony_ci split_item_positions[1]) ? snum012[3] : 0); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* s2bytes */ 56562306a36Sopenharmony_ci snum012[4] = 56662306a36Sopenharmony_ci op_unit_num(&vn->vn_vi[split_item_num]) - snum012[4] - 56762306a36Sopenharmony_ci bytes_to_r - bytes_to_l - bytes_to_S1new; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (vn->vn_vi[split_item_num].vi_index != TYPE_DIRENTRY && 57062306a36Sopenharmony_ci vn->vn_vi[split_item_num].vi_index != TYPE_INDIRECT) 57162306a36Sopenharmony_ci reiserfs_warning(tb->tb_sb, "vs-8115", 57262306a36Sopenharmony_ci "not directory or indirect item"); 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* now we know S2bytes, calculate S1bytes */ 57662306a36Sopenharmony_ci if (snum012[3] > 0) { 57762306a36Sopenharmony_ci int split_item_num; 57862306a36Sopenharmony_ci int bytes_to_r, bytes_to_l; 57962306a36Sopenharmony_ci int bytes_to_S2new; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci split_item_num = split_item_positions[0]; 58262306a36Sopenharmony_ci bytes_to_l = 58362306a36Sopenharmony_ci ((from == split_item_num 58462306a36Sopenharmony_ci && from_bytes != -1) ? from_bytes : 0); 58562306a36Sopenharmony_ci bytes_to_r = 58662306a36Sopenharmony_ci ((end_item == split_item_num 58762306a36Sopenharmony_ci && end_bytes != -1) ? end_bytes : 0); 58862306a36Sopenharmony_ci bytes_to_S2new = 58962306a36Sopenharmony_ci ((split_item_positions[0] == split_item_positions[1] 59062306a36Sopenharmony_ci && snum012[4] != -1) ? snum012[4] : 0); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* s1bytes */ 59362306a36Sopenharmony_ci snum012[3] = 59462306a36Sopenharmony_ci op_unit_num(&vn->vn_vi[split_item_num]) - snum012[3] - 59562306a36Sopenharmony_ci bytes_to_r - bytes_to_l - bytes_to_S2new; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci return needed_nodes; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci/* 60362306a36Sopenharmony_ci * Set parameters for balancing. 60462306a36Sopenharmony_ci * Performs write of results of analysis of balancing into structure tb, 60562306a36Sopenharmony_ci * where it will later be used by the functions that actually do the balancing. 60662306a36Sopenharmony_ci * Parameters: 60762306a36Sopenharmony_ci * tb tree_balance structure; 60862306a36Sopenharmony_ci * h current level of the node; 60962306a36Sopenharmony_ci * lnum number of items from S[h] that must be shifted to L[h]; 61062306a36Sopenharmony_ci * rnum number of items from S[h] that must be shifted to R[h]; 61162306a36Sopenharmony_ci * blk_num number of blocks that S[h] will be splitted into; 61262306a36Sopenharmony_ci * s012 number of items that fall into splitted nodes. 61362306a36Sopenharmony_ci * lbytes number of bytes which flow to the left neighbor from the 61462306a36Sopenharmony_ci * item that is not shifted entirely 61562306a36Sopenharmony_ci * rbytes number of bytes which flow to the right neighbor from the 61662306a36Sopenharmony_ci * item that is not shifted entirely 61762306a36Sopenharmony_ci * s1bytes number of bytes which flow to the first new node when 61862306a36Sopenharmony_ci * S[0] splits (this number is contained in s012 array) 61962306a36Sopenharmony_ci */ 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic void set_parameters(struct tree_balance *tb, int h, int lnum, 62262306a36Sopenharmony_ci int rnum, int blk_num, short *s012, int lb, int rb) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci tb->lnum[h] = lnum; 62662306a36Sopenharmony_ci tb->rnum[h] = rnum; 62762306a36Sopenharmony_ci tb->blknum[h] = blk_num; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci /* only for leaf level */ 63062306a36Sopenharmony_ci if (h == 0) { 63162306a36Sopenharmony_ci if (s012 != NULL) { 63262306a36Sopenharmony_ci tb->s0num = *s012++; 63362306a36Sopenharmony_ci tb->snum[0] = *s012++; 63462306a36Sopenharmony_ci tb->snum[1] = *s012++; 63562306a36Sopenharmony_ci tb->sbytes[0] = *s012++; 63662306a36Sopenharmony_ci tb->sbytes[1] = *s012; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci tb->lbytes = lb; 63962306a36Sopenharmony_ci tb->rbytes = rb; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci PROC_INFO_ADD(tb->tb_sb, lnum[h], lnum); 64262306a36Sopenharmony_ci PROC_INFO_ADD(tb->tb_sb, rnum[h], rnum); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci PROC_INFO_ADD(tb->tb_sb, lbytes[h], lb); 64562306a36Sopenharmony_ci PROC_INFO_ADD(tb->tb_sb, rbytes[h], rb); 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci/* 64962306a36Sopenharmony_ci * check if node disappears if we shift tb->lnum[0] items to left 65062306a36Sopenharmony_ci * neighbor and tb->rnum[0] to the right one. 65162306a36Sopenharmony_ci */ 65262306a36Sopenharmony_cistatic int is_leaf_removable(struct tree_balance *tb) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci struct virtual_node *vn = tb->tb_vn; 65562306a36Sopenharmony_ci int to_left, to_right; 65662306a36Sopenharmony_ci int size; 65762306a36Sopenharmony_ci int remain_items; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci /* 66062306a36Sopenharmony_ci * number of items that will be shifted to left (right) neighbor 66162306a36Sopenharmony_ci * entirely 66262306a36Sopenharmony_ci */ 66362306a36Sopenharmony_ci to_left = tb->lnum[0] - ((tb->lbytes != -1) ? 1 : 0); 66462306a36Sopenharmony_ci to_right = tb->rnum[0] - ((tb->rbytes != -1) ? 1 : 0); 66562306a36Sopenharmony_ci remain_items = vn->vn_nr_item; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* how many items remain in S[0] after shiftings to neighbors */ 66862306a36Sopenharmony_ci remain_items -= (to_left + to_right); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* all content of node can be shifted to neighbors */ 67162306a36Sopenharmony_ci if (remain_items < 1) { 67262306a36Sopenharmony_ci set_parameters(tb, 0, to_left, vn->vn_nr_item - to_left, 0, 67362306a36Sopenharmony_ci NULL, -1, -1); 67462306a36Sopenharmony_ci return 1; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* S[0] is not removable */ 67862306a36Sopenharmony_ci if (remain_items > 1 || tb->lbytes == -1 || tb->rbytes == -1) 67962306a36Sopenharmony_ci return 0; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci /* check whether we can divide 1 remaining item between neighbors */ 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* get size of remaining item (in item units) */ 68462306a36Sopenharmony_ci size = op_unit_num(&vn->vn_vi[to_left]); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (tb->lbytes + tb->rbytes >= size) { 68762306a36Sopenharmony_ci set_parameters(tb, 0, to_left + 1, to_right + 1, 0, NULL, 68862306a36Sopenharmony_ci tb->lbytes, -1); 68962306a36Sopenharmony_ci return 1; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci return 0; 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci/* check whether L, S, R can be joined in one node */ 69662306a36Sopenharmony_cistatic int are_leaves_removable(struct tree_balance *tb, int lfree, int rfree) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci struct virtual_node *vn = tb->tb_vn; 69962306a36Sopenharmony_ci int ih_size; 70062306a36Sopenharmony_ci struct buffer_head *S0; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci S0 = PATH_H_PBUFFER(tb->tb_path, 0); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci ih_size = 0; 70562306a36Sopenharmony_ci if (vn->vn_nr_item) { 70662306a36Sopenharmony_ci if (vn->vn_vi[0].vi_type & VI_TYPE_LEFT_MERGEABLE) 70762306a36Sopenharmony_ci ih_size += IH_SIZE; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci if (vn->vn_vi[vn->vn_nr_item - 1]. 71062306a36Sopenharmony_ci vi_type & VI_TYPE_RIGHT_MERGEABLE) 71162306a36Sopenharmony_ci ih_size += IH_SIZE; 71262306a36Sopenharmony_ci } else { 71362306a36Sopenharmony_ci /* there was only one item and it will be deleted */ 71462306a36Sopenharmony_ci struct item_head *ih; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci RFALSE(B_NR_ITEMS(S0) != 1, 71762306a36Sopenharmony_ci "vs-8125: item number must be 1: it is %d", 71862306a36Sopenharmony_ci B_NR_ITEMS(S0)); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci ih = item_head(S0, 0); 72162306a36Sopenharmony_ci if (tb->CFR[0] 72262306a36Sopenharmony_ci && !comp_short_le_keys(&ih->ih_key, 72362306a36Sopenharmony_ci internal_key(tb->CFR[0], 72462306a36Sopenharmony_ci tb->rkey[0]))) 72562306a36Sopenharmony_ci /* 72662306a36Sopenharmony_ci * Directory must be in correct state here: that is 72762306a36Sopenharmony_ci * somewhere at the left side should exist first 72862306a36Sopenharmony_ci * directory item. But the item being deleted can 72962306a36Sopenharmony_ci * not be that first one because its right neighbor 73062306a36Sopenharmony_ci * is item of the same directory. (But first item 73162306a36Sopenharmony_ci * always gets deleted in last turn). So, neighbors 73262306a36Sopenharmony_ci * of deleted item can be merged, so we can save 73362306a36Sopenharmony_ci * ih_size 73462306a36Sopenharmony_ci */ 73562306a36Sopenharmony_ci if (is_direntry_le_ih(ih)) { 73662306a36Sopenharmony_ci ih_size = IH_SIZE; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci /* 73962306a36Sopenharmony_ci * we might check that left neighbor exists 74062306a36Sopenharmony_ci * and is of the same directory 74162306a36Sopenharmony_ci */ 74262306a36Sopenharmony_ci RFALSE(le_ih_k_offset(ih) == DOT_OFFSET, 74362306a36Sopenharmony_ci "vs-8130: first directory item can not be removed until directory is not empty"); 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (MAX_CHILD_SIZE(S0) + vn->vn_size <= rfree + lfree + ih_size) { 74962306a36Sopenharmony_ci set_parameters(tb, 0, -1, -1, -1, NULL, -1, -1); 75062306a36Sopenharmony_ci PROC_INFO_INC(tb->tb_sb, leaves_removable); 75162306a36Sopenharmony_ci return 1; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci return 0; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci/* when we do not split item, lnum and rnum are numbers of entire items */ 75862306a36Sopenharmony_ci#define SET_PAR_SHIFT_LEFT \ 75962306a36Sopenharmony_ciif (h)\ 76062306a36Sopenharmony_ci{\ 76162306a36Sopenharmony_ci int to_l;\ 76262306a36Sopenharmony_ci \ 76362306a36Sopenharmony_ci to_l = (MAX_NR_KEY(Sh)+1 - lpar + vn->vn_nr_item + 1) / 2 -\ 76462306a36Sopenharmony_ci (MAX_NR_KEY(Sh) + 1 - lpar);\ 76562306a36Sopenharmony_ci \ 76662306a36Sopenharmony_ci set_parameters (tb, h, to_l, 0, lnver, NULL, -1, -1);\ 76762306a36Sopenharmony_ci}\ 76862306a36Sopenharmony_cielse \ 76962306a36Sopenharmony_ci{\ 77062306a36Sopenharmony_ci if (lset==LEFT_SHIFT_FLOW)\ 77162306a36Sopenharmony_ci set_parameters (tb, h, lpar, 0, lnver, snum012+lset,\ 77262306a36Sopenharmony_ci tb->lbytes, -1);\ 77362306a36Sopenharmony_ci else\ 77462306a36Sopenharmony_ci set_parameters (tb, h, lpar - (tb->lbytes!=-1), 0, lnver, snum012+lset,\ 77562306a36Sopenharmony_ci -1, -1);\ 77662306a36Sopenharmony_ci} 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci#define SET_PAR_SHIFT_RIGHT \ 77962306a36Sopenharmony_ciif (h)\ 78062306a36Sopenharmony_ci{\ 78162306a36Sopenharmony_ci int to_r;\ 78262306a36Sopenharmony_ci \ 78362306a36Sopenharmony_ci to_r = (MAX_NR_KEY(Sh)+1 - rpar + vn->vn_nr_item + 1) / 2 - (MAX_NR_KEY(Sh) + 1 - rpar);\ 78462306a36Sopenharmony_ci \ 78562306a36Sopenharmony_ci set_parameters (tb, h, 0, to_r, rnver, NULL, -1, -1);\ 78662306a36Sopenharmony_ci}\ 78762306a36Sopenharmony_cielse \ 78862306a36Sopenharmony_ci{\ 78962306a36Sopenharmony_ci if (rset==RIGHT_SHIFT_FLOW)\ 79062306a36Sopenharmony_ci set_parameters (tb, h, 0, rpar, rnver, snum012+rset,\ 79162306a36Sopenharmony_ci -1, tb->rbytes);\ 79262306a36Sopenharmony_ci else\ 79362306a36Sopenharmony_ci set_parameters (tb, h, 0, rpar - (tb->rbytes!=-1), rnver, snum012+rset,\ 79462306a36Sopenharmony_ci -1, -1);\ 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cistatic void free_buffers_in_tb(struct tree_balance *tb) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci int i; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci pathrelse(tb->tb_path); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci for (i = 0; i < MAX_HEIGHT; i++) { 80462306a36Sopenharmony_ci brelse(tb->L[i]); 80562306a36Sopenharmony_ci brelse(tb->R[i]); 80662306a36Sopenharmony_ci brelse(tb->FL[i]); 80762306a36Sopenharmony_ci brelse(tb->FR[i]); 80862306a36Sopenharmony_ci brelse(tb->CFL[i]); 80962306a36Sopenharmony_ci brelse(tb->CFR[i]); 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci tb->L[i] = NULL; 81262306a36Sopenharmony_ci tb->R[i] = NULL; 81362306a36Sopenharmony_ci tb->FL[i] = NULL; 81462306a36Sopenharmony_ci tb->FR[i] = NULL; 81562306a36Sopenharmony_ci tb->CFL[i] = NULL; 81662306a36Sopenharmony_ci tb->CFR[i] = NULL; 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci/* 82162306a36Sopenharmony_ci * Get new buffers for storing new nodes that are created while balancing. 82262306a36Sopenharmony_ci * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; 82362306a36Sopenharmony_ci * CARRY_ON - schedule didn't occur while the function worked; 82462306a36Sopenharmony_ci * NO_DISK_SPACE - no disk space. 82562306a36Sopenharmony_ci */ 82662306a36Sopenharmony_ci/* The function is NOT SCHEDULE-SAFE! */ 82762306a36Sopenharmony_cistatic int get_empty_nodes(struct tree_balance *tb, int h) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci struct buffer_head *new_bh, *Sh = PATH_H_PBUFFER(tb->tb_path, h); 83062306a36Sopenharmony_ci b_blocknr_t *blocknr, blocknrs[MAX_AMOUNT_NEEDED] = { 0, }; 83162306a36Sopenharmony_ci int counter, number_of_freeblk; 83262306a36Sopenharmony_ci int amount_needed; /* number of needed empty blocks */ 83362306a36Sopenharmony_ci int retval = CARRY_ON; 83462306a36Sopenharmony_ci struct super_block *sb = tb->tb_sb; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* 83762306a36Sopenharmony_ci * number_of_freeblk is the number of empty blocks which have been 83862306a36Sopenharmony_ci * acquired for use by the balancing algorithm minus the number of 83962306a36Sopenharmony_ci * empty blocks used in the previous levels of the analysis, 84062306a36Sopenharmony_ci * number_of_freeblk = tb->cur_blknum can be non-zero if a schedule 84162306a36Sopenharmony_ci * occurs after empty blocks are acquired, and the balancing analysis 84262306a36Sopenharmony_ci * is then restarted, amount_needed is the number needed by this 84362306a36Sopenharmony_ci * level (h) of the balancing analysis. 84462306a36Sopenharmony_ci * 84562306a36Sopenharmony_ci * Note that for systems with many processes writing, it would be 84662306a36Sopenharmony_ci * more layout optimal to calculate the total number needed by all 84762306a36Sopenharmony_ci * levels and then to run reiserfs_new_blocks to get all of them at 84862306a36Sopenharmony_ci * once. 84962306a36Sopenharmony_ci */ 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci /* 85262306a36Sopenharmony_ci * Initiate number_of_freeblk to the amount acquired prior to the 85362306a36Sopenharmony_ci * restart of the analysis or 0 if not restarted, then subtract the 85462306a36Sopenharmony_ci * amount needed by all of the levels of the tree below h. 85562306a36Sopenharmony_ci */ 85662306a36Sopenharmony_ci /* blknum includes S[h], so we subtract 1 in this calculation */ 85762306a36Sopenharmony_ci for (counter = 0, number_of_freeblk = tb->cur_blknum; 85862306a36Sopenharmony_ci counter < h; counter++) 85962306a36Sopenharmony_ci number_of_freeblk -= 86062306a36Sopenharmony_ci (tb->blknum[counter]) ? (tb->blknum[counter] - 86162306a36Sopenharmony_ci 1) : 0; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* Allocate missing empty blocks. */ 86462306a36Sopenharmony_ci /* if Sh == 0 then we are getting a new root */ 86562306a36Sopenharmony_ci amount_needed = (Sh) ? (tb->blknum[h] - 1) : 1; 86662306a36Sopenharmony_ci /* 86762306a36Sopenharmony_ci * Amount_needed = the amount that we need more than the 86862306a36Sopenharmony_ci * amount that we have. 86962306a36Sopenharmony_ci */ 87062306a36Sopenharmony_ci if (amount_needed > number_of_freeblk) 87162306a36Sopenharmony_ci amount_needed -= number_of_freeblk; 87262306a36Sopenharmony_ci else /* If we have enough already then there is nothing to do. */ 87362306a36Sopenharmony_ci return CARRY_ON; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* 87662306a36Sopenharmony_ci * No need to check quota - is not allocated for blocks used 87762306a36Sopenharmony_ci * for formatted nodes 87862306a36Sopenharmony_ci */ 87962306a36Sopenharmony_ci if (reiserfs_new_form_blocknrs(tb, blocknrs, 88062306a36Sopenharmony_ci amount_needed) == NO_DISK_SPACE) 88162306a36Sopenharmony_ci return NO_DISK_SPACE; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci /* for each blocknumber we just got, get a buffer and stick it on FEB */ 88462306a36Sopenharmony_ci for (blocknr = blocknrs, counter = 0; 88562306a36Sopenharmony_ci counter < amount_needed; blocknr++, counter++) { 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci RFALSE(!*blocknr, 88862306a36Sopenharmony_ci "PAP-8135: reiserfs_new_blocknrs failed when got new blocks"); 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci new_bh = sb_getblk(sb, *blocknr); 89162306a36Sopenharmony_ci RFALSE(buffer_dirty(new_bh) || 89262306a36Sopenharmony_ci buffer_journaled(new_bh) || 89362306a36Sopenharmony_ci buffer_journal_dirty(new_bh), 89462306a36Sopenharmony_ci "PAP-8140: journaled or dirty buffer %b for the new block", 89562306a36Sopenharmony_ci new_bh); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci /* Put empty buffers into the array. */ 89862306a36Sopenharmony_ci RFALSE(tb->FEB[tb->cur_blknum], 89962306a36Sopenharmony_ci "PAP-8141: busy slot for new buffer"); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci set_buffer_journal_new(new_bh); 90262306a36Sopenharmony_ci tb->FEB[tb->cur_blknum++] = new_bh; 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if (retval == CARRY_ON && FILESYSTEM_CHANGED_TB(tb)) 90662306a36Sopenharmony_ci retval = REPEAT_SEARCH; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci return retval; 90962306a36Sopenharmony_ci} 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci/* 91262306a36Sopenharmony_ci * Get free space of the left neighbor, which is stored in the parent 91362306a36Sopenharmony_ci * node of the left neighbor. 91462306a36Sopenharmony_ci */ 91562306a36Sopenharmony_cistatic int get_lfree(struct tree_balance *tb, int h) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci struct buffer_head *l, *f; 91862306a36Sopenharmony_ci int order; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci if ((f = PATH_H_PPARENT(tb->tb_path, h)) == NULL || 92162306a36Sopenharmony_ci (l = tb->FL[h]) == NULL) 92262306a36Sopenharmony_ci return 0; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci if (f == l) 92562306a36Sopenharmony_ci order = PATH_H_B_ITEM_ORDER(tb->tb_path, h) - 1; 92662306a36Sopenharmony_ci else { 92762306a36Sopenharmony_ci order = B_NR_ITEMS(l); 92862306a36Sopenharmony_ci f = l; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci return (MAX_CHILD_SIZE(f) - dc_size(B_N_CHILD(f, order))); 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci/* 93562306a36Sopenharmony_ci * Get free space of the right neighbor, 93662306a36Sopenharmony_ci * which is stored in the parent node of the right neighbor. 93762306a36Sopenharmony_ci */ 93862306a36Sopenharmony_cistatic int get_rfree(struct tree_balance *tb, int h) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci struct buffer_head *r, *f; 94162306a36Sopenharmony_ci int order; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci if ((f = PATH_H_PPARENT(tb->tb_path, h)) == NULL || 94462306a36Sopenharmony_ci (r = tb->FR[h]) == NULL) 94562306a36Sopenharmony_ci return 0; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci if (f == r) 94862306a36Sopenharmony_ci order = PATH_H_B_ITEM_ORDER(tb->tb_path, h) + 1; 94962306a36Sopenharmony_ci else { 95062306a36Sopenharmony_ci order = 0; 95162306a36Sopenharmony_ci f = r; 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci return (MAX_CHILD_SIZE(f) - dc_size(B_N_CHILD(f, order))); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci} 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci/* Check whether left neighbor is in memory. */ 95962306a36Sopenharmony_cistatic int is_left_neighbor_in_cache(struct tree_balance *tb, int h) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci struct buffer_head *father, *left; 96262306a36Sopenharmony_ci struct super_block *sb = tb->tb_sb; 96362306a36Sopenharmony_ci b_blocknr_t left_neighbor_blocknr; 96462306a36Sopenharmony_ci int left_neighbor_position; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci /* Father of the left neighbor does not exist. */ 96762306a36Sopenharmony_ci if (!tb->FL[h]) 96862306a36Sopenharmony_ci return 0; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci /* Calculate father of the node to be balanced. */ 97162306a36Sopenharmony_ci father = PATH_H_PBUFFER(tb->tb_path, h + 1); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci RFALSE(!father || 97462306a36Sopenharmony_ci !B_IS_IN_TREE(father) || 97562306a36Sopenharmony_ci !B_IS_IN_TREE(tb->FL[h]) || 97662306a36Sopenharmony_ci !buffer_uptodate(father) || 97762306a36Sopenharmony_ci !buffer_uptodate(tb->FL[h]), 97862306a36Sopenharmony_ci "vs-8165: F[h] (%b) or FL[h] (%b) is invalid", 97962306a36Sopenharmony_ci father, tb->FL[h]); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* 98262306a36Sopenharmony_ci * Get position of the pointer to the left neighbor 98362306a36Sopenharmony_ci * into the left father. 98462306a36Sopenharmony_ci */ 98562306a36Sopenharmony_ci left_neighbor_position = (father == tb->FL[h]) ? 98662306a36Sopenharmony_ci tb->lkey[h] : B_NR_ITEMS(tb->FL[h]); 98762306a36Sopenharmony_ci /* Get left neighbor block number. */ 98862306a36Sopenharmony_ci left_neighbor_blocknr = 98962306a36Sopenharmony_ci B_N_CHILD_NUM(tb->FL[h], left_neighbor_position); 99062306a36Sopenharmony_ci /* Look for the left neighbor in the cache. */ 99162306a36Sopenharmony_ci if ((left = sb_find_get_block(sb, left_neighbor_blocknr))) { 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci RFALSE(buffer_uptodate(left) && !B_IS_IN_TREE(left), 99462306a36Sopenharmony_ci "vs-8170: left neighbor (%b %z) is not in the tree", 99562306a36Sopenharmony_ci left, left); 99662306a36Sopenharmony_ci put_bh(left); 99762306a36Sopenharmony_ci return 1; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci return 0; 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci#define LEFT_PARENTS 'l' 100462306a36Sopenharmony_ci#define RIGHT_PARENTS 'r' 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cistatic void decrement_key(struct cpu_key *key) 100762306a36Sopenharmony_ci{ 100862306a36Sopenharmony_ci /* call item specific function for this key */ 100962306a36Sopenharmony_ci item_ops[cpu_key_k_type(key)]->decrement_key(key); 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci/* 101362306a36Sopenharmony_ci * Calculate far left/right parent of the left/right neighbor of the 101462306a36Sopenharmony_ci * current node, that is calculate the left/right (FL[h]/FR[h]) neighbor 101562306a36Sopenharmony_ci * of the parent F[h]. 101662306a36Sopenharmony_ci * Calculate left/right common parent of the current node and L[h]/R[h]. 101762306a36Sopenharmony_ci * Calculate left/right delimiting key position. 101862306a36Sopenharmony_ci * Returns: PATH_INCORRECT - path in the tree is not correct 101962306a36Sopenharmony_ci * SCHEDULE_OCCURRED - schedule occurred while the function worked 102062306a36Sopenharmony_ci * CARRY_ON - schedule didn't occur while the function 102162306a36Sopenharmony_ci * worked 102262306a36Sopenharmony_ci */ 102362306a36Sopenharmony_cistatic int get_far_parent(struct tree_balance *tb, 102462306a36Sopenharmony_ci int h, 102562306a36Sopenharmony_ci struct buffer_head **pfather, 102662306a36Sopenharmony_ci struct buffer_head **pcom_father, char c_lr_par) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci struct buffer_head *parent; 102962306a36Sopenharmony_ci INITIALIZE_PATH(s_path_to_neighbor_father); 103062306a36Sopenharmony_ci struct treepath *path = tb->tb_path; 103162306a36Sopenharmony_ci struct cpu_key s_lr_father_key; 103262306a36Sopenharmony_ci int counter, 103362306a36Sopenharmony_ci position = INT_MAX, 103462306a36Sopenharmony_ci first_last_position = 0, 103562306a36Sopenharmony_ci path_offset = PATH_H_PATH_OFFSET(path, h); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci /* 103862306a36Sopenharmony_ci * Starting from F[h] go upwards in the tree, and look for the common 103962306a36Sopenharmony_ci * ancestor of F[h], and its neighbor l/r, that should be obtained. 104062306a36Sopenharmony_ci */ 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci counter = path_offset; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci RFALSE(counter < FIRST_PATH_ELEMENT_OFFSET, 104562306a36Sopenharmony_ci "PAP-8180: invalid path length"); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci for (; counter > FIRST_PATH_ELEMENT_OFFSET; counter--) { 104862306a36Sopenharmony_ci /* 104962306a36Sopenharmony_ci * Check whether parent of the current buffer in the path 105062306a36Sopenharmony_ci * is really parent in the tree. 105162306a36Sopenharmony_ci */ 105262306a36Sopenharmony_ci if (!B_IS_IN_TREE 105362306a36Sopenharmony_ci (parent = PATH_OFFSET_PBUFFER(path, counter - 1))) 105462306a36Sopenharmony_ci return REPEAT_SEARCH; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci /* Check whether position in the parent is correct. */ 105762306a36Sopenharmony_ci if ((position = 105862306a36Sopenharmony_ci PATH_OFFSET_POSITION(path, 105962306a36Sopenharmony_ci counter - 1)) > 106062306a36Sopenharmony_ci B_NR_ITEMS(parent)) 106162306a36Sopenharmony_ci return REPEAT_SEARCH; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* 106462306a36Sopenharmony_ci * Check whether parent at the path really points 106562306a36Sopenharmony_ci * to the child. 106662306a36Sopenharmony_ci */ 106762306a36Sopenharmony_ci if (B_N_CHILD_NUM(parent, position) != 106862306a36Sopenharmony_ci PATH_OFFSET_PBUFFER(path, counter)->b_blocknr) 106962306a36Sopenharmony_ci return REPEAT_SEARCH; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci /* 107262306a36Sopenharmony_ci * Return delimiting key if position in the parent is not 107362306a36Sopenharmony_ci * equal to first/last one. 107462306a36Sopenharmony_ci */ 107562306a36Sopenharmony_ci if (c_lr_par == RIGHT_PARENTS) 107662306a36Sopenharmony_ci first_last_position = B_NR_ITEMS(parent); 107762306a36Sopenharmony_ci if (position != first_last_position) { 107862306a36Sopenharmony_ci *pcom_father = parent; 107962306a36Sopenharmony_ci get_bh(*pcom_father); 108062306a36Sopenharmony_ci /*(*pcom_father = parent)->b_count++; */ 108162306a36Sopenharmony_ci break; 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci /* if we are in the root of the tree, then there is no common father */ 108662306a36Sopenharmony_ci if (counter == FIRST_PATH_ELEMENT_OFFSET) { 108762306a36Sopenharmony_ci /* 108862306a36Sopenharmony_ci * Check whether first buffer in the path is the 108962306a36Sopenharmony_ci * root of the tree. 109062306a36Sopenharmony_ci */ 109162306a36Sopenharmony_ci if (PATH_OFFSET_PBUFFER 109262306a36Sopenharmony_ci (tb->tb_path, 109362306a36Sopenharmony_ci FIRST_PATH_ELEMENT_OFFSET)->b_blocknr == 109462306a36Sopenharmony_ci SB_ROOT_BLOCK(tb->tb_sb)) { 109562306a36Sopenharmony_ci *pfather = *pcom_father = NULL; 109662306a36Sopenharmony_ci return CARRY_ON; 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci return REPEAT_SEARCH; 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci RFALSE(B_LEVEL(*pcom_father) <= DISK_LEAF_NODE_LEVEL, 110262306a36Sopenharmony_ci "PAP-8185: (%b %z) level too small", 110362306a36Sopenharmony_ci *pcom_father, *pcom_father); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci /* Check whether the common parent is locked. */ 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci if (buffer_locked(*pcom_father)) { 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci /* Release the write lock while the buffer is busy */ 111062306a36Sopenharmony_ci int depth = reiserfs_write_unlock_nested(tb->tb_sb); 111162306a36Sopenharmony_ci __wait_on_buffer(*pcom_father); 111262306a36Sopenharmony_ci reiserfs_write_lock_nested(tb->tb_sb, depth); 111362306a36Sopenharmony_ci if (FILESYSTEM_CHANGED_TB(tb)) { 111462306a36Sopenharmony_ci brelse(*pcom_father); 111562306a36Sopenharmony_ci return REPEAT_SEARCH; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci /* 112062306a36Sopenharmony_ci * So, we got common parent of the current node and its 112162306a36Sopenharmony_ci * left/right neighbor. Now we are getting the parent of the 112262306a36Sopenharmony_ci * left/right neighbor. 112362306a36Sopenharmony_ci */ 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_ci /* Form key to get parent of the left/right neighbor. */ 112662306a36Sopenharmony_ci le_key2cpu_key(&s_lr_father_key, 112762306a36Sopenharmony_ci internal_key(*pcom_father, 112862306a36Sopenharmony_ci (c_lr_par == 112962306a36Sopenharmony_ci LEFT_PARENTS) ? (tb->lkey[h - 1] = 113062306a36Sopenharmony_ci position - 113162306a36Sopenharmony_ci 1) : (tb->rkey[h - 113262306a36Sopenharmony_ci 1] = 113362306a36Sopenharmony_ci position))); 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci if (c_lr_par == LEFT_PARENTS) 113662306a36Sopenharmony_ci decrement_key(&s_lr_father_key); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci if (search_by_key 113962306a36Sopenharmony_ci (tb->tb_sb, &s_lr_father_key, &s_path_to_neighbor_father, 114062306a36Sopenharmony_ci h + 1) == IO_ERROR) 114162306a36Sopenharmony_ci /* path is released */ 114262306a36Sopenharmony_ci return IO_ERROR; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci if (FILESYSTEM_CHANGED_TB(tb)) { 114562306a36Sopenharmony_ci pathrelse(&s_path_to_neighbor_father); 114662306a36Sopenharmony_ci brelse(*pcom_father); 114762306a36Sopenharmony_ci return REPEAT_SEARCH; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci *pfather = PATH_PLAST_BUFFER(&s_path_to_neighbor_father); 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci RFALSE(B_LEVEL(*pfather) != h + 1, 115362306a36Sopenharmony_ci "PAP-8190: (%b %z) level too small", *pfather, *pfather); 115462306a36Sopenharmony_ci RFALSE(s_path_to_neighbor_father.path_length < 115562306a36Sopenharmony_ci FIRST_PATH_ELEMENT_OFFSET, "PAP-8192: path length is too small"); 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci s_path_to_neighbor_father.path_length--; 115862306a36Sopenharmony_ci pathrelse(&s_path_to_neighbor_father); 115962306a36Sopenharmony_ci return CARRY_ON; 116062306a36Sopenharmony_ci} 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci/* 116362306a36Sopenharmony_ci * Get parents of neighbors of node in the path(S[path_offset]) and 116462306a36Sopenharmony_ci * common parents of S[path_offset] and L[path_offset]/R[path_offset]: 116562306a36Sopenharmony_ci * F[path_offset], FL[path_offset], FR[path_offset], CFL[path_offset], 116662306a36Sopenharmony_ci * CFR[path_offset]. 116762306a36Sopenharmony_ci * Calculate numbers of left and right delimiting keys position: 116862306a36Sopenharmony_ci * lkey[path_offset], rkey[path_offset]. 116962306a36Sopenharmony_ci * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked 117062306a36Sopenharmony_ci * CARRY_ON - schedule didn't occur while the function worked 117162306a36Sopenharmony_ci */ 117262306a36Sopenharmony_cistatic int get_parents(struct tree_balance *tb, int h) 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci struct treepath *path = tb->tb_path; 117562306a36Sopenharmony_ci int position, 117662306a36Sopenharmony_ci ret, 117762306a36Sopenharmony_ci path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h); 117862306a36Sopenharmony_ci struct buffer_head *curf, *curcf; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci /* Current node is the root of the tree or will be root of the tree */ 118162306a36Sopenharmony_ci if (path_offset <= FIRST_PATH_ELEMENT_OFFSET) { 118262306a36Sopenharmony_ci /* 118362306a36Sopenharmony_ci * The root can not have parents. 118462306a36Sopenharmony_ci * Release nodes which previously were obtained as 118562306a36Sopenharmony_ci * parents of the current node neighbors. 118662306a36Sopenharmony_ci */ 118762306a36Sopenharmony_ci brelse(tb->FL[h]); 118862306a36Sopenharmony_ci brelse(tb->CFL[h]); 118962306a36Sopenharmony_ci brelse(tb->FR[h]); 119062306a36Sopenharmony_ci brelse(tb->CFR[h]); 119162306a36Sopenharmony_ci tb->FL[h] = NULL; 119262306a36Sopenharmony_ci tb->CFL[h] = NULL; 119362306a36Sopenharmony_ci tb->FR[h] = NULL; 119462306a36Sopenharmony_ci tb->CFR[h] = NULL; 119562306a36Sopenharmony_ci return CARRY_ON; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci /* Get parent FL[path_offset] of L[path_offset]. */ 119962306a36Sopenharmony_ci position = PATH_OFFSET_POSITION(path, path_offset - 1); 120062306a36Sopenharmony_ci if (position) { 120162306a36Sopenharmony_ci /* Current node is not the first child of its parent. */ 120262306a36Sopenharmony_ci curf = PATH_OFFSET_PBUFFER(path, path_offset - 1); 120362306a36Sopenharmony_ci curcf = PATH_OFFSET_PBUFFER(path, path_offset - 1); 120462306a36Sopenharmony_ci get_bh(curf); 120562306a36Sopenharmony_ci get_bh(curf); 120662306a36Sopenharmony_ci tb->lkey[h] = position - 1; 120762306a36Sopenharmony_ci } else { 120862306a36Sopenharmony_ci /* 120962306a36Sopenharmony_ci * Calculate current parent of L[path_offset], which is the 121062306a36Sopenharmony_ci * left neighbor of the current node. Calculate current 121162306a36Sopenharmony_ci * common parent of L[path_offset] and the current node. 121262306a36Sopenharmony_ci * Note that CFL[path_offset] not equal FL[path_offset] and 121362306a36Sopenharmony_ci * CFL[path_offset] not equal F[path_offset]. 121462306a36Sopenharmony_ci * Calculate lkey[path_offset]. 121562306a36Sopenharmony_ci */ 121662306a36Sopenharmony_ci if ((ret = get_far_parent(tb, h + 1, &curf, 121762306a36Sopenharmony_ci &curcf, 121862306a36Sopenharmony_ci LEFT_PARENTS)) != CARRY_ON) 121962306a36Sopenharmony_ci return ret; 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci brelse(tb->FL[h]); 122362306a36Sopenharmony_ci tb->FL[h] = curf; /* New initialization of FL[h]. */ 122462306a36Sopenharmony_ci brelse(tb->CFL[h]); 122562306a36Sopenharmony_ci tb->CFL[h] = curcf; /* New initialization of CFL[h]. */ 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci RFALSE((curf && !B_IS_IN_TREE(curf)) || 122862306a36Sopenharmony_ci (curcf && !B_IS_IN_TREE(curcf)), 122962306a36Sopenharmony_ci "PAP-8195: FL (%b) or CFL (%b) is invalid", curf, curcf); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci /* Get parent FR[h] of R[h]. */ 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci /* Current node is the last child of F[h]. FR[h] != F[h]. */ 123462306a36Sopenharmony_ci if (position == B_NR_ITEMS(PATH_H_PBUFFER(path, h + 1))) { 123562306a36Sopenharmony_ci /* 123662306a36Sopenharmony_ci * Calculate current parent of R[h], which is the right 123762306a36Sopenharmony_ci * neighbor of F[h]. Calculate current common parent of 123862306a36Sopenharmony_ci * R[h] and current node. Note that CFR[h] not equal 123962306a36Sopenharmony_ci * FR[path_offset] and CFR[h] not equal F[h]. 124062306a36Sopenharmony_ci */ 124162306a36Sopenharmony_ci if ((ret = 124262306a36Sopenharmony_ci get_far_parent(tb, h + 1, &curf, &curcf, 124362306a36Sopenharmony_ci RIGHT_PARENTS)) != CARRY_ON) 124462306a36Sopenharmony_ci return ret; 124562306a36Sopenharmony_ci } else { 124662306a36Sopenharmony_ci /* Current node is not the last child of its parent F[h]. */ 124762306a36Sopenharmony_ci curf = PATH_OFFSET_PBUFFER(path, path_offset - 1); 124862306a36Sopenharmony_ci curcf = PATH_OFFSET_PBUFFER(path, path_offset - 1); 124962306a36Sopenharmony_ci get_bh(curf); 125062306a36Sopenharmony_ci get_bh(curf); 125162306a36Sopenharmony_ci tb->rkey[h] = position; 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci brelse(tb->FR[h]); 125562306a36Sopenharmony_ci /* New initialization of FR[path_offset]. */ 125662306a36Sopenharmony_ci tb->FR[h] = curf; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci brelse(tb->CFR[h]); 125962306a36Sopenharmony_ci /* New initialization of CFR[path_offset]. */ 126062306a36Sopenharmony_ci tb->CFR[h] = curcf; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci RFALSE((curf && !B_IS_IN_TREE(curf)) || 126362306a36Sopenharmony_ci (curcf && !B_IS_IN_TREE(curcf)), 126462306a36Sopenharmony_ci "PAP-8205: FR (%b) or CFR (%b) is invalid", curf, curcf); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci return CARRY_ON; 126762306a36Sopenharmony_ci} 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci/* 127062306a36Sopenharmony_ci * it is possible to remove node as result of shiftings to 127162306a36Sopenharmony_ci * neighbors even when we insert or paste item. 127262306a36Sopenharmony_ci */ 127362306a36Sopenharmony_cistatic inline int can_node_be_removed(int mode, int lfree, int sfree, int rfree, 127462306a36Sopenharmony_ci struct tree_balance *tb, int h) 127562306a36Sopenharmony_ci{ 127662306a36Sopenharmony_ci struct buffer_head *Sh = PATH_H_PBUFFER(tb->tb_path, h); 127762306a36Sopenharmony_ci int levbytes = tb->insert_size[h]; 127862306a36Sopenharmony_ci struct item_head *ih; 127962306a36Sopenharmony_ci struct reiserfs_key *r_key = NULL; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci ih = item_head(Sh, 0); 128262306a36Sopenharmony_ci if (tb->CFR[h]) 128362306a36Sopenharmony_ci r_key = internal_key(tb->CFR[h], tb->rkey[h]); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci if (lfree + rfree + sfree < MAX_CHILD_SIZE(Sh) + levbytes 128662306a36Sopenharmony_ci /* shifting may merge items which might save space */ 128762306a36Sopenharmony_ci - 128862306a36Sopenharmony_ci ((!h 128962306a36Sopenharmony_ci && op_is_left_mergeable(&ih->ih_key, Sh->b_size)) ? IH_SIZE : 0) 129062306a36Sopenharmony_ci - 129162306a36Sopenharmony_ci ((!h && r_key 129262306a36Sopenharmony_ci && op_is_left_mergeable(r_key, Sh->b_size)) ? IH_SIZE : 0) 129362306a36Sopenharmony_ci + ((h) ? KEY_SIZE : 0)) { 129462306a36Sopenharmony_ci /* node can not be removed */ 129562306a36Sopenharmony_ci if (sfree >= levbytes) { 129662306a36Sopenharmony_ci /* new item fits into node S[h] without any shifting */ 129762306a36Sopenharmony_ci if (!h) 129862306a36Sopenharmony_ci tb->s0num = 129962306a36Sopenharmony_ci B_NR_ITEMS(Sh) + 130062306a36Sopenharmony_ci ((mode == M_INSERT) ? 1 : 0); 130162306a36Sopenharmony_ci set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 130262306a36Sopenharmony_ci return NO_BALANCING_NEEDED; 130362306a36Sopenharmony_ci } 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci PROC_INFO_INC(tb->tb_sb, can_node_be_removed[h]); 130662306a36Sopenharmony_ci return !NO_BALANCING_NEEDED; 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci/* 131062306a36Sopenharmony_ci * Check whether current node S[h] is balanced when increasing its size by 131162306a36Sopenharmony_ci * Inserting or Pasting. 131262306a36Sopenharmony_ci * Calculate parameters for balancing for current level h. 131362306a36Sopenharmony_ci * Parameters: 131462306a36Sopenharmony_ci * tb tree_balance structure; 131562306a36Sopenharmony_ci * h current level of the node; 131662306a36Sopenharmony_ci * inum item number in S[h]; 131762306a36Sopenharmony_ci * mode i - insert, p - paste; 131862306a36Sopenharmony_ci * Returns: 1 - schedule occurred; 131962306a36Sopenharmony_ci * 0 - balancing for higher levels needed; 132062306a36Sopenharmony_ci * -1 - no balancing for higher levels needed; 132162306a36Sopenharmony_ci * -2 - no disk space. 132262306a36Sopenharmony_ci */ 132362306a36Sopenharmony_ci/* ip means Inserting or Pasting */ 132462306a36Sopenharmony_cistatic int ip_check_balance(struct tree_balance *tb, int h) 132562306a36Sopenharmony_ci{ 132662306a36Sopenharmony_ci struct virtual_node *vn = tb->tb_vn; 132762306a36Sopenharmony_ci /* 132862306a36Sopenharmony_ci * Number of bytes that must be inserted into (value is negative 132962306a36Sopenharmony_ci * if bytes are deleted) buffer which contains node being balanced. 133062306a36Sopenharmony_ci * The mnemonic is that the attempted change in node space used 133162306a36Sopenharmony_ci * level is levbytes bytes. 133262306a36Sopenharmony_ci */ 133362306a36Sopenharmony_ci int levbytes; 133462306a36Sopenharmony_ci int ret; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci int lfree, sfree, rfree /* free space in L, S and R */ ; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci /* 133962306a36Sopenharmony_ci * nver is short for number of vertixes, and lnver is the number if 134062306a36Sopenharmony_ci * we shift to the left, rnver is the number if we shift to the 134162306a36Sopenharmony_ci * right, and lrnver is the number if we shift in both directions. 134262306a36Sopenharmony_ci * The goal is to minimize first the number of vertixes, and second, 134362306a36Sopenharmony_ci * the number of vertixes whose contents are changed by shifting, 134462306a36Sopenharmony_ci * and third the number of uncached vertixes whose contents are 134562306a36Sopenharmony_ci * changed by shifting and must be read from disk. 134662306a36Sopenharmony_ci */ 134762306a36Sopenharmony_ci int nver, lnver, rnver, lrnver; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci /* 135062306a36Sopenharmony_ci * used at leaf level only, S0 = S[0] is the node being balanced, 135162306a36Sopenharmony_ci * sInum [ I = 0,1,2 ] is the number of items that will 135262306a36Sopenharmony_ci * remain in node SI after balancing. S1 and S2 are new 135362306a36Sopenharmony_ci * nodes that might be created. 135462306a36Sopenharmony_ci */ 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci /* 135762306a36Sopenharmony_ci * we perform 8 calls to get_num_ver(). For each call we 135862306a36Sopenharmony_ci * calculate five parameters. where 4th parameter is s1bytes 135962306a36Sopenharmony_ci * and 5th - s2bytes 136062306a36Sopenharmony_ci * 136162306a36Sopenharmony_ci * s0num, s1num, s2num for 8 cases 136262306a36Sopenharmony_ci * 0,1 - do not shift and do not shift but bottle 136362306a36Sopenharmony_ci * 2 - shift only whole item to left 136462306a36Sopenharmony_ci * 3 - shift to left and bottle as much as possible 136562306a36Sopenharmony_ci * 4,5 - shift to right (whole items and as much as possible 136662306a36Sopenharmony_ci * 6,7 - shift to both directions (whole items and as much as possible) 136762306a36Sopenharmony_ci */ 136862306a36Sopenharmony_ci short snum012[40] = { 0, }; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci /* Sh is the node whose balance is currently being checked */ 137162306a36Sopenharmony_ci struct buffer_head *Sh; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci Sh = PATH_H_PBUFFER(tb->tb_path, h); 137462306a36Sopenharmony_ci levbytes = tb->insert_size[h]; 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci /* Calculate balance parameters for creating new root. */ 137762306a36Sopenharmony_ci if (!Sh) { 137862306a36Sopenharmony_ci if (!h) 137962306a36Sopenharmony_ci reiserfs_panic(tb->tb_sb, "vs-8210", 138062306a36Sopenharmony_ci "S[0] can not be 0"); 138162306a36Sopenharmony_ci switch (ret = get_empty_nodes(tb, h)) { 138262306a36Sopenharmony_ci /* no balancing for higher levels needed */ 138362306a36Sopenharmony_ci case CARRY_ON: 138462306a36Sopenharmony_ci set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 138562306a36Sopenharmony_ci return NO_BALANCING_NEEDED; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci case NO_DISK_SPACE: 138862306a36Sopenharmony_ci case REPEAT_SEARCH: 138962306a36Sopenharmony_ci return ret; 139062306a36Sopenharmony_ci default: 139162306a36Sopenharmony_ci reiserfs_panic(tb->tb_sb, "vs-8215", "incorrect " 139262306a36Sopenharmony_ci "return value of get_empty_nodes"); 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci /* get parents of S[h] neighbors. */ 139762306a36Sopenharmony_ci ret = get_parents(tb, h); 139862306a36Sopenharmony_ci if (ret != CARRY_ON) 139962306a36Sopenharmony_ci return ret; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci sfree = B_FREE_SPACE(Sh); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci /* get free space of neighbors */ 140462306a36Sopenharmony_ci rfree = get_rfree(tb, h); 140562306a36Sopenharmony_ci lfree = get_lfree(tb, h); 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci /* and new item fits into node S[h] without any shifting */ 140862306a36Sopenharmony_ci if (can_node_be_removed(vn->vn_mode, lfree, sfree, rfree, tb, h) == 140962306a36Sopenharmony_ci NO_BALANCING_NEEDED) 141062306a36Sopenharmony_ci return NO_BALANCING_NEEDED; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci create_virtual_node(tb, h); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci /* 141562306a36Sopenharmony_ci * determine maximal number of items we can shift to the left 141662306a36Sopenharmony_ci * neighbor (in tb structure) and the maximal number of bytes 141762306a36Sopenharmony_ci * that can flow to the left neighbor from the left most liquid 141862306a36Sopenharmony_ci * item that cannot be shifted from S[0] entirely (returned value) 141962306a36Sopenharmony_ci */ 142062306a36Sopenharmony_ci check_left(tb, h, lfree); 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci /* 142362306a36Sopenharmony_ci * determine maximal number of items we can shift to the right 142462306a36Sopenharmony_ci * neighbor (in tb structure) and the maximal number of bytes 142562306a36Sopenharmony_ci * that can flow to the right neighbor from the right most liquid 142662306a36Sopenharmony_ci * item that cannot be shifted from S[0] entirely (returned value) 142762306a36Sopenharmony_ci */ 142862306a36Sopenharmony_ci check_right(tb, h, rfree); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci /* 143162306a36Sopenharmony_ci * all contents of internal node S[h] can be moved into its 143262306a36Sopenharmony_ci * neighbors, S[h] will be removed after balancing 143362306a36Sopenharmony_ci */ 143462306a36Sopenharmony_ci if (h && (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1)) { 143562306a36Sopenharmony_ci int to_r; 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci /* 143862306a36Sopenharmony_ci * Since we are working on internal nodes, and our internal 143962306a36Sopenharmony_ci * nodes have fixed size entries, then we can balance by the 144062306a36Sopenharmony_ci * number of items rather than the space they consume. In this 144162306a36Sopenharmony_ci * routine we set the left node equal to the right node, 144262306a36Sopenharmony_ci * allowing a difference of less than or equal to 1 child 144362306a36Sopenharmony_ci * pointer. 144462306a36Sopenharmony_ci */ 144562306a36Sopenharmony_ci to_r = 144662306a36Sopenharmony_ci ((MAX_NR_KEY(Sh) << 1) + 2 - tb->lnum[h] - tb->rnum[h] + 144762306a36Sopenharmony_ci vn->vn_nr_item + 1) / 2 - (MAX_NR_KEY(Sh) + 1 - 144862306a36Sopenharmony_ci tb->rnum[h]); 144962306a36Sopenharmony_ci set_parameters(tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, 145062306a36Sopenharmony_ci -1, -1); 145162306a36Sopenharmony_ci return CARRY_ON; 145262306a36Sopenharmony_ci } 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci /* 145562306a36Sopenharmony_ci * this checks balance condition, that any two neighboring nodes 145662306a36Sopenharmony_ci * can not fit in one node 145762306a36Sopenharmony_ci */ 145862306a36Sopenharmony_ci RFALSE(h && 145962306a36Sopenharmony_ci (tb->lnum[h] >= vn->vn_nr_item + 1 || 146062306a36Sopenharmony_ci tb->rnum[h] >= vn->vn_nr_item + 1), 146162306a36Sopenharmony_ci "vs-8220: tree is not balanced on internal level"); 146262306a36Sopenharmony_ci RFALSE(!h && ((tb->lnum[h] >= vn->vn_nr_item && (tb->lbytes == -1)) || 146362306a36Sopenharmony_ci (tb->rnum[h] >= vn->vn_nr_item && (tb->rbytes == -1))), 146462306a36Sopenharmony_ci "vs-8225: tree is not balanced on leaf level"); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci /* 146762306a36Sopenharmony_ci * all contents of S[0] can be moved into its neighbors 146862306a36Sopenharmony_ci * S[0] will be removed after balancing. 146962306a36Sopenharmony_ci */ 147062306a36Sopenharmony_ci if (!h && is_leaf_removable(tb)) 147162306a36Sopenharmony_ci return CARRY_ON; 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci /* 147462306a36Sopenharmony_ci * why do we perform this check here rather than earlier?? 147562306a36Sopenharmony_ci * Answer: we can win 1 node in some cases above. Moreover we 147662306a36Sopenharmony_ci * checked it above, when we checked, that S[0] is not removable 147762306a36Sopenharmony_ci * in principle 147862306a36Sopenharmony_ci */ 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci /* new item fits into node S[h] without any shifting */ 148162306a36Sopenharmony_ci if (sfree >= levbytes) { 148262306a36Sopenharmony_ci if (!h) 148362306a36Sopenharmony_ci tb->s0num = vn->vn_nr_item; 148462306a36Sopenharmony_ci set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 148562306a36Sopenharmony_ci return NO_BALANCING_NEEDED; 148662306a36Sopenharmony_ci } 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci { 148962306a36Sopenharmony_ci int lpar, rpar, nset, lset, rset, lrset; 149062306a36Sopenharmony_ci /* regular overflowing of the node */ 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci /* 149362306a36Sopenharmony_ci * get_num_ver works in 2 modes (FLOW & NO_FLOW) 149462306a36Sopenharmony_ci * lpar, rpar - number of items we can shift to left/right 149562306a36Sopenharmony_ci * neighbor (including splitting item) 149662306a36Sopenharmony_ci * nset, lset, rset, lrset - shows, whether flowing items 149762306a36Sopenharmony_ci * give better packing 149862306a36Sopenharmony_ci */ 149962306a36Sopenharmony_ci#define FLOW 1 150062306a36Sopenharmony_ci#define NO_FLOW 0 /* do not any splitting */ 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci /* we choose one of the following */ 150362306a36Sopenharmony_ci#define NOTHING_SHIFT_NO_FLOW 0 150462306a36Sopenharmony_ci#define NOTHING_SHIFT_FLOW 5 150562306a36Sopenharmony_ci#define LEFT_SHIFT_NO_FLOW 10 150662306a36Sopenharmony_ci#define LEFT_SHIFT_FLOW 15 150762306a36Sopenharmony_ci#define RIGHT_SHIFT_NO_FLOW 20 150862306a36Sopenharmony_ci#define RIGHT_SHIFT_FLOW 25 150962306a36Sopenharmony_ci#define LR_SHIFT_NO_FLOW 30 151062306a36Sopenharmony_ci#define LR_SHIFT_FLOW 35 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci lpar = tb->lnum[h]; 151362306a36Sopenharmony_ci rpar = tb->rnum[h]; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci /* 151662306a36Sopenharmony_ci * calculate number of blocks S[h] must be split into when 151762306a36Sopenharmony_ci * nothing is shifted to the neighbors, as well as number of 151862306a36Sopenharmony_ci * items in each part of the split node (s012 numbers), 151962306a36Sopenharmony_ci * and number of bytes (s1bytes) of the shared drop which 152062306a36Sopenharmony_ci * flow to S1 if any 152162306a36Sopenharmony_ci */ 152262306a36Sopenharmony_ci nset = NOTHING_SHIFT_NO_FLOW; 152362306a36Sopenharmony_ci nver = get_num_ver(vn->vn_mode, tb, h, 152462306a36Sopenharmony_ci 0, -1, h ? vn->vn_nr_item : 0, -1, 152562306a36Sopenharmony_ci snum012, NO_FLOW); 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci if (!h) { 152862306a36Sopenharmony_ci int nver1; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci /* 153162306a36Sopenharmony_ci * note, that in this case we try to bottle 153262306a36Sopenharmony_ci * between S[0] and S1 (S1 - the first new node) 153362306a36Sopenharmony_ci */ 153462306a36Sopenharmony_ci nver1 = get_num_ver(vn->vn_mode, tb, h, 153562306a36Sopenharmony_ci 0, -1, 0, -1, 153662306a36Sopenharmony_ci snum012 + NOTHING_SHIFT_FLOW, FLOW); 153762306a36Sopenharmony_ci if (nver > nver1) 153862306a36Sopenharmony_ci nset = NOTHING_SHIFT_FLOW, nver = nver1; 153962306a36Sopenharmony_ci } 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci /* 154262306a36Sopenharmony_ci * calculate number of blocks S[h] must be split into when 154362306a36Sopenharmony_ci * l_shift_num first items and l_shift_bytes of the right 154462306a36Sopenharmony_ci * most liquid item to be shifted are shifted to the left 154562306a36Sopenharmony_ci * neighbor, as well as number of items in each part of the 154662306a36Sopenharmony_ci * splitted node (s012 numbers), and number of bytes 154762306a36Sopenharmony_ci * (s1bytes) of the shared drop which flow to S1 if any 154862306a36Sopenharmony_ci */ 154962306a36Sopenharmony_ci lset = LEFT_SHIFT_NO_FLOW; 155062306a36Sopenharmony_ci lnver = get_num_ver(vn->vn_mode, tb, h, 155162306a36Sopenharmony_ci lpar - ((h || tb->lbytes == -1) ? 0 : 1), 155262306a36Sopenharmony_ci -1, h ? vn->vn_nr_item : 0, -1, 155362306a36Sopenharmony_ci snum012 + LEFT_SHIFT_NO_FLOW, NO_FLOW); 155462306a36Sopenharmony_ci if (!h) { 155562306a36Sopenharmony_ci int lnver1; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci lnver1 = get_num_ver(vn->vn_mode, tb, h, 155862306a36Sopenharmony_ci lpar - 155962306a36Sopenharmony_ci ((tb->lbytes != -1) ? 1 : 0), 156062306a36Sopenharmony_ci tb->lbytes, 0, -1, 156162306a36Sopenharmony_ci snum012 + LEFT_SHIFT_FLOW, FLOW); 156262306a36Sopenharmony_ci if (lnver > lnver1) 156362306a36Sopenharmony_ci lset = LEFT_SHIFT_FLOW, lnver = lnver1; 156462306a36Sopenharmony_ci } 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci /* 156762306a36Sopenharmony_ci * calculate number of blocks S[h] must be split into when 156862306a36Sopenharmony_ci * r_shift_num first items and r_shift_bytes of the left most 156962306a36Sopenharmony_ci * liquid item to be shifted are shifted to the right neighbor, 157062306a36Sopenharmony_ci * as well as number of items in each part of the splitted 157162306a36Sopenharmony_ci * node (s012 numbers), and number of bytes (s1bytes) of the 157262306a36Sopenharmony_ci * shared drop which flow to S1 if any 157362306a36Sopenharmony_ci */ 157462306a36Sopenharmony_ci rset = RIGHT_SHIFT_NO_FLOW; 157562306a36Sopenharmony_ci rnver = get_num_ver(vn->vn_mode, tb, h, 157662306a36Sopenharmony_ci 0, -1, 157762306a36Sopenharmony_ci h ? (vn->vn_nr_item - rpar) : (rpar - 157862306a36Sopenharmony_ci ((tb-> 157962306a36Sopenharmony_ci rbytes != 158062306a36Sopenharmony_ci -1) ? 1 : 158162306a36Sopenharmony_ci 0)), -1, 158262306a36Sopenharmony_ci snum012 + RIGHT_SHIFT_NO_FLOW, NO_FLOW); 158362306a36Sopenharmony_ci if (!h) { 158462306a36Sopenharmony_ci int rnver1; 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci rnver1 = get_num_ver(vn->vn_mode, tb, h, 158762306a36Sopenharmony_ci 0, -1, 158862306a36Sopenharmony_ci (rpar - 158962306a36Sopenharmony_ci ((tb->rbytes != -1) ? 1 : 0)), 159062306a36Sopenharmony_ci tb->rbytes, 159162306a36Sopenharmony_ci snum012 + RIGHT_SHIFT_FLOW, FLOW); 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci if (rnver > rnver1) 159462306a36Sopenharmony_ci rset = RIGHT_SHIFT_FLOW, rnver = rnver1; 159562306a36Sopenharmony_ci } 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci /* 159862306a36Sopenharmony_ci * calculate number of blocks S[h] must be split into when 159962306a36Sopenharmony_ci * items are shifted in both directions, as well as number 160062306a36Sopenharmony_ci * of items in each part of the splitted node (s012 numbers), 160162306a36Sopenharmony_ci * and number of bytes (s1bytes) of the shared drop which 160262306a36Sopenharmony_ci * flow to S1 if any 160362306a36Sopenharmony_ci */ 160462306a36Sopenharmony_ci lrset = LR_SHIFT_NO_FLOW; 160562306a36Sopenharmony_ci lrnver = get_num_ver(vn->vn_mode, tb, h, 160662306a36Sopenharmony_ci lpar - ((h || tb->lbytes == -1) ? 0 : 1), 160762306a36Sopenharmony_ci -1, 160862306a36Sopenharmony_ci h ? (vn->vn_nr_item - rpar) : (rpar - 160962306a36Sopenharmony_ci ((tb-> 161062306a36Sopenharmony_ci rbytes != 161162306a36Sopenharmony_ci -1) ? 1 : 161262306a36Sopenharmony_ci 0)), -1, 161362306a36Sopenharmony_ci snum012 + LR_SHIFT_NO_FLOW, NO_FLOW); 161462306a36Sopenharmony_ci if (!h) { 161562306a36Sopenharmony_ci int lrnver1; 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci lrnver1 = get_num_ver(vn->vn_mode, tb, h, 161862306a36Sopenharmony_ci lpar - 161962306a36Sopenharmony_ci ((tb->lbytes != -1) ? 1 : 0), 162062306a36Sopenharmony_ci tb->lbytes, 162162306a36Sopenharmony_ci (rpar - 162262306a36Sopenharmony_ci ((tb->rbytes != -1) ? 1 : 0)), 162362306a36Sopenharmony_ci tb->rbytes, 162462306a36Sopenharmony_ci snum012 + LR_SHIFT_FLOW, FLOW); 162562306a36Sopenharmony_ci if (lrnver > lrnver1) 162662306a36Sopenharmony_ci lrset = LR_SHIFT_FLOW, lrnver = lrnver1; 162762306a36Sopenharmony_ci } 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci /* 163062306a36Sopenharmony_ci * Our general shifting strategy is: 163162306a36Sopenharmony_ci * 1) to minimized number of new nodes; 163262306a36Sopenharmony_ci * 2) to minimized number of neighbors involved in shifting; 163362306a36Sopenharmony_ci * 3) to minimized number of disk reads; 163462306a36Sopenharmony_ci */ 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci /* we can win TWO or ONE nodes by shifting in both directions */ 163762306a36Sopenharmony_ci if (lrnver < lnver && lrnver < rnver) { 163862306a36Sopenharmony_ci RFALSE(h && 163962306a36Sopenharmony_ci (tb->lnum[h] != 1 || 164062306a36Sopenharmony_ci tb->rnum[h] != 1 || 164162306a36Sopenharmony_ci lrnver != 1 || rnver != 2 || lnver != 2 164262306a36Sopenharmony_ci || h != 1), "vs-8230: bad h"); 164362306a36Sopenharmony_ci if (lrset == LR_SHIFT_FLOW) 164462306a36Sopenharmony_ci set_parameters(tb, h, tb->lnum[h], tb->rnum[h], 164562306a36Sopenharmony_ci lrnver, snum012 + lrset, 164662306a36Sopenharmony_ci tb->lbytes, tb->rbytes); 164762306a36Sopenharmony_ci else 164862306a36Sopenharmony_ci set_parameters(tb, h, 164962306a36Sopenharmony_ci tb->lnum[h] - 165062306a36Sopenharmony_ci ((tb->lbytes == -1) ? 0 : 1), 165162306a36Sopenharmony_ci tb->rnum[h] - 165262306a36Sopenharmony_ci ((tb->rbytes == -1) ? 0 : 1), 165362306a36Sopenharmony_ci lrnver, snum012 + lrset, -1, -1); 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci return CARRY_ON; 165662306a36Sopenharmony_ci } 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci /* 165962306a36Sopenharmony_ci * if shifting doesn't lead to better packing 166062306a36Sopenharmony_ci * then don't shift 166162306a36Sopenharmony_ci */ 166262306a36Sopenharmony_ci if (nver == lrnver) { 166362306a36Sopenharmony_ci set_parameters(tb, h, 0, 0, nver, snum012 + nset, -1, 166462306a36Sopenharmony_ci -1); 166562306a36Sopenharmony_ci return CARRY_ON; 166662306a36Sopenharmony_ci } 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci /* 166962306a36Sopenharmony_ci * now we know that for better packing shifting in only one 167062306a36Sopenharmony_ci * direction either to the left or to the right is required 167162306a36Sopenharmony_ci */ 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci /* 167462306a36Sopenharmony_ci * if shifting to the left is better than 167562306a36Sopenharmony_ci * shifting to the right 167662306a36Sopenharmony_ci */ 167762306a36Sopenharmony_ci if (lnver < rnver) { 167862306a36Sopenharmony_ci SET_PAR_SHIFT_LEFT; 167962306a36Sopenharmony_ci return CARRY_ON; 168062306a36Sopenharmony_ci } 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci /* 168362306a36Sopenharmony_ci * if shifting to the right is better than 168462306a36Sopenharmony_ci * shifting to the left 168562306a36Sopenharmony_ci */ 168662306a36Sopenharmony_ci if (lnver > rnver) { 168762306a36Sopenharmony_ci SET_PAR_SHIFT_RIGHT; 168862306a36Sopenharmony_ci return CARRY_ON; 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci /* 169262306a36Sopenharmony_ci * now shifting in either direction gives the same number 169362306a36Sopenharmony_ci * of nodes and we can make use of the cached neighbors 169462306a36Sopenharmony_ci */ 169562306a36Sopenharmony_ci if (is_left_neighbor_in_cache(tb, h)) { 169662306a36Sopenharmony_ci SET_PAR_SHIFT_LEFT; 169762306a36Sopenharmony_ci return CARRY_ON; 169862306a36Sopenharmony_ci } 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci /* 170162306a36Sopenharmony_ci * shift to the right independently on whether the 170262306a36Sopenharmony_ci * right neighbor in cache or not 170362306a36Sopenharmony_ci */ 170462306a36Sopenharmony_ci SET_PAR_SHIFT_RIGHT; 170562306a36Sopenharmony_ci return CARRY_ON; 170662306a36Sopenharmony_ci } 170762306a36Sopenharmony_ci} 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci/* 171062306a36Sopenharmony_ci * Check whether current node S[h] is balanced when Decreasing its size by 171162306a36Sopenharmony_ci * Deleting or Cutting for INTERNAL node of S+tree. 171262306a36Sopenharmony_ci * Calculate parameters for balancing for current level h. 171362306a36Sopenharmony_ci * Parameters: 171462306a36Sopenharmony_ci * tb tree_balance structure; 171562306a36Sopenharmony_ci * h current level of the node; 171662306a36Sopenharmony_ci * inum item number in S[h]; 171762306a36Sopenharmony_ci * mode i - insert, p - paste; 171862306a36Sopenharmony_ci * Returns: 1 - schedule occurred; 171962306a36Sopenharmony_ci * 0 - balancing for higher levels needed; 172062306a36Sopenharmony_ci * -1 - no balancing for higher levels needed; 172162306a36Sopenharmony_ci * -2 - no disk space. 172262306a36Sopenharmony_ci * 172362306a36Sopenharmony_ci * Note: Items of internal nodes have fixed size, so the balance condition for 172462306a36Sopenharmony_ci * the internal part of S+tree is as for the B-trees. 172562306a36Sopenharmony_ci */ 172662306a36Sopenharmony_cistatic int dc_check_balance_internal(struct tree_balance *tb, int h) 172762306a36Sopenharmony_ci{ 172862306a36Sopenharmony_ci struct virtual_node *vn = tb->tb_vn; 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci /* 173162306a36Sopenharmony_ci * Sh is the node whose balance is currently being checked, 173262306a36Sopenharmony_ci * and Fh is its father. 173362306a36Sopenharmony_ci */ 173462306a36Sopenharmony_ci struct buffer_head *Sh, *Fh; 173562306a36Sopenharmony_ci int ret; 173662306a36Sopenharmony_ci int lfree, rfree /* free space in L and R */ ; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci Sh = PATH_H_PBUFFER(tb->tb_path, h); 173962306a36Sopenharmony_ci Fh = PATH_H_PPARENT(tb->tb_path, h); 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci /* 174262306a36Sopenharmony_ci * using tb->insert_size[h], which is negative in this case, 174362306a36Sopenharmony_ci * create_virtual_node calculates: 174462306a36Sopenharmony_ci * new_nr_item = number of items node would have if operation is 174562306a36Sopenharmony_ci * performed without balancing (new_nr_item); 174662306a36Sopenharmony_ci */ 174762306a36Sopenharmony_ci create_virtual_node(tb, h); 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci if (!Fh) { /* S[h] is the root. */ 175062306a36Sopenharmony_ci /* no balancing for higher levels needed */ 175162306a36Sopenharmony_ci if (vn->vn_nr_item > 0) { 175262306a36Sopenharmony_ci set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 175362306a36Sopenharmony_ci return NO_BALANCING_NEEDED; 175462306a36Sopenharmony_ci } 175562306a36Sopenharmony_ci /* 175662306a36Sopenharmony_ci * new_nr_item == 0. 175762306a36Sopenharmony_ci * Current root will be deleted resulting in 175862306a36Sopenharmony_ci * decrementing the tree height. 175962306a36Sopenharmony_ci */ 176062306a36Sopenharmony_ci set_parameters(tb, h, 0, 0, 0, NULL, -1, -1); 176162306a36Sopenharmony_ci return CARRY_ON; 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci if ((ret = get_parents(tb, h)) != CARRY_ON) 176562306a36Sopenharmony_ci return ret; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci /* get free space of neighbors */ 176862306a36Sopenharmony_ci rfree = get_rfree(tb, h); 176962306a36Sopenharmony_ci lfree = get_lfree(tb, h); 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci /* determine maximal number of items we can fit into neighbors */ 177262306a36Sopenharmony_ci check_left(tb, h, lfree); 177362306a36Sopenharmony_ci check_right(tb, h, rfree); 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci /* 177662306a36Sopenharmony_ci * Balance condition for the internal node is valid. 177762306a36Sopenharmony_ci * In this case we balance only if it leads to better packing. 177862306a36Sopenharmony_ci */ 177962306a36Sopenharmony_ci if (vn->vn_nr_item >= MIN_NR_KEY(Sh)) { 178062306a36Sopenharmony_ci /* 178162306a36Sopenharmony_ci * Here we join S[h] with one of its neighbors, 178262306a36Sopenharmony_ci * which is impossible with greater values of new_nr_item. 178362306a36Sopenharmony_ci */ 178462306a36Sopenharmony_ci if (vn->vn_nr_item == MIN_NR_KEY(Sh)) { 178562306a36Sopenharmony_ci /* All contents of S[h] can be moved to L[h]. */ 178662306a36Sopenharmony_ci if (tb->lnum[h] >= vn->vn_nr_item + 1) { 178762306a36Sopenharmony_ci int n; 178862306a36Sopenharmony_ci int order_L; 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci order_L = 179162306a36Sopenharmony_ci ((n = 179262306a36Sopenharmony_ci PATH_H_B_ITEM_ORDER(tb->tb_path, 179362306a36Sopenharmony_ci h)) == 179462306a36Sopenharmony_ci 0) ? B_NR_ITEMS(tb->FL[h]) : n - 1; 179562306a36Sopenharmony_ci n = dc_size(B_N_CHILD(tb->FL[h], order_L)) / 179662306a36Sopenharmony_ci (DC_SIZE + KEY_SIZE); 179762306a36Sopenharmony_ci set_parameters(tb, h, -n - 1, 0, 0, NULL, -1, 179862306a36Sopenharmony_ci -1); 179962306a36Sopenharmony_ci return CARRY_ON; 180062306a36Sopenharmony_ci } 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci /* All contents of S[h] can be moved to R[h]. */ 180362306a36Sopenharmony_ci if (tb->rnum[h] >= vn->vn_nr_item + 1) { 180462306a36Sopenharmony_ci int n; 180562306a36Sopenharmony_ci int order_R; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci order_R = 180862306a36Sopenharmony_ci ((n = 180962306a36Sopenharmony_ci PATH_H_B_ITEM_ORDER(tb->tb_path, 181062306a36Sopenharmony_ci h)) == 181162306a36Sopenharmony_ci B_NR_ITEMS(Fh)) ? 0 : n + 1; 181262306a36Sopenharmony_ci n = dc_size(B_N_CHILD(tb->FR[h], order_R)) / 181362306a36Sopenharmony_ci (DC_SIZE + KEY_SIZE); 181462306a36Sopenharmony_ci set_parameters(tb, h, 0, -n - 1, 0, NULL, -1, 181562306a36Sopenharmony_ci -1); 181662306a36Sopenharmony_ci return CARRY_ON; 181762306a36Sopenharmony_ci } 181862306a36Sopenharmony_ci } 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci /* 182162306a36Sopenharmony_ci * All contents of S[h] can be moved to the neighbors 182262306a36Sopenharmony_ci * (L[h] & R[h]). 182362306a36Sopenharmony_ci */ 182462306a36Sopenharmony_ci if (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1) { 182562306a36Sopenharmony_ci int to_r; 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci to_r = 182862306a36Sopenharmony_ci ((MAX_NR_KEY(Sh) << 1) + 2 - tb->lnum[h] - 182962306a36Sopenharmony_ci tb->rnum[h] + vn->vn_nr_item + 1) / 2 - 183062306a36Sopenharmony_ci (MAX_NR_KEY(Sh) + 1 - tb->rnum[h]); 183162306a36Sopenharmony_ci set_parameters(tb, h, vn->vn_nr_item + 1 - to_r, to_r, 183262306a36Sopenharmony_ci 0, NULL, -1, -1); 183362306a36Sopenharmony_ci return CARRY_ON; 183462306a36Sopenharmony_ci } 183562306a36Sopenharmony_ci 183662306a36Sopenharmony_ci /* Balancing does not lead to better packing. */ 183762306a36Sopenharmony_ci set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 183862306a36Sopenharmony_ci return NO_BALANCING_NEEDED; 183962306a36Sopenharmony_ci } 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci /* 184262306a36Sopenharmony_ci * Current node contain insufficient number of items. 184362306a36Sopenharmony_ci * Balancing is required. 184462306a36Sopenharmony_ci */ 184562306a36Sopenharmony_ci /* Check whether we can merge S[h] with left neighbor. */ 184662306a36Sopenharmony_ci if (tb->lnum[h] >= vn->vn_nr_item + 1) 184762306a36Sopenharmony_ci if (is_left_neighbor_in_cache(tb, h) 184862306a36Sopenharmony_ci || tb->rnum[h] < vn->vn_nr_item + 1 || !tb->FR[h]) { 184962306a36Sopenharmony_ci int n; 185062306a36Sopenharmony_ci int order_L; 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci order_L = 185362306a36Sopenharmony_ci ((n = 185462306a36Sopenharmony_ci PATH_H_B_ITEM_ORDER(tb->tb_path, 185562306a36Sopenharmony_ci h)) == 185662306a36Sopenharmony_ci 0) ? B_NR_ITEMS(tb->FL[h]) : n - 1; 185762306a36Sopenharmony_ci n = dc_size(B_N_CHILD(tb->FL[h], order_L)) / (DC_SIZE + 185862306a36Sopenharmony_ci KEY_SIZE); 185962306a36Sopenharmony_ci set_parameters(tb, h, -n - 1, 0, 0, NULL, -1, -1); 186062306a36Sopenharmony_ci return CARRY_ON; 186162306a36Sopenharmony_ci } 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci /* Check whether we can merge S[h] with right neighbor. */ 186462306a36Sopenharmony_ci if (tb->rnum[h] >= vn->vn_nr_item + 1) { 186562306a36Sopenharmony_ci int n; 186662306a36Sopenharmony_ci int order_R; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci order_R = 186962306a36Sopenharmony_ci ((n = 187062306a36Sopenharmony_ci PATH_H_B_ITEM_ORDER(tb->tb_path, 187162306a36Sopenharmony_ci h)) == B_NR_ITEMS(Fh)) ? 0 : (n + 1); 187262306a36Sopenharmony_ci n = dc_size(B_N_CHILD(tb->FR[h], order_R)) / (DC_SIZE + 187362306a36Sopenharmony_ci KEY_SIZE); 187462306a36Sopenharmony_ci set_parameters(tb, h, 0, -n - 1, 0, NULL, -1, -1); 187562306a36Sopenharmony_ci return CARRY_ON; 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci /* All contents of S[h] can be moved to the neighbors (L[h] & R[h]). */ 187962306a36Sopenharmony_ci if (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1) { 188062306a36Sopenharmony_ci int to_r; 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci to_r = 188362306a36Sopenharmony_ci ((MAX_NR_KEY(Sh) << 1) + 2 - tb->lnum[h] - tb->rnum[h] + 188462306a36Sopenharmony_ci vn->vn_nr_item + 1) / 2 - (MAX_NR_KEY(Sh) + 1 - 188562306a36Sopenharmony_ci tb->rnum[h]); 188662306a36Sopenharmony_ci set_parameters(tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, 188762306a36Sopenharmony_ci -1, -1); 188862306a36Sopenharmony_ci return CARRY_ON; 188962306a36Sopenharmony_ci } 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci /* For internal nodes try to borrow item from a neighbor */ 189262306a36Sopenharmony_ci RFALSE(!tb->FL[h] && !tb->FR[h], "vs-8235: trying to borrow for root"); 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci /* Borrow one or two items from caching neighbor */ 189562306a36Sopenharmony_ci if (is_left_neighbor_in_cache(tb, h) || !tb->FR[h]) { 189662306a36Sopenharmony_ci int from_l; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci from_l = 189962306a36Sopenharmony_ci (MAX_NR_KEY(Sh) + 1 - tb->lnum[h] + vn->vn_nr_item + 190062306a36Sopenharmony_ci 1) / 2 - (vn->vn_nr_item + 1); 190162306a36Sopenharmony_ci set_parameters(tb, h, -from_l, 0, 1, NULL, -1, -1); 190262306a36Sopenharmony_ci return CARRY_ON; 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci set_parameters(tb, h, 0, 190662306a36Sopenharmony_ci -((MAX_NR_KEY(Sh) + 1 - tb->rnum[h] + vn->vn_nr_item + 190762306a36Sopenharmony_ci 1) / 2 - (vn->vn_nr_item + 1)), 1, NULL, -1, -1); 190862306a36Sopenharmony_ci return CARRY_ON; 190962306a36Sopenharmony_ci} 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci/* 191262306a36Sopenharmony_ci * Check whether current node S[h] is balanced when Decreasing its size by 191362306a36Sopenharmony_ci * Deleting or Truncating for LEAF node of S+tree. 191462306a36Sopenharmony_ci * Calculate parameters for balancing for current level h. 191562306a36Sopenharmony_ci * Parameters: 191662306a36Sopenharmony_ci * tb tree_balance structure; 191762306a36Sopenharmony_ci * h current level of the node; 191862306a36Sopenharmony_ci * inum item number in S[h]; 191962306a36Sopenharmony_ci * mode i - insert, p - paste; 192062306a36Sopenharmony_ci * Returns: 1 - schedule occurred; 192162306a36Sopenharmony_ci * 0 - balancing for higher levels needed; 192262306a36Sopenharmony_ci * -1 - no balancing for higher levels needed; 192362306a36Sopenharmony_ci * -2 - no disk space. 192462306a36Sopenharmony_ci */ 192562306a36Sopenharmony_cistatic int dc_check_balance_leaf(struct tree_balance *tb, int h) 192662306a36Sopenharmony_ci{ 192762306a36Sopenharmony_ci struct virtual_node *vn = tb->tb_vn; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci /* 193062306a36Sopenharmony_ci * Number of bytes that must be deleted from 193162306a36Sopenharmony_ci * (value is negative if bytes are deleted) buffer which 193262306a36Sopenharmony_ci * contains node being balanced. The mnemonic is that the 193362306a36Sopenharmony_ci * attempted change in node space used level is levbytes bytes. 193462306a36Sopenharmony_ci */ 193562306a36Sopenharmony_ci int levbytes; 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci /* the maximal item size */ 193862306a36Sopenharmony_ci int maxsize, ret; 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_ci /* 194162306a36Sopenharmony_ci * S0 is the node whose balance is currently being checked, 194262306a36Sopenharmony_ci * and F0 is its father. 194362306a36Sopenharmony_ci */ 194462306a36Sopenharmony_ci struct buffer_head *S0, *F0; 194562306a36Sopenharmony_ci int lfree, rfree /* free space in L and R */ ; 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_ci S0 = PATH_H_PBUFFER(tb->tb_path, 0); 194862306a36Sopenharmony_ci F0 = PATH_H_PPARENT(tb->tb_path, 0); 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci levbytes = tb->insert_size[h]; 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci maxsize = MAX_CHILD_SIZE(S0); /* maximal possible size of an item */ 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci if (!F0) { /* S[0] is the root now. */ 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci RFALSE(-levbytes >= maxsize - B_FREE_SPACE(S0), 195762306a36Sopenharmony_ci "vs-8240: attempt to create empty buffer tree"); 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 196062306a36Sopenharmony_ci return NO_BALANCING_NEEDED; 196162306a36Sopenharmony_ci } 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci if ((ret = get_parents(tb, h)) != CARRY_ON) 196462306a36Sopenharmony_ci return ret; 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci /* get free space of neighbors */ 196762306a36Sopenharmony_ci rfree = get_rfree(tb, h); 196862306a36Sopenharmony_ci lfree = get_lfree(tb, h); 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci create_virtual_node(tb, h); 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci /* if 3 leaves can be merge to one, set parameters and return */ 197362306a36Sopenharmony_ci if (are_leaves_removable(tb, lfree, rfree)) 197462306a36Sopenharmony_ci return CARRY_ON; 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci /* 197762306a36Sopenharmony_ci * determine maximal number of items we can shift to the left/right 197862306a36Sopenharmony_ci * neighbor and the maximal number of bytes that can flow to the 197962306a36Sopenharmony_ci * left/right neighbor from the left/right most liquid item that 198062306a36Sopenharmony_ci * cannot be shifted from S[0] entirely 198162306a36Sopenharmony_ci */ 198262306a36Sopenharmony_ci check_left(tb, h, lfree); 198362306a36Sopenharmony_ci check_right(tb, h, rfree); 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci /* check whether we can merge S with left neighbor. */ 198662306a36Sopenharmony_ci if (tb->lnum[0] >= vn->vn_nr_item && tb->lbytes == -1) 198762306a36Sopenharmony_ci if (is_left_neighbor_in_cache(tb, h) || ((tb->rnum[0] - ((tb->rbytes == -1) ? 0 : 1)) < vn->vn_nr_item) || /* S can not be merged with R */ 198862306a36Sopenharmony_ci !tb->FR[h]) { 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci RFALSE(!tb->FL[h], 199162306a36Sopenharmony_ci "vs-8245: dc_check_balance_leaf: FL[h] must exist"); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci /* set parameter to merge S[0] with its left neighbor */ 199462306a36Sopenharmony_ci set_parameters(tb, h, -1, 0, 0, NULL, -1, -1); 199562306a36Sopenharmony_ci return CARRY_ON; 199662306a36Sopenharmony_ci } 199762306a36Sopenharmony_ci 199862306a36Sopenharmony_ci /* check whether we can merge S[0] with right neighbor. */ 199962306a36Sopenharmony_ci if (tb->rnum[0] >= vn->vn_nr_item && tb->rbytes == -1) { 200062306a36Sopenharmony_ci set_parameters(tb, h, 0, -1, 0, NULL, -1, -1); 200162306a36Sopenharmony_ci return CARRY_ON; 200262306a36Sopenharmony_ci } 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci /* 200562306a36Sopenharmony_ci * All contents of S[0] can be moved to the neighbors (L[0] & R[0]). 200662306a36Sopenharmony_ci * Set parameters and return 200762306a36Sopenharmony_ci */ 200862306a36Sopenharmony_ci if (is_leaf_removable(tb)) 200962306a36Sopenharmony_ci return CARRY_ON; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci /* Balancing is not required. */ 201262306a36Sopenharmony_ci tb->s0num = vn->vn_nr_item; 201362306a36Sopenharmony_ci set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 201462306a36Sopenharmony_ci return NO_BALANCING_NEEDED; 201562306a36Sopenharmony_ci} 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci/* 201862306a36Sopenharmony_ci * Check whether current node S[h] is balanced when Decreasing its size by 201962306a36Sopenharmony_ci * Deleting or Cutting. 202062306a36Sopenharmony_ci * Calculate parameters for balancing for current level h. 202162306a36Sopenharmony_ci * Parameters: 202262306a36Sopenharmony_ci * tb tree_balance structure; 202362306a36Sopenharmony_ci * h current level of the node; 202462306a36Sopenharmony_ci * inum item number in S[h]; 202562306a36Sopenharmony_ci * mode d - delete, c - cut. 202662306a36Sopenharmony_ci * Returns: 1 - schedule occurred; 202762306a36Sopenharmony_ci * 0 - balancing for higher levels needed; 202862306a36Sopenharmony_ci * -1 - no balancing for higher levels needed; 202962306a36Sopenharmony_ci * -2 - no disk space. 203062306a36Sopenharmony_ci */ 203162306a36Sopenharmony_cistatic int dc_check_balance(struct tree_balance *tb, int h) 203262306a36Sopenharmony_ci{ 203362306a36Sopenharmony_ci RFALSE(!(PATH_H_PBUFFER(tb->tb_path, h)), 203462306a36Sopenharmony_ci "vs-8250: S is not initialized"); 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci if (h) 203762306a36Sopenharmony_ci return dc_check_balance_internal(tb, h); 203862306a36Sopenharmony_ci else 203962306a36Sopenharmony_ci return dc_check_balance_leaf(tb, h); 204062306a36Sopenharmony_ci} 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci/* 204362306a36Sopenharmony_ci * Check whether current node S[h] is balanced. 204462306a36Sopenharmony_ci * Calculate parameters for balancing for current level h. 204562306a36Sopenharmony_ci * Parameters: 204662306a36Sopenharmony_ci * 204762306a36Sopenharmony_ci * tb tree_balance structure: 204862306a36Sopenharmony_ci * 204962306a36Sopenharmony_ci * tb is a large structure that must be read about in the header 205062306a36Sopenharmony_ci * file at the same time as this procedure if the reader is 205162306a36Sopenharmony_ci * to successfully understand this procedure 205262306a36Sopenharmony_ci * 205362306a36Sopenharmony_ci * h current level of the node; 205462306a36Sopenharmony_ci * inum item number in S[h]; 205562306a36Sopenharmony_ci * mode i - insert, p - paste, d - delete, c - cut. 205662306a36Sopenharmony_ci * Returns: 1 - schedule occurred; 205762306a36Sopenharmony_ci * 0 - balancing for higher levels needed; 205862306a36Sopenharmony_ci * -1 - no balancing for higher levels needed; 205962306a36Sopenharmony_ci * -2 - no disk space. 206062306a36Sopenharmony_ci */ 206162306a36Sopenharmony_cistatic int check_balance(int mode, 206262306a36Sopenharmony_ci struct tree_balance *tb, 206362306a36Sopenharmony_ci int h, 206462306a36Sopenharmony_ci int inum, 206562306a36Sopenharmony_ci int pos_in_item, 206662306a36Sopenharmony_ci struct item_head *ins_ih, const void *data) 206762306a36Sopenharmony_ci{ 206862306a36Sopenharmony_ci struct virtual_node *vn; 206962306a36Sopenharmony_ci 207062306a36Sopenharmony_ci vn = tb->tb_vn = (struct virtual_node *)(tb->vn_buf); 207162306a36Sopenharmony_ci vn->vn_free_ptr = (char *)(tb->tb_vn + 1); 207262306a36Sopenharmony_ci vn->vn_mode = mode; 207362306a36Sopenharmony_ci vn->vn_affected_item_num = inum; 207462306a36Sopenharmony_ci vn->vn_pos_in_item = pos_in_item; 207562306a36Sopenharmony_ci vn->vn_ins_ih = ins_ih; 207662306a36Sopenharmony_ci vn->vn_data = data; 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci RFALSE(mode == M_INSERT && !vn->vn_ins_ih, 207962306a36Sopenharmony_ci "vs-8255: ins_ih can not be 0 in insert mode"); 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_ci /* Calculate balance parameters when size of node is increasing. */ 208262306a36Sopenharmony_ci if (tb->insert_size[h] > 0) 208362306a36Sopenharmony_ci return ip_check_balance(tb, h); 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci /* Calculate balance parameters when size of node is decreasing. */ 208662306a36Sopenharmony_ci return dc_check_balance(tb, h); 208762306a36Sopenharmony_ci} 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci/* Check whether parent at the path is the really parent of the current node.*/ 209062306a36Sopenharmony_cistatic int get_direct_parent(struct tree_balance *tb, int h) 209162306a36Sopenharmony_ci{ 209262306a36Sopenharmony_ci struct buffer_head *bh; 209362306a36Sopenharmony_ci struct treepath *path = tb->tb_path; 209462306a36Sopenharmony_ci int position, 209562306a36Sopenharmony_ci path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h); 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci /* We are in the root or in the new root. */ 209862306a36Sopenharmony_ci if (path_offset <= FIRST_PATH_ELEMENT_OFFSET) { 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci RFALSE(path_offset < FIRST_PATH_ELEMENT_OFFSET - 1, 210162306a36Sopenharmony_ci "PAP-8260: invalid offset in the path"); 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_ci if (PATH_OFFSET_PBUFFER(path, FIRST_PATH_ELEMENT_OFFSET)-> 210462306a36Sopenharmony_ci b_blocknr == SB_ROOT_BLOCK(tb->tb_sb)) { 210562306a36Sopenharmony_ci /* Root is not changed. */ 210662306a36Sopenharmony_ci PATH_OFFSET_PBUFFER(path, path_offset - 1) = NULL; 210762306a36Sopenharmony_ci PATH_OFFSET_POSITION(path, path_offset - 1) = 0; 210862306a36Sopenharmony_ci return CARRY_ON; 210962306a36Sopenharmony_ci } 211062306a36Sopenharmony_ci /* Root is changed and we must recalculate the path. */ 211162306a36Sopenharmony_ci return REPEAT_SEARCH; 211262306a36Sopenharmony_ci } 211362306a36Sopenharmony_ci 211462306a36Sopenharmony_ci /* Parent in the path is not in the tree. */ 211562306a36Sopenharmony_ci if (!B_IS_IN_TREE 211662306a36Sopenharmony_ci (bh = PATH_OFFSET_PBUFFER(path, path_offset - 1))) 211762306a36Sopenharmony_ci return REPEAT_SEARCH; 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci if ((position = 212062306a36Sopenharmony_ci PATH_OFFSET_POSITION(path, 212162306a36Sopenharmony_ci path_offset - 1)) > B_NR_ITEMS(bh)) 212262306a36Sopenharmony_ci return REPEAT_SEARCH; 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci /* Parent in the path is not parent of the current node in the tree. */ 212562306a36Sopenharmony_ci if (B_N_CHILD_NUM(bh, position) != 212662306a36Sopenharmony_ci PATH_OFFSET_PBUFFER(path, path_offset)->b_blocknr) 212762306a36Sopenharmony_ci return REPEAT_SEARCH; 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci if (buffer_locked(bh)) { 213062306a36Sopenharmony_ci int depth = reiserfs_write_unlock_nested(tb->tb_sb); 213162306a36Sopenharmony_ci __wait_on_buffer(bh); 213262306a36Sopenharmony_ci reiserfs_write_lock_nested(tb->tb_sb, depth); 213362306a36Sopenharmony_ci if (FILESYSTEM_CHANGED_TB(tb)) 213462306a36Sopenharmony_ci return REPEAT_SEARCH; 213562306a36Sopenharmony_ci } 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci /* 213862306a36Sopenharmony_ci * Parent in the path is unlocked and really parent 213962306a36Sopenharmony_ci * of the current node. 214062306a36Sopenharmony_ci */ 214162306a36Sopenharmony_ci return CARRY_ON; 214262306a36Sopenharmony_ci} 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci/* 214562306a36Sopenharmony_ci * Using lnum[h] and rnum[h] we should determine what neighbors 214662306a36Sopenharmony_ci * of S[h] we 214762306a36Sopenharmony_ci * need in order to balance S[h], and get them if necessary. 214862306a36Sopenharmony_ci * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; 214962306a36Sopenharmony_ci * CARRY_ON - schedule didn't occur while the function worked; 215062306a36Sopenharmony_ci */ 215162306a36Sopenharmony_cistatic int get_neighbors(struct tree_balance *tb, int h) 215262306a36Sopenharmony_ci{ 215362306a36Sopenharmony_ci int child_position, 215462306a36Sopenharmony_ci path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h + 1); 215562306a36Sopenharmony_ci unsigned long son_number; 215662306a36Sopenharmony_ci struct super_block *sb = tb->tb_sb; 215762306a36Sopenharmony_ci struct buffer_head *bh; 215862306a36Sopenharmony_ci int depth; 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci PROC_INFO_INC(sb, get_neighbors[h]); 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci if (tb->lnum[h]) { 216362306a36Sopenharmony_ci /* We need left neighbor to balance S[h]. */ 216462306a36Sopenharmony_ci PROC_INFO_INC(sb, need_l_neighbor[h]); 216562306a36Sopenharmony_ci bh = PATH_OFFSET_PBUFFER(tb->tb_path, path_offset); 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci RFALSE(bh == tb->FL[h] && 216862306a36Sopenharmony_ci !PATH_OFFSET_POSITION(tb->tb_path, path_offset), 216962306a36Sopenharmony_ci "PAP-8270: invalid position in the parent"); 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci child_position = 217262306a36Sopenharmony_ci (bh == 217362306a36Sopenharmony_ci tb->FL[h]) ? tb->lkey[h] : B_NR_ITEMS(tb-> 217462306a36Sopenharmony_ci FL[h]); 217562306a36Sopenharmony_ci son_number = B_N_CHILD_NUM(tb->FL[h], child_position); 217662306a36Sopenharmony_ci depth = reiserfs_write_unlock_nested(tb->tb_sb); 217762306a36Sopenharmony_ci bh = sb_bread(sb, son_number); 217862306a36Sopenharmony_ci reiserfs_write_lock_nested(tb->tb_sb, depth); 217962306a36Sopenharmony_ci if (!bh) 218062306a36Sopenharmony_ci return IO_ERROR; 218162306a36Sopenharmony_ci if (FILESYSTEM_CHANGED_TB(tb)) { 218262306a36Sopenharmony_ci brelse(bh); 218362306a36Sopenharmony_ci PROC_INFO_INC(sb, get_neighbors_restart[h]); 218462306a36Sopenharmony_ci return REPEAT_SEARCH; 218562306a36Sopenharmony_ci } 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci RFALSE(!B_IS_IN_TREE(tb->FL[h]) || 218862306a36Sopenharmony_ci child_position > B_NR_ITEMS(tb->FL[h]) || 218962306a36Sopenharmony_ci B_N_CHILD_NUM(tb->FL[h], child_position) != 219062306a36Sopenharmony_ci bh->b_blocknr, "PAP-8275: invalid parent"); 219162306a36Sopenharmony_ci RFALSE(!B_IS_IN_TREE(bh), "PAP-8280: invalid child"); 219262306a36Sopenharmony_ci RFALSE(!h && 219362306a36Sopenharmony_ci B_FREE_SPACE(bh) != 219462306a36Sopenharmony_ci MAX_CHILD_SIZE(bh) - 219562306a36Sopenharmony_ci dc_size(B_N_CHILD(tb->FL[0], child_position)), 219662306a36Sopenharmony_ci "PAP-8290: invalid child size of left neighbor"); 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci brelse(tb->L[h]); 219962306a36Sopenharmony_ci tb->L[h] = bh; 220062306a36Sopenharmony_ci } 220162306a36Sopenharmony_ci 220262306a36Sopenharmony_ci /* We need right neighbor to balance S[path_offset]. */ 220362306a36Sopenharmony_ci if (tb->rnum[h]) { 220462306a36Sopenharmony_ci PROC_INFO_INC(sb, need_r_neighbor[h]); 220562306a36Sopenharmony_ci bh = PATH_OFFSET_PBUFFER(tb->tb_path, path_offset); 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci RFALSE(bh == tb->FR[h] && 220862306a36Sopenharmony_ci PATH_OFFSET_POSITION(tb->tb_path, 220962306a36Sopenharmony_ci path_offset) >= 221062306a36Sopenharmony_ci B_NR_ITEMS(bh), 221162306a36Sopenharmony_ci "PAP-8295: invalid position in the parent"); 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci child_position = 221462306a36Sopenharmony_ci (bh == tb->FR[h]) ? tb->rkey[h] + 1 : 0; 221562306a36Sopenharmony_ci son_number = B_N_CHILD_NUM(tb->FR[h], child_position); 221662306a36Sopenharmony_ci depth = reiserfs_write_unlock_nested(tb->tb_sb); 221762306a36Sopenharmony_ci bh = sb_bread(sb, son_number); 221862306a36Sopenharmony_ci reiserfs_write_lock_nested(tb->tb_sb, depth); 221962306a36Sopenharmony_ci if (!bh) 222062306a36Sopenharmony_ci return IO_ERROR; 222162306a36Sopenharmony_ci if (FILESYSTEM_CHANGED_TB(tb)) { 222262306a36Sopenharmony_ci brelse(bh); 222362306a36Sopenharmony_ci PROC_INFO_INC(sb, get_neighbors_restart[h]); 222462306a36Sopenharmony_ci return REPEAT_SEARCH; 222562306a36Sopenharmony_ci } 222662306a36Sopenharmony_ci brelse(tb->R[h]); 222762306a36Sopenharmony_ci tb->R[h] = bh; 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci RFALSE(!h 223062306a36Sopenharmony_ci && B_FREE_SPACE(bh) != 223162306a36Sopenharmony_ci MAX_CHILD_SIZE(bh) - 223262306a36Sopenharmony_ci dc_size(B_N_CHILD(tb->FR[0], child_position)), 223362306a36Sopenharmony_ci "PAP-8300: invalid child size of right neighbor (%d != %d - %d)", 223462306a36Sopenharmony_ci B_FREE_SPACE(bh), MAX_CHILD_SIZE(bh), 223562306a36Sopenharmony_ci dc_size(B_N_CHILD(tb->FR[0], child_position))); 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci } 223862306a36Sopenharmony_ci return CARRY_ON; 223962306a36Sopenharmony_ci} 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_cistatic int get_virtual_node_size(struct super_block *sb, struct buffer_head *bh) 224262306a36Sopenharmony_ci{ 224362306a36Sopenharmony_ci int max_num_of_items; 224462306a36Sopenharmony_ci int max_num_of_entries; 224562306a36Sopenharmony_ci unsigned long blocksize = sb->s_blocksize; 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci#define MIN_NAME_LEN 1 224862306a36Sopenharmony_ci 224962306a36Sopenharmony_ci max_num_of_items = (blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN); 225062306a36Sopenharmony_ci max_num_of_entries = (blocksize - BLKH_SIZE - IH_SIZE) / 225162306a36Sopenharmony_ci (DEH_SIZE + MIN_NAME_LEN); 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci return sizeof(struct virtual_node) + 225462306a36Sopenharmony_ci max(max_num_of_items * sizeof(struct virtual_item), 225562306a36Sopenharmony_ci sizeof(struct virtual_item) + 225662306a36Sopenharmony_ci struct_size_t(struct direntry_uarea, entry_sizes, 225762306a36Sopenharmony_ci max_num_of_entries)); 225862306a36Sopenharmony_ci} 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci/* 226162306a36Sopenharmony_ci * maybe we should fail balancing we are going to perform when kmalloc 226262306a36Sopenharmony_ci * fails several times. But now it will loop until kmalloc gets 226362306a36Sopenharmony_ci * required memory 226462306a36Sopenharmony_ci */ 226562306a36Sopenharmony_cistatic int get_mem_for_virtual_node(struct tree_balance *tb) 226662306a36Sopenharmony_ci{ 226762306a36Sopenharmony_ci int check_fs = 0; 226862306a36Sopenharmony_ci int size; 226962306a36Sopenharmony_ci char *buf; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci size = get_virtual_node_size(tb->tb_sb, PATH_PLAST_BUFFER(tb->tb_path)); 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci /* we have to allocate more memory for virtual node */ 227462306a36Sopenharmony_ci if (size > tb->vn_buf_size) { 227562306a36Sopenharmony_ci if (tb->vn_buf) { 227662306a36Sopenharmony_ci /* free memory allocated before */ 227762306a36Sopenharmony_ci kfree(tb->vn_buf); 227862306a36Sopenharmony_ci /* this is not needed if kfree is atomic */ 227962306a36Sopenharmony_ci check_fs = 1; 228062306a36Sopenharmony_ci } 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci /* virtual node requires now more memory */ 228362306a36Sopenharmony_ci tb->vn_buf_size = size; 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci /* get memory for virtual item */ 228662306a36Sopenharmony_ci buf = kmalloc(size, GFP_ATOMIC | __GFP_NOWARN); 228762306a36Sopenharmony_ci if (!buf) { 228862306a36Sopenharmony_ci /* 228962306a36Sopenharmony_ci * getting memory with GFP_KERNEL priority may involve 229062306a36Sopenharmony_ci * balancing now (due to indirect_to_direct conversion 229162306a36Sopenharmony_ci * on dcache shrinking). So, release path and collected 229262306a36Sopenharmony_ci * resources here 229362306a36Sopenharmony_ci */ 229462306a36Sopenharmony_ci free_buffers_in_tb(tb); 229562306a36Sopenharmony_ci buf = kmalloc(size, GFP_NOFS); 229662306a36Sopenharmony_ci if (!buf) { 229762306a36Sopenharmony_ci tb->vn_buf_size = 0; 229862306a36Sopenharmony_ci } 229962306a36Sopenharmony_ci tb->vn_buf = buf; 230062306a36Sopenharmony_ci schedule(); 230162306a36Sopenharmony_ci return REPEAT_SEARCH; 230262306a36Sopenharmony_ci } 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci tb->vn_buf = buf; 230562306a36Sopenharmony_ci } 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci if (check_fs && FILESYSTEM_CHANGED_TB(tb)) 230862306a36Sopenharmony_ci return REPEAT_SEARCH; 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci return CARRY_ON; 231162306a36Sopenharmony_ci} 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK 231462306a36Sopenharmony_cistatic void tb_buffer_sanity_check(struct super_block *sb, 231562306a36Sopenharmony_ci struct buffer_head *bh, 231662306a36Sopenharmony_ci const char *descr, int level) 231762306a36Sopenharmony_ci{ 231862306a36Sopenharmony_ci if (bh) { 231962306a36Sopenharmony_ci if (atomic_read(&(bh->b_count)) <= 0) 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci reiserfs_panic(sb, "jmacd-1", "negative or zero " 232262306a36Sopenharmony_ci "reference counter for buffer %s[%d] " 232362306a36Sopenharmony_ci "(%b)", descr, level, bh); 232462306a36Sopenharmony_ci 232562306a36Sopenharmony_ci if (!buffer_uptodate(bh)) 232662306a36Sopenharmony_ci reiserfs_panic(sb, "jmacd-2", "buffer is not up " 232762306a36Sopenharmony_ci "to date %s[%d] (%b)", 232862306a36Sopenharmony_ci descr, level, bh); 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci if (!B_IS_IN_TREE(bh)) 233162306a36Sopenharmony_ci reiserfs_panic(sb, "jmacd-3", "buffer is not " 233262306a36Sopenharmony_ci "in tree %s[%d] (%b)", 233362306a36Sopenharmony_ci descr, level, bh); 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ci if (bh->b_bdev != sb->s_bdev) 233662306a36Sopenharmony_ci reiserfs_panic(sb, "jmacd-4", "buffer has wrong " 233762306a36Sopenharmony_ci "device %s[%d] (%b)", 233862306a36Sopenharmony_ci descr, level, bh); 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_ci if (bh->b_size != sb->s_blocksize) 234162306a36Sopenharmony_ci reiserfs_panic(sb, "jmacd-5", "buffer has wrong " 234262306a36Sopenharmony_ci "blocksize %s[%d] (%b)", 234362306a36Sopenharmony_ci descr, level, bh); 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci if (bh->b_blocknr > SB_BLOCK_COUNT(sb)) 234662306a36Sopenharmony_ci reiserfs_panic(sb, "jmacd-6", "buffer block " 234762306a36Sopenharmony_ci "number too high %s[%d] (%b)", 234862306a36Sopenharmony_ci descr, level, bh); 234962306a36Sopenharmony_ci } 235062306a36Sopenharmony_ci} 235162306a36Sopenharmony_ci#else 235262306a36Sopenharmony_cistatic void tb_buffer_sanity_check(struct super_block *sb, 235362306a36Sopenharmony_ci struct buffer_head *bh, 235462306a36Sopenharmony_ci const char *descr, int level) 235562306a36Sopenharmony_ci{; 235662306a36Sopenharmony_ci} 235762306a36Sopenharmony_ci#endif 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_cistatic int clear_all_dirty_bits(struct super_block *s, struct buffer_head *bh) 236062306a36Sopenharmony_ci{ 236162306a36Sopenharmony_ci return reiserfs_prepare_for_journal(s, bh, 0); 236262306a36Sopenharmony_ci} 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_cistatic int wait_tb_buffers_until_unlocked(struct tree_balance *tb) 236562306a36Sopenharmony_ci{ 236662306a36Sopenharmony_ci struct buffer_head *locked; 236762306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK 236862306a36Sopenharmony_ci int repeat_counter = 0; 236962306a36Sopenharmony_ci#endif 237062306a36Sopenharmony_ci int i; 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_ci do { 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci locked = NULL; 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci for (i = tb->tb_path->path_length; 237762306a36Sopenharmony_ci !locked && i > ILLEGAL_PATH_ELEMENT_OFFSET; i--) { 237862306a36Sopenharmony_ci if (PATH_OFFSET_PBUFFER(tb->tb_path, i)) { 237962306a36Sopenharmony_ci /* 238062306a36Sopenharmony_ci * if I understand correctly, we can only 238162306a36Sopenharmony_ci * be sure the last buffer in the path is 238262306a36Sopenharmony_ci * in the tree --clm 238362306a36Sopenharmony_ci */ 238462306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK 238562306a36Sopenharmony_ci if (PATH_PLAST_BUFFER(tb->tb_path) == 238662306a36Sopenharmony_ci PATH_OFFSET_PBUFFER(tb->tb_path, i)) 238762306a36Sopenharmony_ci tb_buffer_sanity_check(tb->tb_sb, 238862306a36Sopenharmony_ci PATH_OFFSET_PBUFFER 238962306a36Sopenharmony_ci (tb->tb_path, 239062306a36Sopenharmony_ci i), "S", 239162306a36Sopenharmony_ci tb->tb_path-> 239262306a36Sopenharmony_ci path_length - i); 239362306a36Sopenharmony_ci#endif 239462306a36Sopenharmony_ci if (!clear_all_dirty_bits(tb->tb_sb, 239562306a36Sopenharmony_ci PATH_OFFSET_PBUFFER 239662306a36Sopenharmony_ci (tb->tb_path, 239762306a36Sopenharmony_ci i))) { 239862306a36Sopenharmony_ci locked = 239962306a36Sopenharmony_ci PATH_OFFSET_PBUFFER(tb->tb_path, 240062306a36Sopenharmony_ci i); 240162306a36Sopenharmony_ci } 240262306a36Sopenharmony_ci } 240362306a36Sopenharmony_ci } 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci for (i = 0; !locked && i < MAX_HEIGHT && tb->insert_size[i]; 240662306a36Sopenharmony_ci i++) { 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci if (tb->lnum[i]) { 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci if (tb->L[i]) { 241162306a36Sopenharmony_ci tb_buffer_sanity_check(tb->tb_sb, 241262306a36Sopenharmony_ci tb->L[i], 241362306a36Sopenharmony_ci "L", i); 241462306a36Sopenharmony_ci if (!clear_all_dirty_bits 241562306a36Sopenharmony_ci (tb->tb_sb, tb->L[i])) 241662306a36Sopenharmony_ci locked = tb->L[i]; 241762306a36Sopenharmony_ci } 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci if (!locked && tb->FL[i]) { 242062306a36Sopenharmony_ci tb_buffer_sanity_check(tb->tb_sb, 242162306a36Sopenharmony_ci tb->FL[i], 242262306a36Sopenharmony_ci "FL", i); 242362306a36Sopenharmony_ci if (!clear_all_dirty_bits 242462306a36Sopenharmony_ci (tb->tb_sb, tb->FL[i])) 242562306a36Sopenharmony_ci locked = tb->FL[i]; 242662306a36Sopenharmony_ci } 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci if (!locked && tb->CFL[i]) { 242962306a36Sopenharmony_ci tb_buffer_sanity_check(tb->tb_sb, 243062306a36Sopenharmony_ci tb->CFL[i], 243162306a36Sopenharmony_ci "CFL", i); 243262306a36Sopenharmony_ci if (!clear_all_dirty_bits 243362306a36Sopenharmony_ci (tb->tb_sb, tb->CFL[i])) 243462306a36Sopenharmony_ci locked = tb->CFL[i]; 243562306a36Sopenharmony_ci } 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci } 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci if (!locked && (tb->rnum[i])) { 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci if (tb->R[i]) { 244262306a36Sopenharmony_ci tb_buffer_sanity_check(tb->tb_sb, 244362306a36Sopenharmony_ci tb->R[i], 244462306a36Sopenharmony_ci "R", i); 244562306a36Sopenharmony_ci if (!clear_all_dirty_bits 244662306a36Sopenharmony_ci (tb->tb_sb, tb->R[i])) 244762306a36Sopenharmony_ci locked = tb->R[i]; 244862306a36Sopenharmony_ci } 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci if (!locked && tb->FR[i]) { 245162306a36Sopenharmony_ci tb_buffer_sanity_check(tb->tb_sb, 245262306a36Sopenharmony_ci tb->FR[i], 245362306a36Sopenharmony_ci "FR", i); 245462306a36Sopenharmony_ci if (!clear_all_dirty_bits 245562306a36Sopenharmony_ci (tb->tb_sb, tb->FR[i])) 245662306a36Sopenharmony_ci locked = tb->FR[i]; 245762306a36Sopenharmony_ci } 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_ci if (!locked && tb->CFR[i]) { 246062306a36Sopenharmony_ci tb_buffer_sanity_check(tb->tb_sb, 246162306a36Sopenharmony_ci tb->CFR[i], 246262306a36Sopenharmony_ci "CFR", i); 246362306a36Sopenharmony_ci if (!clear_all_dirty_bits 246462306a36Sopenharmony_ci (tb->tb_sb, tb->CFR[i])) 246562306a36Sopenharmony_ci locked = tb->CFR[i]; 246662306a36Sopenharmony_ci } 246762306a36Sopenharmony_ci } 246862306a36Sopenharmony_ci } 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci /* 247162306a36Sopenharmony_ci * as far as I can tell, this is not required. The FEB list 247262306a36Sopenharmony_ci * seems to be full of newly allocated nodes, which will 247362306a36Sopenharmony_ci * never be locked, dirty, or anything else. 247462306a36Sopenharmony_ci * To be safe, I'm putting in the checks and waits in. 247562306a36Sopenharmony_ci * For the moment, they are needed to keep the code in 247662306a36Sopenharmony_ci * journal.c from complaining about the buffer. 247762306a36Sopenharmony_ci * That code is inside CONFIG_REISERFS_CHECK as well. --clm 247862306a36Sopenharmony_ci */ 247962306a36Sopenharmony_ci for (i = 0; !locked && i < MAX_FEB_SIZE; i++) { 248062306a36Sopenharmony_ci if (tb->FEB[i]) { 248162306a36Sopenharmony_ci if (!clear_all_dirty_bits 248262306a36Sopenharmony_ci (tb->tb_sb, tb->FEB[i])) 248362306a36Sopenharmony_ci locked = tb->FEB[i]; 248462306a36Sopenharmony_ci } 248562306a36Sopenharmony_ci } 248662306a36Sopenharmony_ci 248762306a36Sopenharmony_ci if (locked) { 248862306a36Sopenharmony_ci int depth; 248962306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK 249062306a36Sopenharmony_ci repeat_counter++; 249162306a36Sopenharmony_ci if ((repeat_counter % 10000) == 0) { 249262306a36Sopenharmony_ci reiserfs_warning(tb->tb_sb, "reiserfs-8200", 249362306a36Sopenharmony_ci "too many iterations waiting " 249462306a36Sopenharmony_ci "for buffer to unlock " 249562306a36Sopenharmony_ci "(%b)", locked); 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci /* Don't loop forever. Try to recover from possible error. */ 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci return (FILESYSTEM_CHANGED_TB(tb)) ? 250062306a36Sopenharmony_ci REPEAT_SEARCH : CARRY_ON; 250162306a36Sopenharmony_ci } 250262306a36Sopenharmony_ci#endif 250362306a36Sopenharmony_ci depth = reiserfs_write_unlock_nested(tb->tb_sb); 250462306a36Sopenharmony_ci __wait_on_buffer(locked); 250562306a36Sopenharmony_ci reiserfs_write_lock_nested(tb->tb_sb, depth); 250662306a36Sopenharmony_ci if (FILESYSTEM_CHANGED_TB(tb)) 250762306a36Sopenharmony_ci return REPEAT_SEARCH; 250862306a36Sopenharmony_ci } 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci } while (locked); 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci return CARRY_ON; 251362306a36Sopenharmony_ci} 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci/* 251662306a36Sopenharmony_ci * Prepare for balancing, that is 251762306a36Sopenharmony_ci * get all necessary parents, and neighbors; 251862306a36Sopenharmony_ci * analyze what and where should be moved; 251962306a36Sopenharmony_ci * get sufficient number of new nodes; 252062306a36Sopenharmony_ci * Balancing will start only after all resources will be collected at a time. 252162306a36Sopenharmony_ci * 252262306a36Sopenharmony_ci * When ported to SMP kernels, only at the last moment after all needed nodes 252362306a36Sopenharmony_ci * are collected in cache, will the resources be locked using the usual 252462306a36Sopenharmony_ci * textbook ordered lock acquisition algorithms. Note that ensuring that 252562306a36Sopenharmony_ci * this code neither write locks what it does not need to write lock nor locks 252662306a36Sopenharmony_ci * out of order will be a pain in the butt that could have been avoided. 252762306a36Sopenharmony_ci * Grumble grumble. -Hans 252862306a36Sopenharmony_ci * 252962306a36Sopenharmony_ci * fix is meant in the sense of render unchanging 253062306a36Sopenharmony_ci * 253162306a36Sopenharmony_ci * Latency might be improved by first gathering a list of what buffers 253262306a36Sopenharmony_ci * are needed and then getting as many of them in parallel as possible? -Hans 253362306a36Sopenharmony_ci * 253462306a36Sopenharmony_ci * Parameters: 253562306a36Sopenharmony_ci * op_mode i - insert, d - delete, c - cut (truncate), p - paste (append) 253662306a36Sopenharmony_ci * tb tree_balance structure; 253762306a36Sopenharmony_ci * inum item number in S[h]; 253862306a36Sopenharmony_ci * pos_in_item - comment this if you can 253962306a36Sopenharmony_ci * ins_ih item head of item being inserted 254062306a36Sopenharmony_ci * data inserted item or data to be pasted 254162306a36Sopenharmony_ci * Returns: 1 - schedule occurred while the function worked; 254262306a36Sopenharmony_ci * 0 - schedule didn't occur while the function worked; 254362306a36Sopenharmony_ci * -1 - if no_disk_space 254462306a36Sopenharmony_ci */ 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ciint fix_nodes(int op_mode, struct tree_balance *tb, 254762306a36Sopenharmony_ci struct item_head *ins_ih, const void *data) 254862306a36Sopenharmony_ci{ 254962306a36Sopenharmony_ci int ret, h, item_num = PATH_LAST_POSITION(tb->tb_path); 255062306a36Sopenharmony_ci int pos_in_item; 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_ci /* 255362306a36Sopenharmony_ci * we set wait_tb_buffers_run when we have to restore any dirty 255462306a36Sopenharmony_ci * bits cleared during wait_tb_buffers_run 255562306a36Sopenharmony_ci */ 255662306a36Sopenharmony_ci int wait_tb_buffers_run = 0; 255762306a36Sopenharmony_ci struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path); 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_ci ++REISERFS_SB(tb->tb_sb)->s_fix_nodes; 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci pos_in_item = tb->tb_path->pos_in_item; 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci tb->fs_gen = get_generation(tb->tb_sb); 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci /* 256662306a36Sopenharmony_ci * we prepare and log the super here so it will already be in the 256762306a36Sopenharmony_ci * transaction when do_balance needs to change it. 256862306a36Sopenharmony_ci * This way do_balance won't have to schedule when trying to prepare 256962306a36Sopenharmony_ci * the super for logging 257062306a36Sopenharmony_ci */ 257162306a36Sopenharmony_ci reiserfs_prepare_for_journal(tb->tb_sb, 257262306a36Sopenharmony_ci SB_BUFFER_WITH_SB(tb->tb_sb), 1); 257362306a36Sopenharmony_ci journal_mark_dirty(tb->transaction_handle, 257462306a36Sopenharmony_ci SB_BUFFER_WITH_SB(tb->tb_sb)); 257562306a36Sopenharmony_ci if (FILESYSTEM_CHANGED_TB(tb)) 257662306a36Sopenharmony_ci return REPEAT_SEARCH; 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_ci /* if it possible in indirect_to_direct conversion */ 257962306a36Sopenharmony_ci if (buffer_locked(tbS0)) { 258062306a36Sopenharmony_ci int depth = reiserfs_write_unlock_nested(tb->tb_sb); 258162306a36Sopenharmony_ci __wait_on_buffer(tbS0); 258262306a36Sopenharmony_ci reiserfs_write_lock_nested(tb->tb_sb, depth); 258362306a36Sopenharmony_ci if (FILESYSTEM_CHANGED_TB(tb)) 258462306a36Sopenharmony_ci return REPEAT_SEARCH; 258562306a36Sopenharmony_ci } 258662306a36Sopenharmony_ci#ifdef CONFIG_REISERFS_CHECK 258762306a36Sopenharmony_ci if (REISERFS_SB(tb->tb_sb)->cur_tb) { 258862306a36Sopenharmony_ci print_cur_tb("fix_nodes"); 258962306a36Sopenharmony_ci reiserfs_panic(tb->tb_sb, "PAP-8305", 259062306a36Sopenharmony_ci "there is pending do_balance"); 259162306a36Sopenharmony_ci } 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci if (!buffer_uptodate(tbS0) || !B_IS_IN_TREE(tbS0)) 259462306a36Sopenharmony_ci reiserfs_panic(tb->tb_sb, "PAP-8320", "S[0] (%b %z) is " 259562306a36Sopenharmony_ci "not uptodate at the beginning of fix_nodes " 259662306a36Sopenharmony_ci "or not in tree (mode %c)", 259762306a36Sopenharmony_ci tbS0, tbS0, op_mode); 259862306a36Sopenharmony_ci 259962306a36Sopenharmony_ci /* Check parameters. */ 260062306a36Sopenharmony_ci switch (op_mode) { 260162306a36Sopenharmony_ci case M_INSERT: 260262306a36Sopenharmony_ci if (item_num <= 0 || item_num > B_NR_ITEMS(tbS0)) 260362306a36Sopenharmony_ci reiserfs_panic(tb->tb_sb, "PAP-8330", "Incorrect " 260462306a36Sopenharmony_ci "item number %d (in S0 - %d) in case " 260562306a36Sopenharmony_ci "of insert", item_num, 260662306a36Sopenharmony_ci B_NR_ITEMS(tbS0)); 260762306a36Sopenharmony_ci break; 260862306a36Sopenharmony_ci case M_PASTE: 260962306a36Sopenharmony_ci case M_DELETE: 261062306a36Sopenharmony_ci case M_CUT: 261162306a36Sopenharmony_ci if (item_num < 0 || item_num >= B_NR_ITEMS(tbS0)) { 261262306a36Sopenharmony_ci print_block(tbS0, 0, -1, -1); 261362306a36Sopenharmony_ci reiserfs_panic(tb->tb_sb, "PAP-8335", "Incorrect " 261462306a36Sopenharmony_ci "item number(%d); mode = %c " 261562306a36Sopenharmony_ci "insert_size = %d", 261662306a36Sopenharmony_ci item_num, op_mode, 261762306a36Sopenharmony_ci tb->insert_size[0]); 261862306a36Sopenharmony_ci } 261962306a36Sopenharmony_ci break; 262062306a36Sopenharmony_ci default: 262162306a36Sopenharmony_ci reiserfs_panic(tb->tb_sb, "PAP-8340", "Incorrect mode " 262262306a36Sopenharmony_ci "of operation"); 262362306a36Sopenharmony_ci } 262462306a36Sopenharmony_ci#endif 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci if (get_mem_for_virtual_node(tb) == REPEAT_SEARCH) 262762306a36Sopenharmony_ci /* FIXME: maybe -ENOMEM when tb->vn_buf == 0? Now just repeat */ 262862306a36Sopenharmony_ci return REPEAT_SEARCH; 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci /* Starting from the leaf level; for all levels h of the tree. */ 263162306a36Sopenharmony_ci for (h = 0; h < MAX_HEIGHT && tb->insert_size[h]; h++) { 263262306a36Sopenharmony_ci ret = get_direct_parent(tb, h); 263362306a36Sopenharmony_ci if (ret != CARRY_ON) 263462306a36Sopenharmony_ci goto repeat; 263562306a36Sopenharmony_ci 263662306a36Sopenharmony_ci ret = check_balance(op_mode, tb, h, item_num, 263762306a36Sopenharmony_ci pos_in_item, ins_ih, data); 263862306a36Sopenharmony_ci if (ret != CARRY_ON) { 263962306a36Sopenharmony_ci if (ret == NO_BALANCING_NEEDED) { 264062306a36Sopenharmony_ci /* No balancing for higher levels needed. */ 264162306a36Sopenharmony_ci ret = get_neighbors(tb, h); 264262306a36Sopenharmony_ci if (ret != CARRY_ON) 264362306a36Sopenharmony_ci goto repeat; 264462306a36Sopenharmony_ci if (h != MAX_HEIGHT - 1) 264562306a36Sopenharmony_ci tb->insert_size[h + 1] = 0; 264662306a36Sopenharmony_ci /* 264762306a36Sopenharmony_ci * ok, analysis and resource gathering 264862306a36Sopenharmony_ci * are complete 264962306a36Sopenharmony_ci */ 265062306a36Sopenharmony_ci break; 265162306a36Sopenharmony_ci } 265262306a36Sopenharmony_ci goto repeat; 265362306a36Sopenharmony_ci } 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci ret = get_neighbors(tb, h); 265662306a36Sopenharmony_ci if (ret != CARRY_ON) 265762306a36Sopenharmony_ci goto repeat; 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_ci /* 266062306a36Sopenharmony_ci * No disk space, or schedule occurred and analysis may be 266162306a36Sopenharmony_ci * invalid and needs to be redone. 266262306a36Sopenharmony_ci */ 266362306a36Sopenharmony_ci ret = get_empty_nodes(tb, h); 266462306a36Sopenharmony_ci if (ret != CARRY_ON) 266562306a36Sopenharmony_ci goto repeat; 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci /* 266862306a36Sopenharmony_ci * We have a positive insert size but no nodes exist on this 266962306a36Sopenharmony_ci * level, this means that we are creating a new root. 267062306a36Sopenharmony_ci */ 267162306a36Sopenharmony_ci if (!PATH_H_PBUFFER(tb->tb_path, h)) { 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci RFALSE(tb->blknum[h] != 1, 267462306a36Sopenharmony_ci "PAP-8350: creating new empty root"); 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci if (h < MAX_HEIGHT - 1) 267762306a36Sopenharmony_ci tb->insert_size[h + 1] = 0; 267862306a36Sopenharmony_ci } else if (!PATH_H_PBUFFER(tb->tb_path, h + 1)) { 267962306a36Sopenharmony_ci /* 268062306a36Sopenharmony_ci * The tree needs to be grown, so this node S[h] 268162306a36Sopenharmony_ci * which is the root node is split into two nodes, 268262306a36Sopenharmony_ci * and a new node (S[h+1]) will be created to 268362306a36Sopenharmony_ci * become the root node. 268462306a36Sopenharmony_ci */ 268562306a36Sopenharmony_ci if (tb->blknum[h] > 1) { 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci RFALSE(h == MAX_HEIGHT - 1, 268862306a36Sopenharmony_ci "PAP-8355: attempt to create too high of a tree"); 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_ci tb->insert_size[h + 1] = 269162306a36Sopenharmony_ci (DC_SIZE + 269262306a36Sopenharmony_ci KEY_SIZE) * (tb->blknum[h] - 1) + 269362306a36Sopenharmony_ci DC_SIZE; 269462306a36Sopenharmony_ci } else if (h < MAX_HEIGHT - 1) 269562306a36Sopenharmony_ci tb->insert_size[h + 1] = 0; 269662306a36Sopenharmony_ci } else 269762306a36Sopenharmony_ci tb->insert_size[h + 1] = 269862306a36Sopenharmony_ci (DC_SIZE + KEY_SIZE) * (tb->blknum[h] - 1); 269962306a36Sopenharmony_ci } 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci ret = wait_tb_buffers_until_unlocked(tb); 270262306a36Sopenharmony_ci if (ret == CARRY_ON) { 270362306a36Sopenharmony_ci if (FILESYSTEM_CHANGED_TB(tb)) { 270462306a36Sopenharmony_ci wait_tb_buffers_run = 1; 270562306a36Sopenharmony_ci ret = REPEAT_SEARCH; 270662306a36Sopenharmony_ci goto repeat; 270762306a36Sopenharmony_ci } else { 270862306a36Sopenharmony_ci return CARRY_ON; 270962306a36Sopenharmony_ci } 271062306a36Sopenharmony_ci } else { 271162306a36Sopenharmony_ci wait_tb_buffers_run = 1; 271262306a36Sopenharmony_ci goto repeat; 271362306a36Sopenharmony_ci } 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_cirepeat: 271662306a36Sopenharmony_ci /* 271762306a36Sopenharmony_ci * fix_nodes was unable to perform its calculation due to 271862306a36Sopenharmony_ci * filesystem got changed under us, lack of free disk space or i/o 271962306a36Sopenharmony_ci * failure. If the first is the case - the search will be 272062306a36Sopenharmony_ci * repeated. For now - free all resources acquired so far except 272162306a36Sopenharmony_ci * for the new allocated nodes 272262306a36Sopenharmony_ci */ 272362306a36Sopenharmony_ci { 272462306a36Sopenharmony_ci int i; 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci /* Release path buffers. */ 272762306a36Sopenharmony_ci if (wait_tb_buffers_run) { 272862306a36Sopenharmony_ci pathrelse_and_restore(tb->tb_sb, tb->tb_path); 272962306a36Sopenharmony_ci } else { 273062306a36Sopenharmony_ci pathrelse(tb->tb_path); 273162306a36Sopenharmony_ci } 273262306a36Sopenharmony_ci /* brelse all resources collected for balancing */ 273362306a36Sopenharmony_ci for (i = 0; i < MAX_HEIGHT; i++) { 273462306a36Sopenharmony_ci if (wait_tb_buffers_run) { 273562306a36Sopenharmony_ci reiserfs_restore_prepared_buffer(tb->tb_sb, 273662306a36Sopenharmony_ci tb->L[i]); 273762306a36Sopenharmony_ci reiserfs_restore_prepared_buffer(tb->tb_sb, 273862306a36Sopenharmony_ci tb->R[i]); 273962306a36Sopenharmony_ci reiserfs_restore_prepared_buffer(tb->tb_sb, 274062306a36Sopenharmony_ci tb->FL[i]); 274162306a36Sopenharmony_ci reiserfs_restore_prepared_buffer(tb->tb_sb, 274262306a36Sopenharmony_ci tb->FR[i]); 274362306a36Sopenharmony_ci reiserfs_restore_prepared_buffer(tb->tb_sb, 274462306a36Sopenharmony_ci tb-> 274562306a36Sopenharmony_ci CFL[i]); 274662306a36Sopenharmony_ci reiserfs_restore_prepared_buffer(tb->tb_sb, 274762306a36Sopenharmony_ci tb-> 274862306a36Sopenharmony_ci CFR[i]); 274962306a36Sopenharmony_ci } 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci brelse(tb->L[i]); 275262306a36Sopenharmony_ci brelse(tb->R[i]); 275362306a36Sopenharmony_ci brelse(tb->FL[i]); 275462306a36Sopenharmony_ci brelse(tb->FR[i]); 275562306a36Sopenharmony_ci brelse(tb->CFL[i]); 275662306a36Sopenharmony_ci brelse(tb->CFR[i]); 275762306a36Sopenharmony_ci 275862306a36Sopenharmony_ci tb->L[i] = NULL; 275962306a36Sopenharmony_ci tb->R[i] = NULL; 276062306a36Sopenharmony_ci tb->FL[i] = NULL; 276162306a36Sopenharmony_ci tb->FR[i] = NULL; 276262306a36Sopenharmony_ci tb->CFL[i] = NULL; 276362306a36Sopenharmony_ci tb->CFR[i] = NULL; 276462306a36Sopenharmony_ci } 276562306a36Sopenharmony_ci 276662306a36Sopenharmony_ci if (wait_tb_buffers_run) { 276762306a36Sopenharmony_ci for (i = 0; i < MAX_FEB_SIZE; i++) { 276862306a36Sopenharmony_ci if (tb->FEB[i]) 276962306a36Sopenharmony_ci reiserfs_restore_prepared_buffer 277062306a36Sopenharmony_ci (tb->tb_sb, tb->FEB[i]); 277162306a36Sopenharmony_ci } 277262306a36Sopenharmony_ci } 277362306a36Sopenharmony_ci return ret; 277462306a36Sopenharmony_ci } 277562306a36Sopenharmony_ci 277662306a36Sopenharmony_ci} 277762306a36Sopenharmony_ci 277862306a36Sopenharmony_civoid unfix_nodes(struct tree_balance *tb) 277962306a36Sopenharmony_ci{ 278062306a36Sopenharmony_ci int i; 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci /* Release path buffers. */ 278362306a36Sopenharmony_ci pathrelse_and_restore(tb->tb_sb, tb->tb_path); 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci /* brelse all resources collected for balancing */ 278662306a36Sopenharmony_ci for (i = 0; i < MAX_HEIGHT; i++) { 278762306a36Sopenharmony_ci reiserfs_restore_prepared_buffer(tb->tb_sb, tb->L[i]); 278862306a36Sopenharmony_ci reiserfs_restore_prepared_buffer(tb->tb_sb, tb->R[i]); 278962306a36Sopenharmony_ci reiserfs_restore_prepared_buffer(tb->tb_sb, tb->FL[i]); 279062306a36Sopenharmony_ci reiserfs_restore_prepared_buffer(tb->tb_sb, tb->FR[i]); 279162306a36Sopenharmony_ci reiserfs_restore_prepared_buffer(tb->tb_sb, tb->CFL[i]); 279262306a36Sopenharmony_ci reiserfs_restore_prepared_buffer(tb->tb_sb, tb->CFR[i]); 279362306a36Sopenharmony_ci 279462306a36Sopenharmony_ci brelse(tb->L[i]); 279562306a36Sopenharmony_ci brelse(tb->R[i]); 279662306a36Sopenharmony_ci brelse(tb->FL[i]); 279762306a36Sopenharmony_ci brelse(tb->FR[i]); 279862306a36Sopenharmony_ci brelse(tb->CFL[i]); 279962306a36Sopenharmony_ci brelse(tb->CFR[i]); 280062306a36Sopenharmony_ci } 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci /* deal with list of allocated (used and unused) nodes */ 280362306a36Sopenharmony_ci for (i = 0; i < MAX_FEB_SIZE; i++) { 280462306a36Sopenharmony_ci if (tb->FEB[i]) { 280562306a36Sopenharmony_ci b_blocknr_t blocknr = tb->FEB[i]->b_blocknr; 280662306a36Sopenharmony_ci /* 280762306a36Sopenharmony_ci * de-allocated block which was not used by 280862306a36Sopenharmony_ci * balancing and bforget about buffer for it 280962306a36Sopenharmony_ci */ 281062306a36Sopenharmony_ci brelse(tb->FEB[i]); 281162306a36Sopenharmony_ci reiserfs_free_block(tb->transaction_handle, NULL, 281262306a36Sopenharmony_ci blocknr, 0); 281362306a36Sopenharmony_ci } 281462306a36Sopenharmony_ci if (tb->used[i]) { 281562306a36Sopenharmony_ci /* release used as new nodes including a new root */ 281662306a36Sopenharmony_ci brelse(tb->used[i]); 281762306a36Sopenharmony_ci } 281862306a36Sopenharmony_ci } 281962306a36Sopenharmony_ci 282062306a36Sopenharmony_ci kfree(tb->vn_buf); 282162306a36Sopenharmony_ci 282262306a36Sopenharmony_ci} 2823