11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README 31da177e4SLinus Torvalds */ 41da177e4SLinus Torvalds 51da177e4SLinus Torvalds /** 61da177e4SLinus Torvalds ** old_item_num 71da177e4SLinus Torvalds ** old_entry_num 81da177e4SLinus Torvalds ** set_entry_sizes 91da177e4SLinus Torvalds ** create_virtual_node 101da177e4SLinus Torvalds ** check_left 111da177e4SLinus Torvalds ** check_right 121da177e4SLinus Torvalds ** directory_part_size 131da177e4SLinus Torvalds ** get_num_ver 141da177e4SLinus Torvalds ** set_parameters 151da177e4SLinus Torvalds ** is_leaf_removable 161da177e4SLinus Torvalds ** are_leaves_removable 171da177e4SLinus Torvalds ** get_empty_nodes 181da177e4SLinus Torvalds ** get_lfree 191da177e4SLinus Torvalds ** get_rfree 201da177e4SLinus Torvalds ** is_left_neighbor_in_cache 211da177e4SLinus Torvalds ** decrement_key 221da177e4SLinus Torvalds ** get_far_parent 231da177e4SLinus Torvalds ** get_parents 241da177e4SLinus Torvalds ** can_node_be_removed 251da177e4SLinus Torvalds ** ip_check_balance 261da177e4SLinus Torvalds ** dc_check_balance_internal 271da177e4SLinus Torvalds ** dc_check_balance_leaf 281da177e4SLinus Torvalds ** dc_check_balance 291da177e4SLinus Torvalds ** check_balance 301da177e4SLinus Torvalds ** get_direct_parent 311da177e4SLinus Torvalds ** get_neighbors 321da177e4SLinus Torvalds ** fix_nodes 331da177e4SLinus Torvalds ** 341da177e4SLinus Torvalds ** 351da177e4SLinus Torvalds **/ 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds #include <linux/time.h> 381da177e4SLinus Torvalds #include <linux/string.h> 391da177e4SLinus Torvalds #include <linux/reiserfs_fs.h> 401da177e4SLinus Torvalds #include <linux/buffer_head.h> 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds /* To make any changes in the tree we find a node, that contains item 431da177e4SLinus Torvalds to be changed/deleted or position in the node we insert a new item 441da177e4SLinus Torvalds to. We call this node S. To do balancing we need to decide what we 451da177e4SLinus Torvalds will shift to left/right neighbor, or to a new node, where new item 461da177e4SLinus Torvalds will be etc. To make this analysis simpler we build virtual 471da177e4SLinus Torvalds node. Virtual node is an array of items, that will replace items of 481da177e4SLinus Torvalds node S. (For instance if we are going to delete an item, virtual 491da177e4SLinus Torvalds node does not contain it). Virtual node keeps information about 501da177e4SLinus Torvalds item sizes and types, mergeability of first and last items, sizes 511da177e4SLinus Torvalds of all entries in directory item. We use this array of items when 521da177e4SLinus Torvalds calculating what we can shift to neighbors and how many nodes we 531da177e4SLinus Torvalds have to have if we do not any shiftings, if we shift to left/right 541da177e4SLinus Torvalds neighbor or to both. */ 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds /* taking item number in virtual node, returns number of item, that it has in source buffer */ 571da177e4SLinus Torvalds static inline int old_item_num(int new_num, int affected_item_num, int mode) 581da177e4SLinus Torvalds { 591da177e4SLinus Torvalds if (mode == M_PASTE || mode == M_CUT || new_num < affected_item_num) 601da177e4SLinus Torvalds return new_num; 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds if (mode == M_INSERT) { 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds RFALSE(new_num == 0, 651da177e4SLinus Torvalds "vs-8005: for INSERT mode and item number of inserted item"); 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds return new_num - 1; 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds RFALSE(mode != M_DELETE, 71bd4c625cSLinus Torvalds "vs-8010: old_item_num: mode must be M_DELETE (mode = \'%c\'", 72bd4c625cSLinus Torvalds mode); 731da177e4SLinus Torvalds /* delete mode */ 741da177e4SLinus Torvalds return new_num + 1; 751da177e4SLinus Torvalds } 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds static void create_virtual_node(struct tree_balance *tb, int h) 781da177e4SLinus Torvalds { 791da177e4SLinus Torvalds struct item_head *ih; 801da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 811da177e4SLinus Torvalds int new_num; 821da177e4SLinus Torvalds struct buffer_head *Sh; /* this comes from tb->S[h] */ 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds Sh = PATH_H_PBUFFER(tb->tb_path, h); 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds /* size of changed node */ 87bd4c625cSLinus Torvalds vn->vn_size = 88bd4c625cSLinus Torvalds MAX_CHILD_SIZE(Sh) - B_FREE_SPACE(Sh) + tb->insert_size[h]; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds /* for internal nodes array if virtual items is not created */ 911da177e4SLinus Torvalds if (h) { 921da177e4SLinus Torvalds vn->vn_nr_item = (vn->vn_size - DC_SIZE) / (DC_SIZE + KEY_SIZE); 931da177e4SLinus Torvalds return; 941da177e4SLinus Torvalds } 951da177e4SLinus Torvalds 961da177e4SLinus Torvalds /* number of items in virtual node */ 97bd4c625cSLinus Torvalds vn->vn_nr_item = 98bd4c625cSLinus Torvalds B_NR_ITEMS(Sh) + ((vn->vn_mode == M_INSERT) ? 1 : 0) - 99bd4c625cSLinus Torvalds ((vn->vn_mode == M_DELETE) ? 1 : 0); 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds /* first virtual item */ 1021da177e4SLinus Torvalds vn->vn_vi = (struct virtual_item *)(tb->tb_vn + 1); 1031da177e4SLinus Torvalds memset(vn->vn_vi, 0, vn->vn_nr_item * sizeof(struct virtual_item)); 1041da177e4SLinus Torvalds vn->vn_free_ptr += vn->vn_nr_item * sizeof(struct virtual_item); 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds /* first item in the node */ 1071da177e4SLinus Torvalds ih = B_N_PITEM_HEAD(Sh, 0); 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds /* define the mergeability for 0-th item (if it is not being deleted) */ 110bd4c625cSLinus Torvalds if (op_is_left_mergeable(&(ih->ih_key), Sh->b_size) 111bd4c625cSLinus Torvalds && (vn->vn_mode != M_DELETE || vn->vn_affected_item_num)) 1121da177e4SLinus Torvalds vn->vn_vi[0].vi_type |= VI_TYPE_LEFT_MERGEABLE; 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds /* go through all items those remain in the virtual node (except for the new (inserted) one) */ 1151da177e4SLinus Torvalds for (new_num = 0; new_num < vn->vn_nr_item; new_num++) { 1161da177e4SLinus Torvalds int j; 1171da177e4SLinus Torvalds struct virtual_item *vi = vn->vn_vi + new_num; 118bd4c625cSLinus Torvalds int is_affected = 119bd4c625cSLinus Torvalds ((new_num != vn->vn_affected_item_num) ? 0 : 1); 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds if (is_affected && vn->vn_mode == M_INSERT) 1221da177e4SLinus Torvalds continue; 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds /* get item number in source node */ 125bd4c625cSLinus Torvalds j = old_item_num(new_num, vn->vn_affected_item_num, 126bd4c625cSLinus Torvalds vn->vn_mode); 1271da177e4SLinus Torvalds 1281da177e4SLinus Torvalds vi->vi_item_len += ih_item_len(ih + j) + IH_SIZE; 1291da177e4SLinus Torvalds vi->vi_ih = ih + j; 1301da177e4SLinus Torvalds vi->vi_item = B_I_PITEM(Sh, ih + j); 1311da177e4SLinus Torvalds vi->vi_uarea = vn->vn_free_ptr; 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds // FIXME: there is no check, that item operation did not 1341da177e4SLinus Torvalds // consume too much memory 135bd4c625cSLinus Torvalds vn->vn_free_ptr += 136bd4c625cSLinus Torvalds op_create_vi(vn, vi, is_affected, tb->insert_size[0]); 1371da177e4SLinus Torvalds if (tb->vn_buf + tb->vn_buf_size < vn->vn_free_ptr) 138c3a9c210SJeff Mahoney reiserfs_panic(tb->tb_sb, "vs-8030", 1391da177e4SLinus Torvalds "virtual node space consumed"); 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds if (!is_affected) 1421da177e4SLinus Torvalds /* this is not being changed */ 1431da177e4SLinus Torvalds continue; 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds if (vn->vn_mode == M_PASTE || vn->vn_mode == M_CUT) { 1461da177e4SLinus Torvalds vn->vn_vi[new_num].vi_item_len += tb->insert_size[0]; 1471da177e4SLinus Torvalds vi->vi_new_data = vn->vn_data; // pointer to data which is going to be pasted 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds /* virtual inserted item is not defined yet */ 1521da177e4SLinus Torvalds if (vn->vn_mode == M_INSERT) { 1531da177e4SLinus Torvalds struct virtual_item *vi = vn->vn_vi + vn->vn_affected_item_num; 1541da177e4SLinus Torvalds 1559dce07f1SAl Viro RFALSE(vn->vn_ins_ih == NULL, 1561da177e4SLinus Torvalds "vs-8040: item header of inserted item is not specified"); 1571da177e4SLinus Torvalds vi->vi_item_len = tb->insert_size[0]; 1581da177e4SLinus Torvalds vi->vi_ih = vn->vn_ins_ih; 1591da177e4SLinus Torvalds vi->vi_item = vn->vn_data; 1601da177e4SLinus Torvalds vi->vi_uarea = vn->vn_free_ptr; 1611da177e4SLinus Torvalds 162bd4c625cSLinus Torvalds op_create_vi(vn, vi, 0 /*not pasted or cut */ , 163bd4c625cSLinus Torvalds tb->insert_size[0]); 1641da177e4SLinus Torvalds } 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds /* set right merge flag we take right delimiting key and check whether it is a mergeable item */ 1671da177e4SLinus Torvalds if (tb->CFR[0]) { 1681da177e4SLinus Torvalds struct reiserfs_key *key; 1691da177e4SLinus Torvalds 1701da177e4SLinus Torvalds key = B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0]); 171bd4c625cSLinus Torvalds if (op_is_left_mergeable(key, Sh->b_size) 172bd4c625cSLinus Torvalds && (vn->vn_mode != M_DELETE 173bd4c625cSLinus Torvalds || vn->vn_affected_item_num != B_NR_ITEMS(Sh) - 1)) 174bd4c625cSLinus Torvalds vn->vn_vi[vn->vn_nr_item - 1].vi_type |= 175bd4c625cSLinus Torvalds VI_TYPE_RIGHT_MERGEABLE; 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK 1781da177e4SLinus Torvalds if (op_is_left_mergeable(key, Sh->b_size) && 179bd4c625cSLinus Torvalds !(vn->vn_mode != M_DELETE 180bd4c625cSLinus Torvalds || vn->vn_affected_item_num != B_NR_ITEMS(Sh) - 1)) { 1811da177e4SLinus Torvalds /* we delete last item and it could be merged with right neighbor's first item */ 182bd4c625cSLinus Torvalds if (! 183bd4c625cSLinus Torvalds (B_NR_ITEMS(Sh) == 1 184bd4c625cSLinus Torvalds && is_direntry_le_ih(B_N_PITEM_HEAD(Sh, 0)) 185bd4c625cSLinus Torvalds && I_ENTRY_COUNT(B_N_PITEM_HEAD(Sh, 0)) == 1)) { 1861da177e4SLinus Torvalds /* node contains more than 1 item, or item is not directory item, or this item contains more than 1 entry */ 1871da177e4SLinus Torvalds print_block(Sh, 0, -1, -1); 188c3a9c210SJeff Mahoney reiserfs_panic(tb->tb_sb, "vs-8045", 189c3a9c210SJeff Mahoney "rdkey %k, affected item==%d " 190c3a9c210SJeff Mahoney "(mode==%c) Must be %c", 191bd4c625cSLinus Torvalds key, vn->vn_affected_item_num, 192bd4c625cSLinus Torvalds vn->vn_mode, M_DELETE); 193cd02b966SVladimir V. Saveliev } 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds #endif 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds } 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds /* using virtual node check, how many items can be shifted to left 2011da177e4SLinus Torvalds neighbor */ 2021da177e4SLinus Torvalds static void check_left(struct tree_balance *tb, int h, int cur_free) 2031da177e4SLinus Torvalds { 2041da177e4SLinus Torvalds int i; 2051da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 2061da177e4SLinus Torvalds struct virtual_item *vi; 2071da177e4SLinus Torvalds int d_size, ih_size; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds RFALSE(cur_free < 0, "vs-8050: cur_free (%d) < 0", cur_free); 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds /* internal level */ 2121da177e4SLinus Torvalds if (h > 0) { 2131da177e4SLinus Torvalds tb->lnum[h] = cur_free / (DC_SIZE + KEY_SIZE); 2141da177e4SLinus Torvalds return; 2151da177e4SLinus Torvalds } 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds /* leaf level */ 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds if (!cur_free || !vn->vn_nr_item) { 2201da177e4SLinus Torvalds /* no free space or nothing to move */ 2211da177e4SLinus Torvalds tb->lnum[h] = 0; 2221da177e4SLinus Torvalds tb->lbytes = -1; 2231da177e4SLinus Torvalds return; 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds RFALSE(!PATH_H_PPARENT(tb->tb_path, 0), 2271da177e4SLinus Torvalds "vs-8055: parent does not exist or invalid"); 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds vi = vn->vn_vi; 230bd4c625cSLinus Torvalds if ((unsigned int)cur_free >= 231bd4c625cSLinus Torvalds (vn->vn_size - 232bd4c625cSLinus Torvalds ((vi->vi_type & VI_TYPE_LEFT_MERGEABLE) ? IH_SIZE : 0))) { 2331da177e4SLinus Torvalds /* all contents of S[0] fits into L[0] */ 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds RFALSE(vn->vn_mode == M_INSERT || vn->vn_mode == M_PASTE, 2361da177e4SLinus Torvalds "vs-8055: invalid mode or balance condition failed"); 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds tb->lnum[0] = vn->vn_nr_item; 2391da177e4SLinus Torvalds tb->lbytes = -1; 2401da177e4SLinus Torvalds return; 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds d_size = 0, ih_size = IH_SIZE; 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds /* first item may be merge with last item in left neighbor */ 2461da177e4SLinus Torvalds if (vi->vi_type & VI_TYPE_LEFT_MERGEABLE) 2471da177e4SLinus Torvalds d_size = -((int)IH_SIZE), ih_size = 0; 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds tb->lnum[0] = 0; 250bd4c625cSLinus Torvalds for (i = 0; i < vn->vn_nr_item; 251bd4c625cSLinus Torvalds i++, ih_size = IH_SIZE, d_size = 0, vi++) { 2521da177e4SLinus Torvalds d_size += vi->vi_item_len; 2531da177e4SLinus Torvalds if (cur_free >= d_size) { 2541da177e4SLinus Torvalds /* the item can be shifted entirely */ 2551da177e4SLinus Torvalds cur_free -= d_size; 2561da177e4SLinus Torvalds tb->lnum[0]++; 2571da177e4SLinus Torvalds continue; 2581da177e4SLinus Torvalds } 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds /* the item cannot be shifted entirely, try to split it */ 2611da177e4SLinus Torvalds /* check whether L[0] can hold ih and at least one byte of the item body */ 2621da177e4SLinus Torvalds if (cur_free <= ih_size) { 2631da177e4SLinus Torvalds /* cannot shift even a part of the current item */ 2641da177e4SLinus Torvalds tb->lbytes = -1; 2651da177e4SLinus Torvalds return; 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds cur_free -= ih_size; 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds tb->lbytes = op_check_left(vi, cur_free, 0, 0); 2701da177e4SLinus Torvalds if (tb->lbytes != -1) 2711da177e4SLinus Torvalds /* count partially shifted item */ 2721da177e4SLinus Torvalds tb->lnum[0]++; 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds break; 2751da177e4SLinus Torvalds } 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds return; 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds /* using virtual node check, how many items can be shifted to right 2811da177e4SLinus Torvalds neighbor */ 2821da177e4SLinus Torvalds static void check_right(struct tree_balance *tb, int h, int cur_free) 2831da177e4SLinus Torvalds { 2841da177e4SLinus Torvalds int i; 2851da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 2861da177e4SLinus Torvalds struct virtual_item *vi; 2871da177e4SLinus Torvalds int d_size, ih_size; 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds RFALSE(cur_free < 0, "vs-8070: cur_free < 0"); 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds /* internal level */ 2921da177e4SLinus Torvalds if (h > 0) { 2931da177e4SLinus Torvalds tb->rnum[h] = cur_free / (DC_SIZE + KEY_SIZE); 2941da177e4SLinus Torvalds return; 2951da177e4SLinus Torvalds } 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds /* leaf level */ 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds if (!cur_free || !vn->vn_nr_item) { 3001da177e4SLinus Torvalds /* no free space */ 3011da177e4SLinus Torvalds tb->rnum[h] = 0; 3021da177e4SLinus Torvalds tb->rbytes = -1; 3031da177e4SLinus Torvalds return; 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds RFALSE(!PATH_H_PPARENT(tb->tb_path, 0), 3071da177e4SLinus Torvalds "vs-8075: parent does not exist or invalid"); 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds vi = vn->vn_vi + vn->vn_nr_item - 1; 310bd4c625cSLinus Torvalds if ((unsigned int)cur_free >= 311bd4c625cSLinus Torvalds (vn->vn_size - 312bd4c625cSLinus Torvalds ((vi->vi_type & VI_TYPE_RIGHT_MERGEABLE) ? IH_SIZE : 0))) { 3131da177e4SLinus Torvalds /* all contents of S[0] fits into R[0] */ 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds RFALSE(vn->vn_mode == M_INSERT || vn->vn_mode == M_PASTE, 3161da177e4SLinus Torvalds "vs-8080: invalid mode or balance condition failed"); 3171da177e4SLinus Torvalds 3181da177e4SLinus Torvalds tb->rnum[h] = vn->vn_nr_item; 3191da177e4SLinus Torvalds tb->rbytes = -1; 3201da177e4SLinus Torvalds return; 3211da177e4SLinus Torvalds } 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds d_size = 0, ih_size = IH_SIZE; 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds /* last item may be merge with first item in right neighbor */ 3261da177e4SLinus Torvalds if (vi->vi_type & VI_TYPE_RIGHT_MERGEABLE) 3271da177e4SLinus Torvalds d_size = -(int)IH_SIZE, ih_size = 0; 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds tb->rnum[0] = 0; 330bd4c625cSLinus Torvalds for (i = vn->vn_nr_item - 1; i >= 0; 331bd4c625cSLinus Torvalds i--, d_size = 0, ih_size = IH_SIZE, vi--) { 3321da177e4SLinus Torvalds d_size += vi->vi_item_len; 3331da177e4SLinus Torvalds if (cur_free >= d_size) { 3341da177e4SLinus Torvalds /* the item can be shifted entirely */ 3351da177e4SLinus Torvalds cur_free -= d_size; 3361da177e4SLinus Torvalds tb->rnum[0]++; 3371da177e4SLinus Torvalds continue; 3381da177e4SLinus Torvalds } 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds /* check whether R[0] can hold ih and at least one byte of the item body */ 3411da177e4SLinus Torvalds if (cur_free <= ih_size) { /* cannot shift even a part of the current item */ 3421da177e4SLinus Torvalds tb->rbytes = -1; 3431da177e4SLinus Torvalds return; 3441da177e4SLinus Torvalds } 3451da177e4SLinus Torvalds 3461da177e4SLinus Torvalds /* R[0] can hold the header of the item and at least one byte of its body */ 3471da177e4SLinus Torvalds cur_free -= ih_size; /* cur_free is still > 0 */ 3481da177e4SLinus Torvalds 3491da177e4SLinus Torvalds tb->rbytes = op_check_right(vi, cur_free); 3501da177e4SLinus Torvalds if (tb->rbytes != -1) 3511da177e4SLinus Torvalds /* count partially shifted item */ 3521da177e4SLinus Torvalds tb->rnum[0]++; 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds break; 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds return; 3581da177e4SLinus Torvalds } 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds /* 3611da177e4SLinus Torvalds * from - number of items, which are shifted to left neighbor entirely 3621da177e4SLinus Torvalds * to - number of item, which are shifted to right neighbor entirely 3631da177e4SLinus Torvalds * from_bytes - number of bytes of boundary item (or directory entries) which are shifted to left neighbor 3641da177e4SLinus Torvalds * to_bytes - number of bytes of boundary item (or directory entries) which are shifted to right neighbor */ 3651da177e4SLinus Torvalds static int get_num_ver(int mode, struct tree_balance *tb, int h, 3661da177e4SLinus Torvalds int from, int from_bytes, 367bd4c625cSLinus Torvalds int to, int to_bytes, short *snum012, int flow) 3681da177e4SLinus Torvalds { 3691da177e4SLinus Torvalds int i; 3701da177e4SLinus Torvalds int cur_free; 3711da177e4SLinus Torvalds // int bytes; 3721da177e4SLinus Torvalds int units; 3731da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 3741da177e4SLinus Torvalds // struct virtual_item * vi; 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds int total_node_size, max_node_size, current_item_size; 3771da177e4SLinus Torvalds int needed_nodes; 3781da177e4SLinus Torvalds int start_item, /* position of item we start filling node from */ 3791da177e4SLinus Torvalds end_item, /* position of item we finish filling node by */ 3801da177e4SLinus Torvalds start_bytes, /* number of first bytes (entries for directory) of start_item-th item 3811da177e4SLinus Torvalds we do not include into node that is being filled */ 3821da177e4SLinus Torvalds end_bytes; /* number of last bytes (entries for directory) of end_item-th item 3831da177e4SLinus Torvalds we do node include into node that is being filled */ 3841da177e4SLinus Torvalds int split_item_positions[2]; /* these are positions in virtual item of 3851da177e4SLinus Torvalds items, that are split between S[0] and 3861da177e4SLinus Torvalds S1new and S1new and S2new */ 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds split_item_positions[0] = -1; 3891da177e4SLinus Torvalds split_item_positions[1] = -1; 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds /* We only create additional nodes if we are in insert or paste mode 3921da177e4SLinus Torvalds or we are in replace mode at the internal level. If h is 0 and 3931da177e4SLinus Torvalds the mode is M_REPLACE then in fix_nodes we change the mode to 3941da177e4SLinus Torvalds paste or insert before we get here in the code. */ 3951da177e4SLinus Torvalds RFALSE(tb->insert_size[h] < 0 || (mode != M_INSERT && mode != M_PASTE), 3961da177e4SLinus Torvalds "vs-8100: insert_size < 0 in overflow"); 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds max_node_size = MAX_CHILD_SIZE(PATH_H_PBUFFER(tb->tb_path, h)); 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds /* snum012 [0-2] - number of items, that lay 4011da177e4SLinus Torvalds to S[0], first new node and second new node */ 4021da177e4SLinus Torvalds snum012[3] = -1; /* s1bytes */ 4031da177e4SLinus Torvalds snum012[4] = -1; /* s2bytes */ 4041da177e4SLinus Torvalds 4051da177e4SLinus Torvalds /* internal level */ 4061da177e4SLinus Torvalds if (h > 0) { 4071da177e4SLinus Torvalds i = ((to - from) * (KEY_SIZE + DC_SIZE) + DC_SIZE); 4081da177e4SLinus Torvalds if (i == max_node_size) 4091da177e4SLinus Torvalds return 1; 4101da177e4SLinus Torvalds return (i / max_node_size + 1); 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds /* leaf level */ 4141da177e4SLinus Torvalds needed_nodes = 1; 4151da177e4SLinus Torvalds total_node_size = 0; 4161da177e4SLinus Torvalds cur_free = max_node_size; 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds // start from 'from'-th item 4191da177e4SLinus Torvalds start_item = from; 4201da177e4SLinus Torvalds // skip its first 'start_bytes' units 4211da177e4SLinus Torvalds start_bytes = ((from_bytes != -1) ? from_bytes : 0); 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds // last included item is the 'end_item'-th one 4241da177e4SLinus Torvalds end_item = vn->vn_nr_item - to - 1; 4251da177e4SLinus Torvalds // do not count last 'end_bytes' units of 'end_item'-th item 4261da177e4SLinus Torvalds end_bytes = (to_bytes != -1) ? to_bytes : 0; 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds /* go through all item beginning from the start_item-th item and ending by 4291da177e4SLinus Torvalds the end_item-th item. Do not count first 'start_bytes' units of 4301da177e4SLinus Torvalds 'start_item'-th item and last 'end_bytes' of 'end_item'-th item */ 4311da177e4SLinus Torvalds 4321da177e4SLinus Torvalds for (i = start_item; i <= end_item; i++) { 4331da177e4SLinus Torvalds struct virtual_item *vi = vn->vn_vi + i; 4341da177e4SLinus Torvalds int skip_from_end = ((i == end_item) ? end_bytes : 0); 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds RFALSE(needed_nodes > 3, "vs-8105: too many nodes are needed"); 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds /* get size of current item */ 4391da177e4SLinus Torvalds current_item_size = vi->vi_item_len; 4401da177e4SLinus Torvalds 4411da177e4SLinus Torvalds /* do not take in calculation head part (from_bytes) of from-th item */ 442bd4c625cSLinus Torvalds current_item_size -= 443bd4c625cSLinus Torvalds op_part_size(vi, 0 /*from start */ , start_bytes); 4441da177e4SLinus Torvalds 4451da177e4SLinus Torvalds /* do not take in calculation tail part of last item */ 446bd4c625cSLinus Torvalds current_item_size -= 447bd4c625cSLinus Torvalds op_part_size(vi, 1 /*from end */ , skip_from_end); 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds /* if item fits into current node entierly */ 4501da177e4SLinus Torvalds if (total_node_size + current_item_size <= max_node_size) { 4511da177e4SLinus Torvalds snum012[needed_nodes - 1]++; 4521da177e4SLinus Torvalds total_node_size += current_item_size; 4531da177e4SLinus Torvalds start_bytes = 0; 4541da177e4SLinus Torvalds continue; 4551da177e4SLinus Torvalds } 4561da177e4SLinus Torvalds 4571da177e4SLinus Torvalds if (current_item_size > max_node_size) { 4581da177e4SLinus Torvalds /* virtual item length is longer, than max size of item in 4591da177e4SLinus Torvalds a node. It is impossible for direct item */ 4601da177e4SLinus Torvalds RFALSE(is_direct_le_ih(vi->vi_ih), 4611da177e4SLinus Torvalds "vs-8110: " 4621da177e4SLinus Torvalds "direct item length is %d. It can not be longer than %d", 4631da177e4SLinus Torvalds current_item_size, max_node_size); 4641da177e4SLinus Torvalds /* we will try to split it */ 4651da177e4SLinus Torvalds flow = 1; 4661da177e4SLinus Torvalds } 4671da177e4SLinus Torvalds 4681da177e4SLinus Torvalds if (!flow) { 4691da177e4SLinus Torvalds /* as we do not split items, take new node and continue */ 470bd4c625cSLinus Torvalds needed_nodes++; 471bd4c625cSLinus Torvalds i--; 472bd4c625cSLinus Torvalds total_node_size = 0; 4731da177e4SLinus Torvalds continue; 4741da177e4SLinus Torvalds } 4751da177e4SLinus Torvalds // calculate number of item units which fit into node being 4761da177e4SLinus Torvalds // filled 4771da177e4SLinus Torvalds { 4781da177e4SLinus Torvalds int free_space; 4791da177e4SLinus Torvalds 4801da177e4SLinus Torvalds free_space = max_node_size - total_node_size - IH_SIZE; 481bd4c625cSLinus Torvalds units = 482bd4c625cSLinus Torvalds op_check_left(vi, free_space, start_bytes, 483bd4c625cSLinus Torvalds skip_from_end); 4841da177e4SLinus Torvalds if (units == -1) { 4851da177e4SLinus Torvalds /* nothing fits into current node, take new node and continue */ 4861da177e4SLinus Torvalds needed_nodes++, i--, total_node_size = 0; 4871da177e4SLinus Torvalds continue; 4881da177e4SLinus Torvalds } 4891da177e4SLinus Torvalds } 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds /* something fits into the current node */ 4921da177e4SLinus Torvalds //if (snum012[3] != -1 || needed_nodes != 1) 4931da177e4SLinus Torvalds // reiserfs_panic (tb->tb_sb, "vs-8115: get_num_ver: too many nodes required"); 4941da177e4SLinus Torvalds //snum012[needed_nodes - 1 + 3] = op_unit_num (vi) - start_bytes - units; 4951da177e4SLinus Torvalds start_bytes += units; 4961da177e4SLinus Torvalds snum012[needed_nodes - 1 + 3] = units; 4971da177e4SLinus Torvalds 4981da177e4SLinus Torvalds if (needed_nodes > 2) 49945b03d5eSJeff Mahoney reiserfs_warning(tb->tb_sb, "vs-8111", 50045b03d5eSJeff Mahoney "split_item_position is out of range"); 5011da177e4SLinus Torvalds snum012[needed_nodes - 1]++; 5021da177e4SLinus Torvalds split_item_positions[needed_nodes - 1] = i; 5031da177e4SLinus Torvalds needed_nodes++; 5041da177e4SLinus Torvalds /* continue from the same item with start_bytes != -1 */ 5051da177e4SLinus Torvalds start_item = i; 5061da177e4SLinus Torvalds i--; 5071da177e4SLinus Torvalds total_node_size = 0; 5081da177e4SLinus Torvalds } 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds // sum012[4] (if it is not -1) contains number of units of which 5111da177e4SLinus Torvalds // are to be in S1new, snum012[3] - to be in S0. They are supposed 5121da177e4SLinus Torvalds // to be S1bytes and S2bytes correspondingly, so recalculate 5131da177e4SLinus Torvalds if (snum012[4] > 0) { 5141da177e4SLinus Torvalds int split_item_num; 5151da177e4SLinus Torvalds int bytes_to_r, bytes_to_l; 5161da177e4SLinus Torvalds int bytes_to_S1new; 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds split_item_num = split_item_positions[1]; 519bd4c625cSLinus Torvalds bytes_to_l = 520bd4c625cSLinus Torvalds ((from == split_item_num 521bd4c625cSLinus Torvalds && from_bytes != -1) ? from_bytes : 0); 522bd4c625cSLinus Torvalds bytes_to_r = 523bd4c625cSLinus Torvalds ((end_item == split_item_num 524bd4c625cSLinus Torvalds && end_bytes != -1) ? end_bytes : 0); 525bd4c625cSLinus Torvalds bytes_to_S1new = 526bd4c625cSLinus Torvalds ((split_item_positions[0] == 527bd4c625cSLinus Torvalds split_item_positions[1]) ? snum012[3] : 0); 5281da177e4SLinus Torvalds 5291da177e4SLinus Torvalds // s2bytes 530bd4c625cSLinus Torvalds snum012[4] = 531bd4c625cSLinus Torvalds op_unit_num(&vn->vn_vi[split_item_num]) - snum012[4] - 532bd4c625cSLinus Torvalds bytes_to_r - bytes_to_l - bytes_to_S1new; 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds if (vn->vn_vi[split_item_num].vi_index != TYPE_DIRENTRY && 5351da177e4SLinus Torvalds vn->vn_vi[split_item_num].vi_index != TYPE_INDIRECT) 53645b03d5eSJeff Mahoney reiserfs_warning(tb->tb_sb, "vs-8115", 53745b03d5eSJeff Mahoney "not directory or indirect item"); 5381da177e4SLinus Torvalds } 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds /* now we know S2bytes, calculate S1bytes */ 5411da177e4SLinus Torvalds if (snum012[3] > 0) { 5421da177e4SLinus Torvalds int split_item_num; 5431da177e4SLinus Torvalds int bytes_to_r, bytes_to_l; 5441da177e4SLinus Torvalds int bytes_to_S2new; 5451da177e4SLinus Torvalds 5461da177e4SLinus Torvalds split_item_num = split_item_positions[0]; 547bd4c625cSLinus Torvalds bytes_to_l = 548bd4c625cSLinus Torvalds ((from == split_item_num 549bd4c625cSLinus Torvalds && from_bytes != -1) ? from_bytes : 0); 550bd4c625cSLinus Torvalds bytes_to_r = 551bd4c625cSLinus Torvalds ((end_item == split_item_num 552bd4c625cSLinus Torvalds && end_bytes != -1) ? end_bytes : 0); 553bd4c625cSLinus Torvalds bytes_to_S2new = 554bd4c625cSLinus Torvalds ((split_item_positions[0] == split_item_positions[1] 555bd4c625cSLinus Torvalds && snum012[4] != -1) ? snum012[4] : 0); 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds // s1bytes 558bd4c625cSLinus Torvalds snum012[3] = 559bd4c625cSLinus Torvalds op_unit_num(&vn->vn_vi[split_item_num]) - snum012[3] - 560bd4c625cSLinus Torvalds bytes_to_r - bytes_to_l - bytes_to_S2new; 5611da177e4SLinus Torvalds } 5621da177e4SLinus Torvalds 5631da177e4SLinus Torvalds return needed_nodes; 5641da177e4SLinus Torvalds } 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK 5671da177e4SLinus Torvalds extern struct tree_balance *cur_tb; 5681da177e4SLinus Torvalds #endif 5691da177e4SLinus Torvalds 5701da177e4SLinus Torvalds /* Set parameters for balancing. 5711da177e4SLinus Torvalds * Performs write of results of analysis of balancing into structure tb, 5721da177e4SLinus Torvalds * where it will later be used by the functions that actually do the balancing. 5731da177e4SLinus Torvalds * Parameters: 5741da177e4SLinus Torvalds * tb tree_balance structure; 5751da177e4SLinus Torvalds * h current level of the node; 5761da177e4SLinus Torvalds * lnum number of items from S[h] that must be shifted to L[h]; 5771da177e4SLinus Torvalds * rnum number of items from S[h] that must be shifted to R[h]; 5781da177e4SLinus Torvalds * blk_num number of blocks that S[h] will be splitted into; 5791da177e4SLinus Torvalds * s012 number of items that fall into splitted nodes. 5801da177e4SLinus Torvalds * lbytes number of bytes which flow to the left neighbor from the item that is not 5811da177e4SLinus Torvalds * not shifted entirely 5821da177e4SLinus Torvalds * rbytes number of bytes which flow to the right neighbor from the item that is not 5831da177e4SLinus Torvalds * not shifted entirely 5841da177e4SLinus Torvalds * s1bytes number of bytes which flow to the first new node when S[0] splits (this number is contained in s012 array) 5851da177e4SLinus Torvalds */ 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds static void set_parameters(struct tree_balance *tb, int h, int lnum, 5881da177e4SLinus Torvalds int rnum, int blk_num, short *s012, int lb, int rb) 5891da177e4SLinus Torvalds { 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds tb->lnum[h] = lnum; 5921da177e4SLinus Torvalds tb->rnum[h] = rnum; 5931da177e4SLinus Torvalds tb->blknum[h] = blk_num; 5941da177e4SLinus Torvalds 595bd4c625cSLinus Torvalds if (h == 0) { /* only for leaf level */ 596bd4c625cSLinus Torvalds if (s012 != NULL) { 5971da177e4SLinus Torvalds tb->s0num = *s012++, 598bd4c625cSLinus Torvalds tb->s1num = *s012++, tb->s2num = *s012++; 5991da177e4SLinus Torvalds tb->s1bytes = *s012++; 6001da177e4SLinus Torvalds tb->s2bytes = *s012; 6011da177e4SLinus Torvalds } 6021da177e4SLinus Torvalds tb->lbytes = lb; 6031da177e4SLinus Torvalds tb->rbytes = rb; 6041da177e4SLinus Torvalds } 6051da177e4SLinus Torvalds PROC_INFO_ADD(tb->tb_sb, lnum[h], lnum); 6061da177e4SLinus Torvalds PROC_INFO_ADD(tb->tb_sb, rnum[h], rnum); 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds PROC_INFO_ADD(tb->tb_sb, lbytes[h], lb); 6091da177e4SLinus Torvalds PROC_INFO_ADD(tb->tb_sb, rbytes[h], rb); 6101da177e4SLinus Torvalds } 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds /* check, does node disappear if we shift tb->lnum[0] items to left 6131da177e4SLinus Torvalds neighbor and tb->rnum[0] to the right one. */ 6141da177e4SLinus Torvalds static int is_leaf_removable(struct tree_balance *tb) 6151da177e4SLinus Torvalds { 6161da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 6171da177e4SLinus Torvalds int to_left, to_right; 6181da177e4SLinus Torvalds int size; 6191da177e4SLinus Torvalds int remain_items; 6201da177e4SLinus Torvalds 6211da177e4SLinus Torvalds /* number of items, that will be shifted to left (right) neighbor 6221da177e4SLinus Torvalds entirely */ 6231da177e4SLinus Torvalds to_left = tb->lnum[0] - ((tb->lbytes != -1) ? 1 : 0); 6241da177e4SLinus Torvalds to_right = tb->rnum[0] - ((tb->rbytes != -1) ? 1 : 0); 6251da177e4SLinus Torvalds remain_items = vn->vn_nr_item; 6261da177e4SLinus Torvalds 6271da177e4SLinus Torvalds /* how many items remain in S[0] after shiftings to neighbors */ 6281da177e4SLinus Torvalds remain_items -= (to_left + to_right); 6291da177e4SLinus Torvalds 6301da177e4SLinus Torvalds if (remain_items < 1) { 6311da177e4SLinus Torvalds /* all content of node can be shifted to neighbors */ 632bd4c625cSLinus Torvalds set_parameters(tb, 0, to_left, vn->vn_nr_item - to_left, 0, 633bd4c625cSLinus Torvalds NULL, -1, -1); 6341da177e4SLinus Torvalds return 1; 6351da177e4SLinus Torvalds } 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds if (remain_items > 1 || tb->lbytes == -1 || tb->rbytes == -1) 6381da177e4SLinus Torvalds /* S[0] is not removable */ 6391da177e4SLinus Torvalds return 0; 6401da177e4SLinus Torvalds 6411da177e4SLinus Torvalds /* check, whether we can divide 1 remaining item between neighbors */ 6421da177e4SLinus Torvalds 6431da177e4SLinus Torvalds /* get size of remaining item (in item units) */ 6441da177e4SLinus Torvalds size = op_unit_num(&(vn->vn_vi[to_left])); 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds if (tb->lbytes + tb->rbytes >= size) { 647bd4c625cSLinus Torvalds set_parameters(tb, 0, to_left + 1, to_right + 1, 0, NULL, 648bd4c625cSLinus Torvalds tb->lbytes, -1); 6491da177e4SLinus Torvalds return 1; 6501da177e4SLinus Torvalds } 6511da177e4SLinus Torvalds 6521da177e4SLinus Torvalds return 0; 6531da177e4SLinus Torvalds } 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds /* check whether L, S, R can be joined in one node */ 6561da177e4SLinus Torvalds static int are_leaves_removable(struct tree_balance *tb, int lfree, int rfree) 6571da177e4SLinus Torvalds { 6581da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 6591da177e4SLinus Torvalds int ih_size; 6601da177e4SLinus Torvalds struct buffer_head *S0; 6611da177e4SLinus Torvalds 6621da177e4SLinus Torvalds S0 = PATH_H_PBUFFER(tb->tb_path, 0); 6631da177e4SLinus Torvalds 6641da177e4SLinus Torvalds ih_size = 0; 6651da177e4SLinus Torvalds if (vn->vn_nr_item) { 6661da177e4SLinus Torvalds if (vn->vn_vi[0].vi_type & VI_TYPE_LEFT_MERGEABLE) 6671da177e4SLinus Torvalds ih_size += IH_SIZE; 6681da177e4SLinus Torvalds 669bd4c625cSLinus Torvalds if (vn->vn_vi[vn->vn_nr_item - 1]. 670bd4c625cSLinus Torvalds vi_type & VI_TYPE_RIGHT_MERGEABLE) 6711da177e4SLinus Torvalds ih_size += IH_SIZE; 6721da177e4SLinus Torvalds } else { 6731da177e4SLinus Torvalds /* there was only one item and it will be deleted */ 6741da177e4SLinus Torvalds struct item_head *ih; 6751da177e4SLinus Torvalds 6761da177e4SLinus Torvalds RFALSE(B_NR_ITEMS(S0) != 1, 677bd4c625cSLinus Torvalds "vs-8125: item number must be 1: it is %d", 678bd4c625cSLinus Torvalds B_NR_ITEMS(S0)); 6791da177e4SLinus Torvalds 6801da177e4SLinus Torvalds ih = B_N_PITEM_HEAD(S0, 0); 681bd4c625cSLinus Torvalds if (tb->CFR[0] 682bd4c625cSLinus Torvalds && !comp_short_le_keys(&(ih->ih_key), 683bd4c625cSLinus Torvalds B_N_PDELIM_KEY(tb->CFR[0], 684bd4c625cSLinus Torvalds tb->rkey[0]))) 6851da177e4SLinus Torvalds if (is_direntry_le_ih(ih)) { 6861da177e4SLinus Torvalds /* Directory must be in correct state here: that is 6871da177e4SLinus Torvalds somewhere at the left side should exist first directory 6881da177e4SLinus Torvalds item. But the item being deleted can not be that first 6891da177e4SLinus Torvalds one because its right neighbor is item of the same 6901da177e4SLinus Torvalds directory. (But first item always gets deleted in last 6911da177e4SLinus Torvalds turn). So, neighbors of deleted item can be merged, so 6921da177e4SLinus Torvalds we can save ih_size */ 6931da177e4SLinus Torvalds ih_size = IH_SIZE; 6941da177e4SLinus Torvalds 6951da177e4SLinus Torvalds /* we might check that left neighbor exists and is of the 6961da177e4SLinus Torvalds same directory */ 6971da177e4SLinus Torvalds RFALSE(le_ih_k_offset(ih) == DOT_OFFSET, 6981da177e4SLinus Torvalds "vs-8130: first directory item can not be removed until directory is not empty"); 6991da177e4SLinus Torvalds } 7001da177e4SLinus Torvalds 7011da177e4SLinus Torvalds } 7021da177e4SLinus Torvalds 7031da177e4SLinus Torvalds if (MAX_CHILD_SIZE(S0) + vn->vn_size <= rfree + lfree + ih_size) { 7041da177e4SLinus Torvalds set_parameters(tb, 0, -1, -1, -1, NULL, -1, -1); 7051da177e4SLinus Torvalds PROC_INFO_INC(tb->tb_sb, leaves_removable); 7061da177e4SLinus Torvalds return 1; 7071da177e4SLinus Torvalds } 7081da177e4SLinus Torvalds return 0; 7091da177e4SLinus Torvalds 7101da177e4SLinus Torvalds } 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds /* when we do not split item, lnum and rnum are numbers of entire items */ 7131da177e4SLinus Torvalds #define SET_PAR_SHIFT_LEFT \ 7141da177e4SLinus Torvalds if (h)\ 7151da177e4SLinus Torvalds {\ 7161da177e4SLinus Torvalds int to_l;\ 7171da177e4SLinus Torvalds \ 7181da177e4SLinus Torvalds to_l = (MAX_NR_KEY(Sh)+1 - lpar + vn->vn_nr_item + 1) / 2 -\ 7191da177e4SLinus Torvalds (MAX_NR_KEY(Sh) + 1 - lpar);\ 7201da177e4SLinus Torvalds \ 7211da177e4SLinus Torvalds set_parameters (tb, h, to_l, 0, lnver, NULL, -1, -1);\ 7221da177e4SLinus Torvalds }\ 7231da177e4SLinus Torvalds else \ 7241da177e4SLinus Torvalds {\ 7251da177e4SLinus Torvalds if (lset==LEFT_SHIFT_FLOW)\ 7261da177e4SLinus Torvalds set_parameters (tb, h, lpar, 0, lnver, snum012+lset,\ 7271da177e4SLinus Torvalds tb->lbytes, -1);\ 7281da177e4SLinus Torvalds else\ 7291da177e4SLinus Torvalds set_parameters (tb, h, lpar - (tb->lbytes!=-1), 0, lnver, snum012+lset,\ 7301da177e4SLinus Torvalds -1, -1);\ 7311da177e4SLinus Torvalds } 7321da177e4SLinus Torvalds 7331da177e4SLinus Torvalds #define SET_PAR_SHIFT_RIGHT \ 7341da177e4SLinus Torvalds if (h)\ 7351da177e4SLinus Torvalds {\ 7361da177e4SLinus Torvalds int to_r;\ 7371da177e4SLinus Torvalds \ 7381da177e4SLinus Torvalds to_r = (MAX_NR_KEY(Sh)+1 - rpar + vn->vn_nr_item + 1) / 2 - (MAX_NR_KEY(Sh) + 1 - rpar);\ 7391da177e4SLinus Torvalds \ 7401da177e4SLinus Torvalds set_parameters (tb, h, 0, to_r, rnver, NULL, -1, -1);\ 7411da177e4SLinus Torvalds }\ 7421da177e4SLinus Torvalds else \ 7431da177e4SLinus Torvalds {\ 7441da177e4SLinus Torvalds if (rset==RIGHT_SHIFT_FLOW)\ 7451da177e4SLinus Torvalds set_parameters (tb, h, 0, rpar, rnver, snum012+rset,\ 7461da177e4SLinus Torvalds -1, tb->rbytes);\ 7471da177e4SLinus Torvalds else\ 7481da177e4SLinus Torvalds set_parameters (tb, h, 0, rpar - (tb->rbytes!=-1), rnver, snum012+rset,\ 7491da177e4SLinus Torvalds -1, -1);\ 7501da177e4SLinus Torvalds } 7511da177e4SLinus Torvalds 752a063ae17SJeff Mahoney static void free_buffers_in_tb(struct tree_balance *tb) 753bd4c625cSLinus Torvalds { 754ee93961bSJeff Mahoney int i; 7551da177e4SLinus Torvalds 756a063ae17SJeff Mahoney pathrelse(tb->tb_path); 7571da177e4SLinus Torvalds 758ee93961bSJeff Mahoney for (i = 0; i < MAX_HEIGHT; i++) { 759ee93961bSJeff Mahoney brelse(tb->L[i]); 760ee93961bSJeff Mahoney brelse(tb->R[i]); 761ee93961bSJeff Mahoney brelse(tb->FL[i]); 762ee93961bSJeff Mahoney brelse(tb->FR[i]); 763ee93961bSJeff Mahoney brelse(tb->CFL[i]); 764ee93961bSJeff Mahoney brelse(tb->CFR[i]); 7653cd6dbe6SJeff Mahoney 766ee93961bSJeff Mahoney tb->L[i] = NULL; 767ee93961bSJeff Mahoney tb->R[i] = NULL; 768ee93961bSJeff Mahoney tb->FL[i] = NULL; 769ee93961bSJeff Mahoney tb->FR[i] = NULL; 770ee93961bSJeff Mahoney tb->CFL[i] = NULL; 771ee93961bSJeff Mahoney tb->CFR[i] = NULL; 7721da177e4SLinus Torvalds } 7731da177e4SLinus Torvalds } 7741da177e4SLinus Torvalds 7751da177e4SLinus Torvalds /* Get new buffers for storing new nodes that are created while balancing. 7761da177e4SLinus Torvalds * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; 7771da177e4SLinus Torvalds * CARRY_ON - schedule didn't occur while the function worked; 7781da177e4SLinus Torvalds * NO_DISK_SPACE - no disk space. 7791da177e4SLinus Torvalds */ 7801da177e4SLinus Torvalds /* The function is NOT SCHEDULE-SAFE! */ 781ee93961bSJeff Mahoney static int get_empty_nodes(struct tree_balance *tb, int h) 782bd4c625cSLinus Torvalds { 783d68caa95SJeff Mahoney struct buffer_head *new_bh, 784ee93961bSJeff Mahoney *Sh = PATH_H_PBUFFER(tb->tb_path, h); 785ee93961bSJeff Mahoney b_blocknr_t *blocknr, blocknrs[MAX_AMOUNT_NEEDED] = { 0, }; 786ee93961bSJeff Mahoney int counter, number_of_freeblk, amount_needed, /* number of needed empty blocks */ 787ee93961bSJeff Mahoney retval = CARRY_ON; 788a063ae17SJeff Mahoney struct super_block *sb = tb->tb_sb; 7891da177e4SLinus Torvalds 7901da177e4SLinus Torvalds /* number_of_freeblk is the number of empty blocks which have been 7911da177e4SLinus Torvalds acquired for use by the balancing algorithm minus the number of 7921da177e4SLinus Torvalds empty blocks used in the previous levels of the analysis, 7931da177e4SLinus Torvalds number_of_freeblk = tb->cur_blknum can be non-zero if a schedule occurs 7941da177e4SLinus Torvalds after empty blocks are acquired, and the balancing analysis is 7951da177e4SLinus Torvalds then restarted, amount_needed is the number needed by this level 796ee93961bSJeff Mahoney (h) of the balancing analysis. 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds Note that for systems with many processes writing, it would be 7991da177e4SLinus Torvalds more layout optimal to calculate the total number needed by all 8001da177e4SLinus Torvalds levels and then to run reiserfs_new_blocks to get all of them at once. */ 8011da177e4SLinus Torvalds 8021da177e4SLinus Torvalds /* Initiate number_of_freeblk to the amount acquired prior to the restart of 8031da177e4SLinus Torvalds the analysis or 0 if not restarted, then subtract the amount needed 804ee93961bSJeff Mahoney by all of the levels of the tree below h. */ 805ee93961bSJeff Mahoney /* blknum includes S[h], so we subtract 1 in this calculation */ 806ee93961bSJeff Mahoney for (counter = 0, number_of_freeblk = tb->cur_blknum; 807ee93961bSJeff Mahoney counter < h; counter++) 808ee93961bSJeff Mahoney number_of_freeblk -= 809ee93961bSJeff Mahoney (tb->blknum[counter]) ? (tb->blknum[counter] - 810bd4c625cSLinus Torvalds 1) : 0; 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds /* Allocate missing empty blocks. */ 813d68caa95SJeff Mahoney /* if Sh == 0 then we are getting a new root */ 814ee93961bSJeff Mahoney amount_needed = (Sh) ? (tb->blknum[h] - 1) : 1; 8151da177e4SLinus Torvalds /* Amount_needed = the amount that we need more than the amount that we have. */ 816ee93961bSJeff Mahoney if (amount_needed > number_of_freeblk) 817ee93961bSJeff Mahoney amount_needed -= number_of_freeblk; 8181da177e4SLinus Torvalds else /* If we have enough already then there is nothing to do. */ 8191da177e4SLinus Torvalds return CARRY_ON; 8201da177e4SLinus Torvalds 8211da177e4SLinus Torvalds /* No need to check quota - is not allocated for blocks used for formatted nodes */ 822ee93961bSJeff Mahoney if (reiserfs_new_form_blocknrs(tb, blocknrs, 823ee93961bSJeff Mahoney amount_needed) == NO_DISK_SPACE) 8241da177e4SLinus Torvalds return NO_DISK_SPACE; 8251da177e4SLinus Torvalds 8261da177e4SLinus Torvalds /* for each blocknumber we just got, get a buffer and stick it on FEB */ 827ee93961bSJeff Mahoney for (blocknr = blocknrs, counter = 0; 828ee93961bSJeff Mahoney counter < amount_needed; blocknr++, counter++) { 8291da177e4SLinus Torvalds 830d68caa95SJeff Mahoney RFALSE(!*blocknr, 8311da177e4SLinus Torvalds "PAP-8135: reiserfs_new_blocknrs failed when got new blocks"); 8321da177e4SLinus Torvalds 833d68caa95SJeff Mahoney new_bh = sb_getblk(sb, *blocknr); 834d68caa95SJeff Mahoney RFALSE(buffer_dirty(new_bh) || 835d68caa95SJeff Mahoney buffer_journaled(new_bh) || 836d68caa95SJeff Mahoney buffer_journal_dirty(new_bh), 837*febe29d9SAdam Buchbinder "PAP-8140: journaled or dirty buffer %b for the new block", 838d68caa95SJeff Mahoney new_bh); 8391da177e4SLinus Torvalds 8401da177e4SLinus Torvalds /* Put empty buffers into the array. */ 841a063ae17SJeff Mahoney RFALSE(tb->FEB[tb->cur_blknum], 8421da177e4SLinus Torvalds "PAP-8141: busy slot for new buffer"); 8431da177e4SLinus Torvalds 844d68caa95SJeff Mahoney set_buffer_journal_new(new_bh); 845d68caa95SJeff Mahoney tb->FEB[tb->cur_blknum++] = new_bh; 8461da177e4SLinus Torvalds } 8471da177e4SLinus Torvalds 848ee93961bSJeff Mahoney if (retval == CARRY_ON && FILESYSTEM_CHANGED_TB(tb)) 849ee93961bSJeff Mahoney retval = REPEAT_SEARCH; 8501da177e4SLinus Torvalds 851ee93961bSJeff Mahoney return retval; 8521da177e4SLinus Torvalds } 8531da177e4SLinus Torvalds 8541da177e4SLinus Torvalds /* Get free space of the left neighbor, which is stored in the parent 8551da177e4SLinus Torvalds * node of the left neighbor. */ 8561da177e4SLinus Torvalds static int get_lfree(struct tree_balance *tb, int h) 8571da177e4SLinus Torvalds { 8581da177e4SLinus Torvalds struct buffer_head *l, *f; 8591da177e4SLinus Torvalds int order; 8601da177e4SLinus Torvalds 8619dce07f1SAl Viro if ((f = PATH_H_PPARENT(tb->tb_path, h)) == NULL || 8629dce07f1SAl Viro (l = tb->FL[h]) == NULL) 8631da177e4SLinus Torvalds return 0; 8641da177e4SLinus Torvalds 8651da177e4SLinus Torvalds if (f == l) 8661da177e4SLinus Torvalds order = PATH_H_B_ITEM_ORDER(tb->tb_path, h) - 1; 8671da177e4SLinus Torvalds else { 8681da177e4SLinus Torvalds order = B_NR_ITEMS(l); 8691da177e4SLinus Torvalds f = l; 8701da177e4SLinus Torvalds } 8711da177e4SLinus Torvalds 8721da177e4SLinus Torvalds return (MAX_CHILD_SIZE(f) - dc_size(B_N_CHILD(f, order))); 8731da177e4SLinus Torvalds } 8741da177e4SLinus Torvalds 8751da177e4SLinus Torvalds /* Get free space of the right neighbor, 8761da177e4SLinus Torvalds * which is stored in the parent node of the right neighbor. 8771da177e4SLinus Torvalds */ 8781da177e4SLinus Torvalds static int get_rfree(struct tree_balance *tb, int h) 8791da177e4SLinus Torvalds { 8801da177e4SLinus Torvalds struct buffer_head *r, *f; 8811da177e4SLinus Torvalds int order; 8821da177e4SLinus Torvalds 8839dce07f1SAl Viro if ((f = PATH_H_PPARENT(tb->tb_path, h)) == NULL || 8849dce07f1SAl Viro (r = tb->FR[h]) == NULL) 8851da177e4SLinus Torvalds return 0; 8861da177e4SLinus Torvalds 8871da177e4SLinus Torvalds if (f == r) 8881da177e4SLinus Torvalds order = PATH_H_B_ITEM_ORDER(tb->tb_path, h) + 1; 8891da177e4SLinus Torvalds else { 8901da177e4SLinus Torvalds order = 0; 8911da177e4SLinus Torvalds f = r; 8921da177e4SLinus Torvalds } 8931da177e4SLinus Torvalds 8941da177e4SLinus Torvalds return (MAX_CHILD_SIZE(f) - dc_size(B_N_CHILD(f, order))); 8951da177e4SLinus Torvalds 8961da177e4SLinus Torvalds } 8971da177e4SLinus Torvalds 8981da177e4SLinus Torvalds /* Check whether left neighbor is in memory. */ 899ee93961bSJeff Mahoney static int is_left_neighbor_in_cache(struct tree_balance *tb, int h) 900bd4c625cSLinus Torvalds { 901d68caa95SJeff Mahoney struct buffer_head *father, *left; 902a063ae17SJeff Mahoney struct super_block *sb = tb->tb_sb; 903ee93961bSJeff Mahoney b_blocknr_t left_neighbor_blocknr; 904ee93961bSJeff Mahoney int left_neighbor_position; 9051da177e4SLinus Torvalds 906a063ae17SJeff Mahoney /* Father of the left neighbor does not exist. */ 907ee93961bSJeff Mahoney if (!tb->FL[h]) 9081da177e4SLinus Torvalds return 0; 9091da177e4SLinus Torvalds 9101da177e4SLinus Torvalds /* Calculate father of the node to be balanced. */ 911ee93961bSJeff Mahoney father = PATH_H_PBUFFER(tb->tb_path, h + 1); 9121da177e4SLinus Torvalds 913d68caa95SJeff Mahoney RFALSE(!father || 914d68caa95SJeff Mahoney !B_IS_IN_TREE(father) || 915ee93961bSJeff Mahoney !B_IS_IN_TREE(tb->FL[h]) || 916d68caa95SJeff Mahoney !buffer_uptodate(father) || 917ee93961bSJeff Mahoney !buffer_uptodate(tb->FL[h]), 9181da177e4SLinus Torvalds "vs-8165: F[h] (%b) or FL[h] (%b) is invalid", 919ee93961bSJeff Mahoney father, tb->FL[h]); 9201da177e4SLinus Torvalds 9211da177e4SLinus Torvalds /* Get position of the pointer to the left neighbor into the left father. */ 922ee93961bSJeff Mahoney left_neighbor_position = (father == tb->FL[h]) ? 923ee93961bSJeff Mahoney tb->lkey[h] : B_NR_ITEMS(tb->FL[h]); 9241da177e4SLinus Torvalds /* Get left neighbor block number. */ 925ee93961bSJeff Mahoney left_neighbor_blocknr = 926ee93961bSJeff Mahoney B_N_CHILD_NUM(tb->FL[h], left_neighbor_position); 9271da177e4SLinus Torvalds /* Look for the left neighbor in the cache. */ 928ee93961bSJeff Mahoney if ((left = sb_find_get_block(sb, left_neighbor_blocknr))) { 9291da177e4SLinus Torvalds 9301da177e4SLinus Torvalds RFALSE(buffer_uptodate(left) && !B_IS_IN_TREE(left), 931bd4c625cSLinus Torvalds "vs-8170: left neighbor (%b %z) is not in the tree", 932bd4c625cSLinus Torvalds left, left); 9331da177e4SLinus Torvalds put_bh(left); 9341da177e4SLinus Torvalds return 1; 9351da177e4SLinus Torvalds } 9361da177e4SLinus Torvalds 9371da177e4SLinus Torvalds return 0; 9381da177e4SLinus Torvalds } 9391da177e4SLinus Torvalds 9401da177e4SLinus Torvalds #define LEFT_PARENTS 'l' 9411da177e4SLinus Torvalds #define RIGHT_PARENTS 'r' 9421da177e4SLinus Torvalds 943d68caa95SJeff Mahoney static void decrement_key(struct cpu_key *key) 9441da177e4SLinus Torvalds { 9451da177e4SLinus Torvalds // call item specific function for this key 946d68caa95SJeff Mahoney item_ops[cpu_key_k_type(key)]->decrement_key(key); 9471da177e4SLinus Torvalds } 9481da177e4SLinus Torvalds 9491da177e4SLinus Torvalds /* Calculate far left/right parent of the left/right neighbor of the current node, that 9501da177e4SLinus Torvalds * is calculate the left/right (FL[h]/FR[h]) neighbor of the parent F[h]. 9511da177e4SLinus Torvalds * Calculate left/right common parent of the current node and L[h]/R[h]. 9521da177e4SLinus Torvalds * Calculate left/right delimiting key position. 9531da177e4SLinus Torvalds * Returns: PATH_INCORRECT - path in the tree is not correct; 9541da177e4SLinus Torvalds SCHEDULE_OCCURRED - schedule occurred while the function worked; 9551da177e4SLinus Torvalds * CARRY_ON - schedule didn't occur while the function worked; 9561da177e4SLinus Torvalds */ 957a063ae17SJeff Mahoney static int get_far_parent(struct tree_balance *tb, 958ee93961bSJeff Mahoney int h, 959d68caa95SJeff Mahoney struct buffer_head **pfather, 960d68caa95SJeff Mahoney struct buffer_head **pcom_father, char c_lr_par) 9611da177e4SLinus Torvalds { 962d68caa95SJeff Mahoney struct buffer_head *parent; 9631da177e4SLinus Torvalds INITIALIZE_PATH(s_path_to_neighbor_father); 964d68caa95SJeff Mahoney struct treepath *path = tb->tb_path; 9651da177e4SLinus Torvalds struct cpu_key s_lr_father_key; 966ee93961bSJeff Mahoney int counter, 967ee93961bSJeff Mahoney position = INT_MAX, 968ee93961bSJeff Mahoney first_last_position = 0, 969ee93961bSJeff Mahoney path_offset = PATH_H_PATH_OFFSET(path, h); 9701da177e4SLinus Torvalds 971ee93961bSJeff Mahoney /* Starting from F[h] go upwards in the tree, and look for the common 972ee93961bSJeff Mahoney ancestor of F[h], and its neighbor l/r, that should be obtained. */ 9731da177e4SLinus Torvalds 974ee93961bSJeff Mahoney counter = path_offset; 9751da177e4SLinus Torvalds 976ee93961bSJeff Mahoney RFALSE(counter < FIRST_PATH_ELEMENT_OFFSET, 9771da177e4SLinus Torvalds "PAP-8180: invalid path length"); 9781da177e4SLinus Torvalds 979ee93961bSJeff Mahoney for (; counter > FIRST_PATH_ELEMENT_OFFSET; counter--) { 9801da177e4SLinus Torvalds /* Check whether parent of the current buffer in the path is really parent in the tree. */ 981bd4c625cSLinus Torvalds if (!B_IS_IN_TREE 982ee93961bSJeff Mahoney (parent = PATH_OFFSET_PBUFFER(path, counter - 1))) 9831da177e4SLinus Torvalds return REPEAT_SEARCH; 9841da177e4SLinus Torvalds /* Check whether position in the parent is correct. */ 985ee93961bSJeff Mahoney if ((position = 986d68caa95SJeff Mahoney PATH_OFFSET_POSITION(path, 987ee93961bSJeff Mahoney counter - 1)) > 988d68caa95SJeff Mahoney B_NR_ITEMS(parent)) 9891da177e4SLinus Torvalds return REPEAT_SEARCH; 9901da177e4SLinus Torvalds /* Check whether parent at the path really points to the child. */ 991ee93961bSJeff Mahoney if (B_N_CHILD_NUM(parent, position) != 992ee93961bSJeff Mahoney PATH_OFFSET_PBUFFER(path, counter)->b_blocknr) 9931da177e4SLinus Torvalds return REPEAT_SEARCH; 9941da177e4SLinus Torvalds /* Return delimiting key if position in the parent is not equal to first/last one. */ 9951da177e4SLinus Torvalds if (c_lr_par == RIGHT_PARENTS) 996ee93961bSJeff Mahoney first_last_position = B_NR_ITEMS(parent); 997ee93961bSJeff Mahoney if (position != first_last_position) { 998d68caa95SJeff Mahoney *pcom_father = parent; 999d68caa95SJeff Mahoney get_bh(*pcom_father); 1000d68caa95SJeff Mahoney /*(*pcom_father = parent)->b_count++; */ 10011da177e4SLinus Torvalds break; 10021da177e4SLinus Torvalds } 10031da177e4SLinus Torvalds } 10041da177e4SLinus Torvalds 10051da177e4SLinus Torvalds /* if we are in the root of the tree, then there is no common father */ 1006ee93961bSJeff Mahoney if (counter == FIRST_PATH_ELEMENT_OFFSET) { 10071da177e4SLinus Torvalds /* Check whether first buffer in the path is the root of the tree. */ 1008bd4c625cSLinus Torvalds if (PATH_OFFSET_PBUFFER 1009a063ae17SJeff Mahoney (tb->tb_path, 1010bd4c625cSLinus Torvalds FIRST_PATH_ELEMENT_OFFSET)->b_blocknr == 1011a063ae17SJeff Mahoney SB_ROOT_BLOCK(tb->tb_sb)) { 1012d68caa95SJeff Mahoney *pfather = *pcom_father = NULL; 10131da177e4SLinus Torvalds return CARRY_ON; 10141da177e4SLinus Torvalds } 10151da177e4SLinus Torvalds return REPEAT_SEARCH; 10161da177e4SLinus Torvalds } 10171da177e4SLinus Torvalds 1018d68caa95SJeff Mahoney RFALSE(B_LEVEL(*pcom_father) <= DISK_LEAF_NODE_LEVEL, 10191da177e4SLinus Torvalds "PAP-8185: (%b %z) level too small", 1020d68caa95SJeff Mahoney *pcom_father, *pcom_father); 10211da177e4SLinus Torvalds 10221da177e4SLinus Torvalds /* Check whether the common parent is locked. */ 10231da177e4SLinus Torvalds 1024d68caa95SJeff Mahoney if (buffer_locked(*pcom_father)) { 1025d68caa95SJeff Mahoney __wait_on_buffer(*pcom_father); 1026a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) { 1027d68caa95SJeff Mahoney brelse(*pcom_father); 10281da177e4SLinus Torvalds return REPEAT_SEARCH; 10291da177e4SLinus Torvalds } 10301da177e4SLinus Torvalds } 10311da177e4SLinus Torvalds 10321da177e4SLinus Torvalds /* So, we got common parent of the current node and its left/right neighbor. 10331da177e4SLinus Torvalds Now we are geting the parent of the left/right neighbor. */ 10341da177e4SLinus Torvalds 10351da177e4SLinus Torvalds /* Form key to get parent of the left/right neighbor. */ 1036bd4c625cSLinus Torvalds le_key2cpu_key(&s_lr_father_key, 1037d68caa95SJeff Mahoney B_N_PDELIM_KEY(*pcom_father, 1038bd4c625cSLinus Torvalds (c_lr_par == 1039ee93961bSJeff Mahoney LEFT_PARENTS) ? (tb->lkey[h - 1] = 1040ee93961bSJeff Mahoney position - 1041ee93961bSJeff Mahoney 1) : (tb->rkey[h - 1042bd4c625cSLinus Torvalds 1] = 1043ee93961bSJeff Mahoney position))); 10441da177e4SLinus Torvalds 10451da177e4SLinus Torvalds if (c_lr_par == LEFT_PARENTS) 10461da177e4SLinus Torvalds decrement_key(&s_lr_father_key); 10471da177e4SLinus Torvalds 1048bd4c625cSLinus Torvalds if (search_by_key 1049a063ae17SJeff Mahoney (tb->tb_sb, &s_lr_father_key, &s_path_to_neighbor_father, 1050ee93961bSJeff Mahoney h + 1) == IO_ERROR) 10511da177e4SLinus Torvalds // path is released 10521da177e4SLinus Torvalds return IO_ERROR; 10531da177e4SLinus Torvalds 1054a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) { 10553cd6dbe6SJeff Mahoney pathrelse(&s_path_to_neighbor_father); 1056d68caa95SJeff Mahoney brelse(*pcom_father); 10571da177e4SLinus Torvalds return REPEAT_SEARCH; 10581da177e4SLinus Torvalds } 10591da177e4SLinus Torvalds 1060d68caa95SJeff Mahoney *pfather = PATH_PLAST_BUFFER(&s_path_to_neighbor_father); 10611da177e4SLinus Torvalds 1062ee93961bSJeff Mahoney RFALSE(B_LEVEL(*pfather) != h + 1, 1063d68caa95SJeff Mahoney "PAP-8190: (%b %z) level too small", *pfather, *pfather); 1064bd4c625cSLinus Torvalds RFALSE(s_path_to_neighbor_father.path_length < 1065bd4c625cSLinus Torvalds FIRST_PATH_ELEMENT_OFFSET, "PAP-8192: path length is too small"); 10661da177e4SLinus Torvalds 10671da177e4SLinus Torvalds s_path_to_neighbor_father.path_length--; 10683cd6dbe6SJeff Mahoney pathrelse(&s_path_to_neighbor_father); 10691da177e4SLinus Torvalds return CARRY_ON; 10701da177e4SLinus Torvalds } 10711da177e4SLinus Torvalds 1072ee93961bSJeff Mahoney /* Get parents of neighbors of node in the path(S[path_offset]) and common parents of 1073ee93961bSJeff Mahoney * S[path_offset] and L[path_offset]/R[path_offset]: F[path_offset], FL[path_offset], 1074ee93961bSJeff Mahoney * FR[path_offset], CFL[path_offset], CFR[path_offset]. 1075ee93961bSJeff Mahoney * Calculate numbers of left and right delimiting keys position: lkey[path_offset], rkey[path_offset]. 10761da177e4SLinus Torvalds * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; 10771da177e4SLinus Torvalds * CARRY_ON - schedule didn't occur while the function worked; 10781da177e4SLinus Torvalds */ 1079ee93961bSJeff Mahoney static int get_parents(struct tree_balance *tb, int h) 10801da177e4SLinus Torvalds { 1081d68caa95SJeff Mahoney struct treepath *path = tb->tb_path; 1082ee93961bSJeff Mahoney int position, 1083ee93961bSJeff Mahoney ret, 1084ee93961bSJeff Mahoney path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h); 1085d68caa95SJeff Mahoney struct buffer_head *curf, *curcf; 10861da177e4SLinus Torvalds 10871da177e4SLinus Torvalds /* Current node is the root of the tree or will be root of the tree */ 1088ee93961bSJeff Mahoney if (path_offset <= FIRST_PATH_ELEMENT_OFFSET) { 10891da177e4SLinus Torvalds /* The root can not have parents. 10901da177e4SLinus Torvalds Release nodes which previously were obtained as parents of the current node neighbors. */ 1091ee93961bSJeff Mahoney brelse(tb->FL[h]); 1092ee93961bSJeff Mahoney brelse(tb->CFL[h]); 1093ee93961bSJeff Mahoney brelse(tb->FR[h]); 1094ee93961bSJeff Mahoney brelse(tb->CFR[h]); 1095ee93961bSJeff Mahoney tb->FL[h] = NULL; 1096ee93961bSJeff Mahoney tb->CFL[h] = NULL; 1097ee93961bSJeff Mahoney tb->FR[h] = NULL; 1098ee93961bSJeff Mahoney tb->CFR[h] = NULL; 10991da177e4SLinus Torvalds return CARRY_ON; 11001da177e4SLinus Torvalds } 11011da177e4SLinus Torvalds 1102ee93961bSJeff Mahoney /* Get parent FL[path_offset] of L[path_offset]. */ 1103ee93961bSJeff Mahoney position = PATH_OFFSET_POSITION(path, path_offset - 1); 1104ee93961bSJeff Mahoney if (position) { 11051da177e4SLinus Torvalds /* Current node is not the first child of its parent. */ 1106ee93961bSJeff Mahoney curf = PATH_OFFSET_PBUFFER(path, path_offset - 1); 1107ee93961bSJeff Mahoney curcf = PATH_OFFSET_PBUFFER(path, path_offset - 1); 1108d68caa95SJeff Mahoney get_bh(curf); 1109d68caa95SJeff Mahoney get_bh(curf); 1110ee93961bSJeff Mahoney tb->lkey[h] = position - 1; 1111bd4c625cSLinus Torvalds } else { 1112ee93961bSJeff Mahoney /* Calculate current parent of L[path_offset], which is the left neighbor of the current node. 1113ee93961bSJeff Mahoney Calculate current common parent of L[path_offset] and the current node. Note that 1114ee93961bSJeff Mahoney CFL[path_offset] not equal FL[path_offset] and CFL[path_offset] not equal F[path_offset]. 1115ee93961bSJeff Mahoney Calculate lkey[path_offset]. */ 1116ee93961bSJeff Mahoney if ((ret = get_far_parent(tb, h + 1, &curf, 1117d68caa95SJeff Mahoney &curcf, 1118bd4c625cSLinus Torvalds LEFT_PARENTS)) != CARRY_ON) 1119ee93961bSJeff Mahoney return ret; 11201da177e4SLinus Torvalds } 11211da177e4SLinus Torvalds 1122ee93961bSJeff Mahoney brelse(tb->FL[h]); 1123ee93961bSJeff Mahoney tb->FL[h] = curf; /* New initialization of FL[h]. */ 1124ee93961bSJeff Mahoney brelse(tb->CFL[h]); 1125ee93961bSJeff Mahoney tb->CFL[h] = curcf; /* New initialization of CFL[h]. */ 11261da177e4SLinus Torvalds 1127d68caa95SJeff Mahoney RFALSE((curf && !B_IS_IN_TREE(curf)) || 1128d68caa95SJeff Mahoney (curcf && !B_IS_IN_TREE(curcf)), 1129d68caa95SJeff Mahoney "PAP-8195: FL (%b) or CFL (%b) is invalid", curf, curcf); 11301da177e4SLinus Torvalds 1131ee93961bSJeff Mahoney /* Get parent FR[h] of R[h]. */ 11321da177e4SLinus Torvalds 1133ee93961bSJeff Mahoney /* Current node is the last child of F[h]. FR[h] != F[h]. */ 1134ee93961bSJeff Mahoney if (position == B_NR_ITEMS(PATH_H_PBUFFER(path, h + 1))) { 1135ee93961bSJeff Mahoney /* Calculate current parent of R[h], which is the right neighbor of F[h]. 1136ee93961bSJeff Mahoney Calculate current common parent of R[h] and current node. Note that CFR[h] 1137ee93961bSJeff Mahoney not equal FR[path_offset] and CFR[h] not equal F[h]. */ 1138ee93961bSJeff Mahoney if ((ret = 1139ee93961bSJeff Mahoney get_far_parent(tb, h + 1, &curf, &curcf, 1140bd4c625cSLinus Torvalds RIGHT_PARENTS)) != CARRY_ON) 1141ee93961bSJeff Mahoney return ret; 1142bd4c625cSLinus Torvalds } else { 1143ee93961bSJeff Mahoney /* Current node is not the last child of its parent F[h]. */ 1144ee93961bSJeff Mahoney curf = PATH_OFFSET_PBUFFER(path, path_offset - 1); 1145ee93961bSJeff Mahoney curcf = PATH_OFFSET_PBUFFER(path, path_offset - 1); 1146d68caa95SJeff Mahoney get_bh(curf); 1147d68caa95SJeff Mahoney get_bh(curf); 1148ee93961bSJeff Mahoney tb->rkey[h] = position; 11491da177e4SLinus Torvalds } 11501da177e4SLinus Torvalds 1151ee93961bSJeff Mahoney brelse(tb->FR[h]); 1152ee93961bSJeff Mahoney /* New initialization of FR[path_offset]. */ 1153ee93961bSJeff Mahoney tb->FR[h] = curf; 11541da177e4SLinus Torvalds 1155ee93961bSJeff Mahoney brelse(tb->CFR[h]); 1156ee93961bSJeff Mahoney /* New initialization of CFR[path_offset]. */ 1157ee93961bSJeff Mahoney tb->CFR[h] = curcf; 11581da177e4SLinus Torvalds 1159d68caa95SJeff Mahoney RFALSE((curf && !B_IS_IN_TREE(curf)) || 1160d68caa95SJeff Mahoney (curcf && !B_IS_IN_TREE(curcf)), 1161d68caa95SJeff Mahoney "PAP-8205: FR (%b) or CFR (%b) is invalid", curf, curcf); 11621da177e4SLinus Torvalds 11631da177e4SLinus Torvalds return CARRY_ON; 11641da177e4SLinus Torvalds } 11651da177e4SLinus Torvalds 11661da177e4SLinus Torvalds /* it is possible to remove node as result of shiftings to 11671da177e4SLinus Torvalds neighbors even when we insert or paste item. */ 1168bd4c625cSLinus Torvalds static inline int can_node_be_removed(int mode, int lfree, int sfree, int rfree, 1169bd4c625cSLinus Torvalds struct tree_balance *tb, int h) 11701da177e4SLinus Torvalds { 11711da177e4SLinus Torvalds struct buffer_head *Sh = PATH_H_PBUFFER(tb->tb_path, h); 11721da177e4SLinus Torvalds int levbytes = tb->insert_size[h]; 11731da177e4SLinus Torvalds struct item_head *ih; 11741da177e4SLinus Torvalds struct reiserfs_key *r_key = NULL; 11751da177e4SLinus Torvalds 11761da177e4SLinus Torvalds ih = B_N_PITEM_HEAD(Sh, 0); 11771da177e4SLinus Torvalds if (tb->CFR[h]) 11781da177e4SLinus Torvalds r_key = B_N_PDELIM_KEY(tb->CFR[h], tb->rkey[h]); 11791da177e4SLinus Torvalds 1180bd4c625cSLinus Torvalds if (lfree + rfree + sfree < MAX_CHILD_SIZE(Sh) + levbytes 11811da177e4SLinus Torvalds /* shifting may merge items which might save space */ 1182bd4c625cSLinus Torvalds - 1183bd4c625cSLinus Torvalds ((!h 1184bd4c625cSLinus Torvalds && op_is_left_mergeable(&(ih->ih_key), Sh->b_size)) ? IH_SIZE : 0) 1185bd4c625cSLinus Torvalds - 1186bd4c625cSLinus Torvalds ((!h && r_key 1187bd4c625cSLinus Torvalds && op_is_left_mergeable(r_key, Sh->b_size)) ? IH_SIZE : 0) 1188bd4c625cSLinus Torvalds + ((h) ? KEY_SIZE : 0)) { 11891da177e4SLinus Torvalds /* node can not be removed */ 11901da177e4SLinus Torvalds if (sfree >= levbytes) { /* new item fits into node S[h] without any shifting */ 11911da177e4SLinus Torvalds if (!h) 1192bd4c625cSLinus Torvalds tb->s0num = 1193bd4c625cSLinus Torvalds B_NR_ITEMS(Sh) + 1194bd4c625cSLinus Torvalds ((mode == M_INSERT) ? 1 : 0); 11951da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 11961da177e4SLinus Torvalds return NO_BALANCING_NEEDED; 11971da177e4SLinus Torvalds } 11981da177e4SLinus Torvalds } 11991da177e4SLinus Torvalds PROC_INFO_INC(tb->tb_sb, can_node_be_removed[h]); 12001da177e4SLinus Torvalds return !NO_BALANCING_NEEDED; 12011da177e4SLinus Torvalds } 12021da177e4SLinus Torvalds 12031da177e4SLinus Torvalds /* Check whether current node S[h] is balanced when increasing its size by 12041da177e4SLinus Torvalds * Inserting or Pasting. 12051da177e4SLinus Torvalds * Calculate parameters for balancing for current level h. 12061da177e4SLinus Torvalds * Parameters: 12071da177e4SLinus Torvalds * tb tree_balance structure; 12081da177e4SLinus Torvalds * h current level of the node; 12091da177e4SLinus Torvalds * inum item number in S[h]; 12101da177e4SLinus Torvalds * mode i - insert, p - paste; 12111da177e4SLinus Torvalds * Returns: 1 - schedule occurred; 12121da177e4SLinus Torvalds * 0 - balancing for higher levels needed; 12131da177e4SLinus Torvalds * -1 - no balancing for higher levels needed; 12141da177e4SLinus Torvalds * -2 - no disk space. 12151da177e4SLinus Torvalds */ 12161da177e4SLinus Torvalds /* ip means Inserting or Pasting */ 12171da177e4SLinus Torvalds static int ip_check_balance(struct tree_balance *tb, int h) 12181da177e4SLinus Torvalds { 12191da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 12201da177e4SLinus Torvalds int levbytes, /* Number of bytes that must be inserted into (value 12211da177e4SLinus Torvalds is negative if bytes are deleted) buffer which 12221da177e4SLinus Torvalds contains node being balanced. The mnemonic is 12231da177e4SLinus Torvalds that the attempted change in node space used level 12241da177e4SLinus Torvalds is levbytes bytes. */ 1225ee93961bSJeff Mahoney ret; 12261da177e4SLinus Torvalds 12271da177e4SLinus Torvalds int lfree, sfree, rfree /* free space in L, S and R */ ; 12281da177e4SLinus Torvalds 12291da177e4SLinus Torvalds /* nver is short for number of vertixes, and lnver is the number if 12301da177e4SLinus Torvalds we shift to the left, rnver is the number if we shift to the 12311da177e4SLinus Torvalds right, and lrnver is the number if we shift in both directions. 12321da177e4SLinus Torvalds The goal is to minimize first the number of vertixes, and second, 12331da177e4SLinus Torvalds the number of vertixes whose contents are changed by shifting, 12341da177e4SLinus Torvalds and third the number of uncached vertixes whose contents are 12351da177e4SLinus Torvalds changed by shifting and must be read from disk. */ 12361da177e4SLinus Torvalds int nver, lnver, rnver, lrnver; 12371da177e4SLinus Torvalds 12381da177e4SLinus Torvalds /* used at leaf level only, S0 = S[0] is the node being balanced, 12391da177e4SLinus Torvalds sInum [ I = 0,1,2 ] is the number of items that will 12401da177e4SLinus Torvalds remain in node SI after balancing. S1 and S2 are new 12411da177e4SLinus Torvalds nodes that might be created. */ 12421da177e4SLinus Torvalds 12431da177e4SLinus Torvalds /* we perform 8 calls to get_num_ver(). For each call we calculate five parameters. 12441da177e4SLinus Torvalds where 4th parameter is s1bytes and 5th - s2bytes 12451da177e4SLinus Torvalds */ 12461da177e4SLinus Torvalds short snum012[40] = { 0, }; /* s0num, s1num, s2num for 8 cases 12471da177e4SLinus Torvalds 0,1 - do not shift and do not shift but bottle 12481da177e4SLinus Torvalds 2 - shift only whole item to left 12491da177e4SLinus Torvalds 3 - shift to left and bottle as much as possible 12501da177e4SLinus Torvalds 4,5 - shift to right (whole items and as much as possible 12511da177e4SLinus Torvalds 6,7 - shift to both directions (whole items and as much as possible) 12521da177e4SLinus Torvalds */ 12531da177e4SLinus Torvalds 12541da177e4SLinus Torvalds /* Sh is the node whose balance is currently being checked */ 12551da177e4SLinus Torvalds struct buffer_head *Sh; 12561da177e4SLinus Torvalds 12571da177e4SLinus Torvalds Sh = PATH_H_PBUFFER(tb->tb_path, h); 12581da177e4SLinus Torvalds levbytes = tb->insert_size[h]; 12591da177e4SLinus Torvalds 12601da177e4SLinus Torvalds /* Calculate balance parameters for creating new root. */ 12611da177e4SLinus Torvalds if (!Sh) { 12621da177e4SLinus Torvalds if (!h) 1263c3a9c210SJeff Mahoney reiserfs_panic(tb->tb_sb, "vs-8210", 1264c3a9c210SJeff Mahoney "S[0] can not be 0"); 1265ee93961bSJeff Mahoney switch (ret = get_empty_nodes(tb, h)) { 12661da177e4SLinus Torvalds case CARRY_ON: 12671da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 12681da177e4SLinus Torvalds return NO_BALANCING_NEEDED; /* no balancing for higher levels needed */ 12691da177e4SLinus Torvalds 12701da177e4SLinus Torvalds case NO_DISK_SPACE: 12711da177e4SLinus Torvalds case REPEAT_SEARCH: 1272ee93961bSJeff Mahoney return ret; 12731da177e4SLinus Torvalds default: 1274c3a9c210SJeff Mahoney reiserfs_panic(tb->tb_sb, "vs-8215", "incorrect " 1275c3a9c210SJeff Mahoney "return value of get_empty_nodes"); 12761da177e4SLinus Torvalds } 12771da177e4SLinus Torvalds } 12781da177e4SLinus Torvalds 1279ee93961bSJeff Mahoney if ((ret = get_parents(tb, h)) != CARRY_ON) /* get parents of S[h] neighbors. */ 1280ee93961bSJeff Mahoney return ret; 12811da177e4SLinus Torvalds 12821da177e4SLinus Torvalds sfree = B_FREE_SPACE(Sh); 12831da177e4SLinus Torvalds 12841da177e4SLinus Torvalds /* get free space of neighbors */ 12851da177e4SLinus Torvalds rfree = get_rfree(tb, h); 12861da177e4SLinus Torvalds lfree = get_lfree(tb, h); 12871da177e4SLinus Torvalds 1288bd4c625cSLinus Torvalds if (can_node_be_removed(vn->vn_mode, lfree, sfree, rfree, tb, h) == 1289bd4c625cSLinus Torvalds NO_BALANCING_NEEDED) 12901da177e4SLinus Torvalds /* and new item fits into node S[h] without any shifting */ 12911da177e4SLinus Torvalds return NO_BALANCING_NEEDED; 12921da177e4SLinus Torvalds 12931da177e4SLinus Torvalds create_virtual_node(tb, h); 12941da177e4SLinus Torvalds 12951da177e4SLinus Torvalds /* 12961da177e4SLinus Torvalds determine maximal number of items we can shift to the left neighbor (in tb structure) 12971da177e4SLinus Torvalds and the maximal number of bytes that can flow to the left neighbor 12981da177e4SLinus Torvalds from the left most liquid item that cannot be shifted from S[0] entirely (returned value) 12991da177e4SLinus Torvalds */ 13001da177e4SLinus Torvalds check_left(tb, h, lfree); 13011da177e4SLinus Torvalds 13021da177e4SLinus Torvalds /* 13031da177e4SLinus Torvalds determine maximal number of items we can shift to the right neighbor (in tb structure) 13041da177e4SLinus Torvalds and the maximal number of bytes that can flow to the right neighbor 13051da177e4SLinus Torvalds from the right most liquid item that cannot be shifted from S[0] entirely (returned value) 13061da177e4SLinus Torvalds */ 13071da177e4SLinus Torvalds check_right(tb, h, rfree); 13081da177e4SLinus Torvalds 13091da177e4SLinus Torvalds /* all contents of internal node S[h] can be moved into its 13101da177e4SLinus Torvalds neighbors, S[h] will be removed after balancing */ 13111da177e4SLinus Torvalds if (h && (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1)) { 13121da177e4SLinus Torvalds int to_r; 13131da177e4SLinus Torvalds 13141da177e4SLinus Torvalds /* Since we are working on internal nodes, and our internal 13151da177e4SLinus Torvalds nodes have fixed size entries, then we can balance by the 13161da177e4SLinus Torvalds number of items rather than the space they consume. In this 13171da177e4SLinus Torvalds routine we set the left node equal to the right node, 13181da177e4SLinus Torvalds allowing a difference of less than or equal to 1 child 13191da177e4SLinus Torvalds pointer. */ 1320bd4c625cSLinus Torvalds to_r = 1321bd4c625cSLinus Torvalds ((MAX_NR_KEY(Sh) << 1) + 2 - tb->lnum[h] - tb->rnum[h] + 1322bd4c625cSLinus Torvalds vn->vn_nr_item + 1) / 2 - (MAX_NR_KEY(Sh) + 1 - 1323bd4c625cSLinus Torvalds tb->rnum[h]); 1324bd4c625cSLinus Torvalds set_parameters(tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, 1325bd4c625cSLinus Torvalds -1, -1); 13261da177e4SLinus Torvalds return CARRY_ON; 13271da177e4SLinus Torvalds } 13281da177e4SLinus Torvalds 13291da177e4SLinus Torvalds /* this checks balance condition, that any two neighboring nodes can not fit in one node */ 13301da177e4SLinus Torvalds RFALSE(h && 13311da177e4SLinus Torvalds (tb->lnum[h] >= vn->vn_nr_item + 1 || 13321da177e4SLinus Torvalds tb->rnum[h] >= vn->vn_nr_item + 1), 13331da177e4SLinus Torvalds "vs-8220: tree is not balanced on internal level"); 13341da177e4SLinus Torvalds RFALSE(!h && ((tb->lnum[h] >= vn->vn_nr_item && (tb->lbytes == -1)) || 13351da177e4SLinus Torvalds (tb->rnum[h] >= vn->vn_nr_item && (tb->rbytes == -1))), 13361da177e4SLinus Torvalds "vs-8225: tree is not balanced on leaf level"); 13371da177e4SLinus Torvalds 13381da177e4SLinus Torvalds /* all contents of S[0] can be moved into its neighbors 13391da177e4SLinus Torvalds S[0] will be removed after balancing. */ 13401da177e4SLinus Torvalds if (!h && is_leaf_removable(tb)) 13411da177e4SLinus Torvalds return CARRY_ON; 13421da177e4SLinus Torvalds 13431da177e4SLinus Torvalds /* why do we perform this check here rather than earlier?? 13441da177e4SLinus Torvalds Answer: we can win 1 node in some cases above. Moreover we 13451da177e4SLinus Torvalds checked it above, when we checked, that S[0] is not removable 13461da177e4SLinus Torvalds in principle */ 13471da177e4SLinus Torvalds if (sfree >= levbytes) { /* new item fits into node S[h] without any shifting */ 13481da177e4SLinus Torvalds if (!h) 13491da177e4SLinus Torvalds tb->s0num = vn->vn_nr_item; 13501da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 13511da177e4SLinus Torvalds return NO_BALANCING_NEEDED; 13521da177e4SLinus Torvalds } 13531da177e4SLinus Torvalds 13541da177e4SLinus Torvalds { 13551da177e4SLinus Torvalds int lpar, rpar, nset, lset, rset, lrset; 13561da177e4SLinus Torvalds /* 13571da177e4SLinus Torvalds * regular overflowing of the node 13581da177e4SLinus Torvalds */ 13591da177e4SLinus Torvalds 13601da177e4SLinus Torvalds /* get_num_ver works in 2 modes (FLOW & NO_FLOW) 13611da177e4SLinus Torvalds lpar, rpar - number of items we can shift to left/right neighbor (including splitting item) 13621da177e4SLinus Torvalds nset, lset, rset, lrset - shows, whether flowing items give better packing 13631da177e4SLinus Torvalds */ 13641da177e4SLinus Torvalds #define FLOW 1 13651da177e4SLinus Torvalds #define NO_FLOW 0 /* do not any splitting */ 13661da177e4SLinus Torvalds 13671da177e4SLinus Torvalds /* we choose one the following */ 13681da177e4SLinus Torvalds #define NOTHING_SHIFT_NO_FLOW 0 13691da177e4SLinus Torvalds #define NOTHING_SHIFT_FLOW 5 13701da177e4SLinus Torvalds #define LEFT_SHIFT_NO_FLOW 10 13711da177e4SLinus Torvalds #define LEFT_SHIFT_FLOW 15 13721da177e4SLinus Torvalds #define RIGHT_SHIFT_NO_FLOW 20 13731da177e4SLinus Torvalds #define RIGHT_SHIFT_FLOW 25 13741da177e4SLinus Torvalds #define LR_SHIFT_NO_FLOW 30 13751da177e4SLinus Torvalds #define LR_SHIFT_FLOW 35 13761da177e4SLinus Torvalds 13771da177e4SLinus Torvalds lpar = tb->lnum[h]; 13781da177e4SLinus Torvalds rpar = tb->rnum[h]; 13791da177e4SLinus Torvalds 13801da177e4SLinus Torvalds /* calculate number of blocks S[h] must be split into when 13811da177e4SLinus Torvalds nothing is shifted to the neighbors, 13821da177e4SLinus Torvalds as well as number of items in each part of the split node (s012 numbers), 13831da177e4SLinus Torvalds and number of bytes (s1bytes) of the shared drop which flow to S1 if any */ 13841da177e4SLinus Torvalds nset = NOTHING_SHIFT_NO_FLOW; 13851da177e4SLinus Torvalds nver = get_num_ver(vn->vn_mode, tb, h, 13861da177e4SLinus Torvalds 0, -1, h ? vn->vn_nr_item : 0, -1, 13871da177e4SLinus Torvalds snum012, NO_FLOW); 13881da177e4SLinus Torvalds 1389bd4c625cSLinus Torvalds if (!h) { 13901da177e4SLinus Torvalds int nver1; 13911da177e4SLinus Torvalds 13921da177e4SLinus Torvalds /* note, that in this case we try to bottle between S[0] and S1 (S1 - the first new node) */ 13931da177e4SLinus Torvalds nver1 = get_num_ver(vn->vn_mode, tb, h, 13941da177e4SLinus Torvalds 0, -1, 0, -1, 13951da177e4SLinus Torvalds snum012 + NOTHING_SHIFT_FLOW, FLOW); 13961da177e4SLinus Torvalds if (nver > nver1) 13971da177e4SLinus Torvalds nset = NOTHING_SHIFT_FLOW, nver = nver1; 13981da177e4SLinus Torvalds } 13991da177e4SLinus Torvalds 14001da177e4SLinus Torvalds /* calculate number of blocks S[h] must be split into when 14011da177e4SLinus Torvalds l_shift_num first items and l_shift_bytes of the right most 14021da177e4SLinus Torvalds liquid item to be shifted are shifted to the left neighbor, 14031da177e4SLinus Torvalds as well as number of items in each part of the splitted node (s012 numbers), 14041da177e4SLinus Torvalds and number of bytes (s1bytes) of the shared drop which flow to S1 if any 14051da177e4SLinus Torvalds */ 14061da177e4SLinus Torvalds lset = LEFT_SHIFT_NO_FLOW; 14071da177e4SLinus Torvalds lnver = get_num_ver(vn->vn_mode, tb, h, 1408bd4c625cSLinus Torvalds lpar - ((h || tb->lbytes == -1) ? 0 : 1), 1409bd4c625cSLinus Torvalds -1, h ? vn->vn_nr_item : 0, -1, 14101da177e4SLinus Torvalds snum012 + LEFT_SHIFT_NO_FLOW, NO_FLOW); 1411bd4c625cSLinus Torvalds if (!h) { 14121da177e4SLinus Torvalds int lnver1; 14131da177e4SLinus Torvalds 14141da177e4SLinus Torvalds lnver1 = get_num_ver(vn->vn_mode, tb, h, 1415bd4c625cSLinus Torvalds lpar - 1416bd4c625cSLinus Torvalds ((tb->lbytes != -1) ? 1 : 0), 1417bd4c625cSLinus Torvalds tb->lbytes, 0, -1, 14181da177e4SLinus Torvalds snum012 + LEFT_SHIFT_FLOW, FLOW); 14191da177e4SLinus Torvalds if (lnver > lnver1) 14201da177e4SLinus Torvalds lset = LEFT_SHIFT_FLOW, lnver = lnver1; 14211da177e4SLinus Torvalds } 14221da177e4SLinus Torvalds 14231da177e4SLinus Torvalds /* calculate number of blocks S[h] must be split into when 14241da177e4SLinus Torvalds r_shift_num first items and r_shift_bytes of the left most 14251da177e4SLinus Torvalds liquid item to be shifted are shifted to the right neighbor, 14261da177e4SLinus Torvalds as well as number of items in each part of the splitted node (s012 numbers), 14271da177e4SLinus Torvalds and number of bytes (s1bytes) of the shared drop which flow to S1 if any 14281da177e4SLinus Torvalds */ 14291da177e4SLinus Torvalds rset = RIGHT_SHIFT_NO_FLOW; 14301da177e4SLinus Torvalds rnver = get_num_ver(vn->vn_mode, tb, h, 1431bd4c625cSLinus Torvalds 0, -1, 1432bd4c625cSLinus Torvalds h ? (vn->vn_nr_item - rpar) : (rpar - 1433bd4c625cSLinus Torvalds ((tb-> 1434bd4c625cSLinus Torvalds rbytes != 1435bd4c625cSLinus Torvalds -1) ? 1 : 1436bd4c625cSLinus Torvalds 0)), -1, 14371da177e4SLinus Torvalds snum012 + RIGHT_SHIFT_NO_FLOW, NO_FLOW); 1438bd4c625cSLinus Torvalds if (!h) { 14391da177e4SLinus Torvalds int rnver1; 14401da177e4SLinus Torvalds 14411da177e4SLinus Torvalds rnver1 = get_num_ver(vn->vn_mode, tb, h, 1442bd4c625cSLinus Torvalds 0, -1, 1443bd4c625cSLinus Torvalds (rpar - 1444bd4c625cSLinus Torvalds ((tb->rbytes != -1) ? 1 : 0)), 1445bd4c625cSLinus Torvalds tb->rbytes, 14461da177e4SLinus Torvalds snum012 + RIGHT_SHIFT_FLOW, FLOW); 14471da177e4SLinus Torvalds 14481da177e4SLinus Torvalds if (rnver > rnver1) 14491da177e4SLinus Torvalds rset = RIGHT_SHIFT_FLOW, rnver = rnver1; 14501da177e4SLinus Torvalds } 14511da177e4SLinus Torvalds 14521da177e4SLinus Torvalds /* calculate number of blocks S[h] must be split into when 14531da177e4SLinus Torvalds items are shifted in both directions, 14541da177e4SLinus Torvalds as well as number of items in each part of the splitted node (s012 numbers), 14551da177e4SLinus Torvalds and number of bytes (s1bytes) of the shared drop which flow to S1 if any 14561da177e4SLinus Torvalds */ 14571da177e4SLinus Torvalds lrset = LR_SHIFT_NO_FLOW; 14581da177e4SLinus Torvalds lrnver = get_num_ver(vn->vn_mode, tb, h, 1459bd4c625cSLinus Torvalds lpar - ((h || tb->lbytes == -1) ? 0 : 1), 1460bd4c625cSLinus Torvalds -1, 1461bd4c625cSLinus Torvalds h ? (vn->vn_nr_item - rpar) : (rpar - 1462bd4c625cSLinus Torvalds ((tb-> 1463bd4c625cSLinus Torvalds rbytes != 1464bd4c625cSLinus Torvalds -1) ? 1 : 1465bd4c625cSLinus Torvalds 0)), -1, 14661da177e4SLinus Torvalds snum012 + LR_SHIFT_NO_FLOW, NO_FLOW); 1467bd4c625cSLinus Torvalds if (!h) { 14681da177e4SLinus Torvalds int lrnver1; 14691da177e4SLinus Torvalds 14701da177e4SLinus Torvalds lrnver1 = get_num_ver(vn->vn_mode, tb, h, 1471bd4c625cSLinus Torvalds lpar - 1472bd4c625cSLinus Torvalds ((tb->lbytes != -1) ? 1 : 0), 1473bd4c625cSLinus Torvalds tb->lbytes, 1474bd4c625cSLinus Torvalds (rpar - 1475bd4c625cSLinus Torvalds ((tb->rbytes != -1) ? 1 : 0)), 1476bd4c625cSLinus Torvalds tb->rbytes, 14771da177e4SLinus Torvalds snum012 + LR_SHIFT_FLOW, FLOW); 14781da177e4SLinus Torvalds if (lrnver > lrnver1) 14791da177e4SLinus Torvalds lrset = LR_SHIFT_FLOW, lrnver = lrnver1; 14801da177e4SLinus Torvalds } 14811da177e4SLinus Torvalds 14821da177e4SLinus Torvalds /* Our general shifting strategy is: 14831da177e4SLinus Torvalds 1) to minimized number of new nodes; 14841da177e4SLinus Torvalds 2) to minimized number of neighbors involved in shifting; 14851da177e4SLinus Torvalds 3) to minimized number of disk reads; */ 14861da177e4SLinus Torvalds 14871da177e4SLinus Torvalds /* we can win TWO or ONE nodes by shifting in both directions */ 1488bd4c625cSLinus Torvalds if (lrnver < lnver && lrnver < rnver) { 14891da177e4SLinus Torvalds RFALSE(h && 14901da177e4SLinus Torvalds (tb->lnum[h] != 1 || 14911da177e4SLinus Torvalds tb->rnum[h] != 1 || 1492bd4c625cSLinus Torvalds lrnver != 1 || rnver != 2 || lnver != 2 1493bd4c625cSLinus Torvalds || h != 1), "vs-8230: bad h"); 14941da177e4SLinus Torvalds if (lrset == LR_SHIFT_FLOW) 1495bd4c625cSLinus Torvalds set_parameters(tb, h, tb->lnum[h], tb->rnum[h], 1496bd4c625cSLinus Torvalds lrnver, snum012 + lrset, 14971da177e4SLinus Torvalds tb->lbytes, tb->rbytes); 14981da177e4SLinus Torvalds else 1499bd4c625cSLinus Torvalds set_parameters(tb, h, 1500bd4c625cSLinus Torvalds tb->lnum[h] - 1501bd4c625cSLinus Torvalds ((tb->lbytes == -1) ? 0 : 1), 1502bd4c625cSLinus Torvalds tb->rnum[h] - 1503bd4c625cSLinus Torvalds ((tb->rbytes == -1) ? 0 : 1), 1504bd4c625cSLinus Torvalds lrnver, snum012 + lrset, -1, -1); 15051da177e4SLinus Torvalds 15061da177e4SLinus Torvalds return CARRY_ON; 15071da177e4SLinus Torvalds } 15081da177e4SLinus Torvalds 15091da177e4SLinus Torvalds /* if shifting doesn't lead to better packing then don't shift */ 1510bd4c625cSLinus Torvalds if (nver == lrnver) { 1511bd4c625cSLinus Torvalds set_parameters(tb, h, 0, 0, nver, snum012 + nset, -1, 1512bd4c625cSLinus Torvalds -1); 15131da177e4SLinus Torvalds return CARRY_ON; 15141da177e4SLinus Torvalds } 15151da177e4SLinus Torvalds 15161da177e4SLinus Torvalds /* now we know that for better packing shifting in only one 15171da177e4SLinus Torvalds direction either to the left or to the right is required */ 15181da177e4SLinus Torvalds 15191da177e4SLinus Torvalds /* if shifting to the left is better than shifting to the right */ 1520bd4c625cSLinus Torvalds if (lnver < rnver) { 15211da177e4SLinus Torvalds SET_PAR_SHIFT_LEFT; 15221da177e4SLinus Torvalds return CARRY_ON; 15231da177e4SLinus Torvalds } 15241da177e4SLinus Torvalds 15251da177e4SLinus Torvalds /* if shifting to the right is better than shifting to the left */ 1526bd4c625cSLinus Torvalds if (lnver > rnver) { 15271da177e4SLinus Torvalds SET_PAR_SHIFT_RIGHT; 15281da177e4SLinus Torvalds return CARRY_ON; 15291da177e4SLinus Torvalds } 15301da177e4SLinus Torvalds 15311da177e4SLinus Torvalds /* now shifting in either direction gives the same number 15321da177e4SLinus Torvalds of nodes and we can make use of the cached neighbors */ 1533bd4c625cSLinus Torvalds if (is_left_neighbor_in_cache(tb, h)) { 15341da177e4SLinus Torvalds SET_PAR_SHIFT_LEFT; 15351da177e4SLinus Torvalds return CARRY_ON; 15361da177e4SLinus Torvalds } 15371da177e4SLinus Torvalds 15381da177e4SLinus Torvalds /* shift to the right independently on whether the right neighbor in cache or not */ 15391da177e4SLinus Torvalds SET_PAR_SHIFT_RIGHT; 15401da177e4SLinus Torvalds return CARRY_ON; 15411da177e4SLinus Torvalds } 15421da177e4SLinus Torvalds } 15431da177e4SLinus Torvalds 15441da177e4SLinus Torvalds /* Check whether current node S[h] is balanced when Decreasing its size by 15451da177e4SLinus Torvalds * Deleting or Cutting for INTERNAL node of S+tree. 15461da177e4SLinus Torvalds * Calculate parameters for balancing for current level h. 15471da177e4SLinus Torvalds * Parameters: 15481da177e4SLinus Torvalds * tb tree_balance structure; 15491da177e4SLinus Torvalds * h current level of the node; 15501da177e4SLinus Torvalds * inum item number in S[h]; 15511da177e4SLinus Torvalds * mode i - insert, p - paste; 15521da177e4SLinus Torvalds * Returns: 1 - schedule occurred; 15531da177e4SLinus Torvalds * 0 - balancing for higher levels needed; 15541da177e4SLinus Torvalds * -1 - no balancing for higher levels needed; 15551da177e4SLinus Torvalds * -2 - no disk space. 15561da177e4SLinus Torvalds * 15571da177e4SLinus Torvalds * Note: Items of internal nodes have fixed size, so the balance condition for 15581da177e4SLinus Torvalds * the internal part of S+tree is as for the B-trees. 15591da177e4SLinus Torvalds */ 15601da177e4SLinus Torvalds static int dc_check_balance_internal(struct tree_balance *tb, int h) 15611da177e4SLinus Torvalds { 15621da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 15631da177e4SLinus Torvalds 15641da177e4SLinus Torvalds /* Sh is the node whose balance is currently being checked, 15651da177e4SLinus Torvalds and Fh is its father. */ 15661da177e4SLinus Torvalds struct buffer_head *Sh, *Fh; 1567ee93961bSJeff Mahoney int maxsize, ret; 15681da177e4SLinus Torvalds int lfree, rfree /* free space in L and R */ ; 15691da177e4SLinus Torvalds 15701da177e4SLinus Torvalds Sh = PATH_H_PBUFFER(tb->tb_path, h); 15711da177e4SLinus Torvalds Fh = PATH_H_PPARENT(tb->tb_path, h); 15721da177e4SLinus Torvalds 15731da177e4SLinus Torvalds maxsize = MAX_CHILD_SIZE(Sh); 15741da177e4SLinus Torvalds 15751da177e4SLinus Torvalds /* using tb->insert_size[h], which is negative in this case, create_virtual_node calculates: */ 15761da177e4SLinus Torvalds /* new_nr_item = number of items node would have if operation is */ 15771da177e4SLinus Torvalds /* performed without balancing (new_nr_item); */ 15781da177e4SLinus Torvalds create_virtual_node(tb, h); 15791da177e4SLinus Torvalds 1580bd4c625cSLinus Torvalds if (!Fh) { /* S[h] is the root. */ 1581bd4c625cSLinus Torvalds if (vn->vn_nr_item > 0) { 15821da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 15831da177e4SLinus Torvalds return NO_BALANCING_NEEDED; /* no balancing for higher levels needed */ 15841da177e4SLinus Torvalds } 15851da177e4SLinus Torvalds /* new_nr_item == 0. 15861da177e4SLinus Torvalds * Current root will be deleted resulting in 15871da177e4SLinus Torvalds * decrementing the tree height. */ 15881da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 0, NULL, -1, -1); 15891da177e4SLinus Torvalds return CARRY_ON; 15901da177e4SLinus Torvalds } 15911da177e4SLinus Torvalds 1592ee93961bSJeff Mahoney if ((ret = get_parents(tb, h)) != CARRY_ON) 1593ee93961bSJeff Mahoney return ret; 15941da177e4SLinus Torvalds 15951da177e4SLinus Torvalds /* get free space of neighbors */ 15961da177e4SLinus Torvalds rfree = get_rfree(tb, h); 15971da177e4SLinus Torvalds lfree = get_lfree(tb, h); 15981da177e4SLinus Torvalds 15991da177e4SLinus Torvalds /* determine maximal number of items we can fit into neighbors */ 16001da177e4SLinus Torvalds check_left(tb, h, lfree); 16011da177e4SLinus Torvalds check_right(tb, h, rfree); 16021da177e4SLinus Torvalds 1603bd4c625cSLinus Torvalds if (vn->vn_nr_item >= MIN_NR_KEY(Sh)) { /* Balance condition for the internal node is valid. 16041da177e4SLinus Torvalds * In this case we balance only if it leads to better packing. */ 1605bd4c625cSLinus Torvalds if (vn->vn_nr_item == MIN_NR_KEY(Sh)) { /* Here we join S[h] with one of its neighbors, 16061da177e4SLinus Torvalds * which is impossible with greater values of new_nr_item. */ 1607bd4c625cSLinus Torvalds if (tb->lnum[h] >= vn->vn_nr_item + 1) { 16081da177e4SLinus Torvalds /* All contents of S[h] can be moved to L[h]. */ 16091da177e4SLinus Torvalds int n; 16101da177e4SLinus Torvalds int order_L; 16111da177e4SLinus Torvalds 1612bd4c625cSLinus Torvalds order_L = 1613bd4c625cSLinus Torvalds ((n = 1614bd4c625cSLinus Torvalds PATH_H_B_ITEM_ORDER(tb->tb_path, 1615bd4c625cSLinus Torvalds h)) == 1616bd4c625cSLinus Torvalds 0) ? B_NR_ITEMS(tb->FL[h]) : n - 1; 1617bd4c625cSLinus Torvalds n = dc_size(B_N_CHILD(tb->FL[h], order_L)) / 1618bd4c625cSLinus Torvalds (DC_SIZE + KEY_SIZE); 1619bd4c625cSLinus Torvalds set_parameters(tb, h, -n - 1, 0, 0, NULL, -1, 1620bd4c625cSLinus Torvalds -1); 16211da177e4SLinus Torvalds return CARRY_ON; 16221da177e4SLinus Torvalds } 16231da177e4SLinus Torvalds 1624bd4c625cSLinus Torvalds if (tb->rnum[h] >= vn->vn_nr_item + 1) { 16251da177e4SLinus Torvalds /* All contents of S[h] can be moved to R[h]. */ 16261da177e4SLinus Torvalds int n; 16271da177e4SLinus Torvalds int order_R; 16281da177e4SLinus Torvalds 1629bd4c625cSLinus Torvalds order_R = 1630bd4c625cSLinus Torvalds ((n = 1631bd4c625cSLinus Torvalds PATH_H_B_ITEM_ORDER(tb->tb_path, 1632bd4c625cSLinus Torvalds h)) == 1633bd4c625cSLinus Torvalds B_NR_ITEMS(Fh)) ? 0 : n + 1; 1634bd4c625cSLinus Torvalds n = dc_size(B_N_CHILD(tb->FR[h], order_R)) / 1635bd4c625cSLinus Torvalds (DC_SIZE + KEY_SIZE); 1636bd4c625cSLinus Torvalds set_parameters(tb, h, 0, -n - 1, 0, NULL, -1, 1637bd4c625cSLinus Torvalds -1); 16381da177e4SLinus Torvalds return CARRY_ON; 16391da177e4SLinus Torvalds } 16401da177e4SLinus Torvalds } 16411da177e4SLinus Torvalds 1642bd4c625cSLinus Torvalds if (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1) { 16431da177e4SLinus Torvalds /* All contents of S[h] can be moved to the neighbors (L[h] & R[h]). */ 16441da177e4SLinus Torvalds int to_r; 16451da177e4SLinus Torvalds 1646bd4c625cSLinus Torvalds to_r = 1647bd4c625cSLinus Torvalds ((MAX_NR_KEY(Sh) << 1) + 2 - tb->lnum[h] - 1648bd4c625cSLinus Torvalds tb->rnum[h] + vn->vn_nr_item + 1) / 2 - 16491da177e4SLinus Torvalds (MAX_NR_KEY(Sh) + 1 - tb->rnum[h]); 1650bd4c625cSLinus Torvalds set_parameters(tb, h, vn->vn_nr_item + 1 - to_r, to_r, 1651bd4c625cSLinus Torvalds 0, NULL, -1, -1); 16521da177e4SLinus Torvalds return CARRY_ON; 16531da177e4SLinus Torvalds } 16541da177e4SLinus Torvalds 16551da177e4SLinus Torvalds /* Balancing does not lead to better packing. */ 16561da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 16571da177e4SLinus Torvalds return NO_BALANCING_NEEDED; 16581da177e4SLinus Torvalds } 16591da177e4SLinus Torvalds 16601da177e4SLinus Torvalds /* Current node contain insufficient number of items. Balancing is required. */ 16611da177e4SLinus Torvalds /* Check whether we can merge S[h] with left neighbor. */ 16621da177e4SLinus Torvalds if (tb->lnum[h] >= vn->vn_nr_item + 1) 1663bd4c625cSLinus Torvalds if (is_left_neighbor_in_cache(tb, h) 1664bd4c625cSLinus Torvalds || tb->rnum[h] < vn->vn_nr_item + 1 || !tb->FR[h]) { 16651da177e4SLinus Torvalds int n; 16661da177e4SLinus Torvalds int order_L; 16671da177e4SLinus Torvalds 1668bd4c625cSLinus Torvalds order_L = 1669bd4c625cSLinus Torvalds ((n = 1670bd4c625cSLinus Torvalds PATH_H_B_ITEM_ORDER(tb->tb_path, 1671bd4c625cSLinus Torvalds h)) == 1672bd4c625cSLinus Torvalds 0) ? B_NR_ITEMS(tb->FL[h]) : n - 1; 1673bd4c625cSLinus Torvalds n = dc_size(B_N_CHILD(tb->FL[h], order_L)) / (DC_SIZE + 1674bd4c625cSLinus Torvalds KEY_SIZE); 16751da177e4SLinus Torvalds set_parameters(tb, h, -n - 1, 0, 0, NULL, -1, -1); 16761da177e4SLinus Torvalds return CARRY_ON; 16771da177e4SLinus Torvalds } 16781da177e4SLinus Torvalds 16791da177e4SLinus Torvalds /* Check whether we can merge S[h] with right neighbor. */ 1680bd4c625cSLinus Torvalds if (tb->rnum[h] >= vn->vn_nr_item + 1) { 16811da177e4SLinus Torvalds int n; 16821da177e4SLinus Torvalds int order_R; 16831da177e4SLinus Torvalds 1684bd4c625cSLinus Torvalds order_R = 1685bd4c625cSLinus Torvalds ((n = 1686bd4c625cSLinus Torvalds PATH_H_B_ITEM_ORDER(tb->tb_path, 1687bd4c625cSLinus Torvalds h)) == B_NR_ITEMS(Fh)) ? 0 : (n + 1); 1688bd4c625cSLinus Torvalds n = dc_size(B_N_CHILD(tb->FR[h], order_R)) / (DC_SIZE + 1689bd4c625cSLinus Torvalds KEY_SIZE); 16901da177e4SLinus Torvalds set_parameters(tb, h, 0, -n - 1, 0, NULL, -1, -1); 16911da177e4SLinus Torvalds return CARRY_ON; 16921da177e4SLinus Torvalds } 16931da177e4SLinus Torvalds 16941da177e4SLinus Torvalds /* All contents of S[h] can be moved to the neighbors (L[h] & R[h]). */ 1695bd4c625cSLinus Torvalds if (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1) { 16961da177e4SLinus Torvalds int to_r; 16971da177e4SLinus Torvalds 1698bd4c625cSLinus Torvalds to_r = 1699bd4c625cSLinus Torvalds ((MAX_NR_KEY(Sh) << 1) + 2 - tb->lnum[h] - tb->rnum[h] + 1700bd4c625cSLinus Torvalds vn->vn_nr_item + 1) / 2 - (MAX_NR_KEY(Sh) + 1 - 1701bd4c625cSLinus Torvalds tb->rnum[h]); 1702bd4c625cSLinus Torvalds set_parameters(tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, 1703bd4c625cSLinus Torvalds -1, -1); 17041da177e4SLinus Torvalds return CARRY_ON; 17051da177e4SLinus Torvalds } 17061da177e4SLinus Torvalds 17071da177e4SLinus Torvalds /* For internal nodes try to borrow item from a neighbor */ 17081da177e4SLinus Torvalds RFALSE(!tb->FL[h] && !tb->FR[h], "vs-8235: trying to borrow for root"); 17091da177e4SLinus Torvalds 17101da177e4SLinus Torvalds /* Borrow one or two items from caching neighbor */ 1711bd4c625cSLinus Torvalds if (is_left_neighbor_in_cache(tb, h) || !tb->FR[h]) { 17121da177e4SLinus Torvalds int from_l; 17131da177e4SLinus Torvalds 1714bd4c625cSLinus Torvalds from_l = 1715bd4c625cSLinus Torvalds (MAX_NR_KEY(Sh) + 1 - tb->lnum[h] + vn->vn_nr_item + 1716bd4c625cSLinus Torvalds 1) / 2 - (vn->vn_nr_item + 1); 17171da177e4SLinus Torvalds set_parameters(tb, h, -from_l, 0, 1, NULL, -1, -1); 17181da177e4SLinus Torvalds return CARRY_ON; 17191da177e4SLinus Torvalds } 17201da177e4SLinus Torvalds 1721bd4c625cSLinus Torvalds set_parameters(tb, h, 0, 1722bd4c625cSLinus Torvalds -((MAX_NR_KEY(Sh) + 1 - tb->rnum[h] + vn->vn_nr_item + 1723bd4c625cSLinus Torvalds 1) / 2 - (vn->vn_nr_item + 1)), 1, NULL, -1, -1); 17241da177e4SLinus Torvalds return CARRY_ON; 17251da177e4SLinus Torvalds } 17261da177e4SLinus Torvalds 17271da177e4SLinus Torvalds /* Check whether current node S[h] is balanced when Decreasing its size by 17281da177e4SLinus Torvalds * Deleting or Truncating for LEAF node of S+tree. 17291da177e4SLinus Torvalds * Calculate parameters for balancing for current level h. 17301da177e4SLinus Torvalds * Parameters: 17311da177e4SLinus Torvalds * tb tree_balance structure; 17321da177e4SLinus Torvalds * h current level of the node; 17331da177e4SLinus Torvalds * inum item number in S[h]; 17341da177e4SLinus Torvalds * mode i - insert, p - paste; 17351da177e4SLinus Torvalds * Returns: 1 - schedule occurred; 17361da177e4SLinus Torvalds * 0 - balancing for higher levels needed; 17371da177e4SLinus Torvalds * -1 - no balancing for higher levels needed; 17381da177e4SLinus Torvalds * -2 - no disk space. 17391da177e4SLinus Torvalds */ 17401da177e4SLinus Torvalds static int dc_check_balance_leaf(struct tree_balance *tb, int h) 17411da177e4SLinus Torvalds { 17421da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 17431da177e4SLinus Torvalds 17441da177e4SLinus Torvalds /* Number of bytes that must be deleted from 17451da177e4SLinus Torvalds (value is negative if bytes are deleted) buffer which 17461da177e4SLinus Torvalds contains node being balanced. The mnemonic is that the 17471da177e4SLinus Torvalds attempted change in node space used level is levbytes bytes. */ 17481da177e4SLinus Torvalds int levbytes; 17491da177e4SLinus Torvalds /* the maximal item size */ 1750ee93961bSJeff Mahoney int maxsize, ret; 17511da177e4SLinus Torvalds /* S0 is the node whose balance is currently being checked, 17521da177e4SLinus Torvalds and F0 is its father. */ 17531da177e4SLinus Torvalds struct buffer_head *S0, *F0; 17541da177e4SLinus Torvalds int lfree, rfree /* free space in L and R */ ; 17551da177e4SLinus Torvalds 17561da177e4SLinus Torvalds S0 = PATH_H_PBUFFER(tb->tb_path, 0); 17571da177e4SLinus Torvalds F0 = PATH_H_PPARENT(tb->tb_path, 0); 17581da177e4SLinus Torvalds 17591da177e4SLinus Torvalds levbytes = tb->insert_size[h]; 17601da177e4SLinus Torvalds 17611da177e4SLinus Torvalds maxsize = MAX_CHILD_SIZE(S0); /* maximal possible size of an item */ 17621da177e4SLinus Torvalds 1763bd4c625cSLinus Torvalds if (!F0) { /* S[0] is the root now. */ 17641da177e4SLinus Torvalds 17651da177e4SLinus Torvalds RFALSE(-levbytes >= maxsize - B_FREE_SPACE(S0), 17661da177e4SLinus Torvalds "vs-8240: attempt to create empty buffer tree"); 17671da177e4SLinus Torvalds 17681da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 17691da177e4SLinus Torvalds return NO_BALANCING_NEEDED; 17701da177e4SLinus Torvalds } 17711da177e4SLinus Torvalds 1772ee93961bSJeff Mahoney if ((ret = get_parents(tb, h)) != CARRY_ON) 1773ee93961bSJeff Mahoney return ret; 17741da177e4SLinus Torvalds 17751da177e4SLinus Torvalds /* get free space of neighbors */ 17761da177e4SLinus Torvalds rfree = get_rfree(tb, h); 17771da177e4SLinus Torvalds lfree = get_lfree(tb, h); 17781da177e4SLinus Torvalds 17791da177e4SLinus Torvalds create_virtual_node(tb, h); 17801da177e4SLinus Torvalds 17811da177e4SLinus Torvalds /* if 3 leaves can be merge to one, set parameters and return */ 17821da177e4SLinus Torvalds if (are_leaves_removable(tb, lfree, rfree)) 17831da177e4SLinus Torvalds return CARRY_ON; 17841da177e4SLinus Torvalds 17851da177e4SLinus Torvalds /* determine maximal number of items we can shift to the left/right neighbor 17861da177e4SLinus Torvalds and the maximal number of bytes that can flow to the left/right neighbor 17871da177e4SLinus Torvalds from the left/right most liquid item that cannot be shifted from S[0] entirely 17881da177e4SLinus Torvalds */ 17891da177e4SLinus Torvalds check_left(tb, h, lfree); 17901da177e4SLinus Torvalds check_right(tb, h, rfree); 17911da177e4SLinus Torvalds 17921da177e4SLinus Torvalds /* check whether we can merge S with left neighbor. */ 17931da177e4SLinus Torvalds if (tb->lnum[0] >= vn->vn_nr_item && tb->lbytes == -1) 1794bd4c625cSLinus Torvalds 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 */ 17951da177e4SLinus Torvalds !tb->FR[h]) { 17961da177e4SLinus Torvalds 1797bd4c625cSLinus Torvalds RFALSE(!tb->FL[h], 1798bd4c625cSLinus Torvalds "vs-8245: dc_check_balance_leaf: FL[h] must exist"); 17991da177e4SLinus Torvalds 18001da177e4SLinus Torvalds /* set parameter to merge S[0] with its left neighbor */ 18011da177e4SLinus Torvalds set_parameters(tb, h, -1, 0, 0, NULL, -1, -1); 18021da177e4SLinus Torvalds return CARRY_ON; 18031da177e4SLinus Torvalds } 18041da177e4SLinus Torvalds 18051da177e4SLinus Torvalds /* check whether we can merge S[0] with right neighbor. */ 18061da177e4SLinus Torvalds if (tb->rnum[0] >= vn->vn_nr_item && tb->rbytes == -1) { 18071da177e4SLinus Torvalds set_parameters(tb, h, 0, -1, 0, NULL, -1, -1); 18081da177e4SLinus Torvalds return CARRY_ON; 18091da177e4SLinus Torvalds } 18101da177e4SLinus Torvalds 18111da177e4SLinus Torvalds /* All contents of S[0] can be moved to the neighbors (L[0] & R[0]). Set parameters and return */ 18121da177e4SLinus Torvalds if (is_leaf_removable(tb)) 18131da177e4SLinus Torvalds return CARRY_ON; 18141da177e4SLinus Torvalds 18151da177e4SLinus Torvalds /* Balancing is not required. */ 18161da177e4SLinus Torvalds tb->s0num = vn->vn_nr_item; 18171da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 18181da177e4SLinus Torvalds return NO_BALANCING_NEEDED; 18191da177e4SLinus Torvalds } 18201da177e4SLinus Torvalds 18211da177e4SLinus Torvalds /* Check whether current node S[h] is balanced when Decreasing its size by 18221da177e4SLinus Torvalds * Deleting or Cutting. 18231da177e4SLinus Torvalds * Calculate parameters for balancing for current level h. 18241da177e4SLinus Torvalds * Parameters: 18251da177e4SLinus Torvalds * tb tree_balance structure; 18261da177e4SLinus Torvalds * h current level of the node; 18271da177e4SLinus Torvalds * inum item number in S[h]; 18281da177e4SLinus Torvalds * mode d - delete, c - cut. 18291da177e4SLinus Torvalds * Returns: 1 - schedule occurred; 18301da177e4SLinus Torvalds * 0 - balancing for higher levels needed; 18311da177e4SLinus Torvalds * -1 - no balancing for higher levels needed; 18321da177e4SLinus Torvalds * -2 - no disk space. 18331da177e4SLinus Torvalds */ 18341da177e4SLinus Torvalds static int dc_check_balance(struct tree_balance *tb, int h) 18351da177e4SLinus Torvalds { 1836bd4c625cSLinus Torvalds RFALSE(!(PATH_H_PBUFFER(tb->tb_path, h)), 1837bd4c625cSLinus Torvalds "vs-8250: S is not initialized"); 18381da177e4SLinus Torvalds 18391da177e4SLinus Torvalds if (h) 18401da177e4SLinus Torvalds return dc_check_balance_internal(tb, h); 18411da177e4SLinus Torvalds else 18421da177e4SLinus Torvalds return dc_check_balance_leaf(tb, h); 18431da177e4SLinus Torvalds } 18441da177e4SLinus Torvalds 18451da177e4SLinus Torvalds /* Check whether current node S[h] is balanced. 18461da177e4SLinus Torvalds * Calculate parameters for balancing for current level h. 18471da177e4SLinus Torvalds * Parameters: 18481da177e4SLinus Torvalds * 18491da177e4SLinus Torvalds * tb tree_balance structure: 18501da177e4SLinus Torvalds * 18511da177e4SLinus Torvalds * tb is a large structure that must be read about in the header file 18521da177e4SLinus Torvalds * at the same time as this procedure if the reader is to successfully 18531da177e4SLinus Torvalds * understand this procedure 18541da177e4SLinus Torvalds * 18551da177e4SLinus Torvalds * h current level of the node; 18561da177e4SLinus Torvalds * inum item number in S[h]; 18571da177e4SLinus Torvalds * mode i - insert, p - paste, d - delete, c - cut. 18581da177e4SLinus Torvalds * Returns: 1 - schedule occurred; 18591da177e4SLinus Torvalds * 0 - balancing for higher levels needed; 18601da177e4SLinus Torvalds * -1 - no balancing for higher levels needed; 18611da177e4SLinus Torvalds * -2 - no disk space. 18621da177e4SLinus Torvalds */ 18631da177e4SLinus Torvalds static int check_balance(int mode, 18641da177e4SLinus Torvalds struct tree_balance *tb, 18651da177e4SLinus Torvalds int h, 18661da177e4SLinus Torvalds int inum, 18671da177e4SLinus Torvalds int pos_in_item, 1868bd4c625cSLinus Torvalds struct item_head *ins_ih, const void *data) 18691da177e4SLinus Torvalds { 18701da177e4SLinus Torvalds struct virtual_node *vn; 18711da177e4SLinus Torvalds 18721da177e4SLinus Torvalds vn = tb->tb_vn = (struct virtual_node *)(tb->vn_buf); 18731da177e4SLinus Torvalds vn->vn_free_ptr = (char *)(tb->tb_vn + 1); 18741da177e4SLinus Torvalds vn->vn_mode = mode; 18751da177e4SLinus Torvalds vn->vn_affected_item_num = inum; 18761da177e4SLinus Torvalds vn->vn_pos_in_item = pos_in_item; 18771da177e4SLinus Torvalds vn->vn_ins_ih = ins_ih; 18781da177e4SLinus Torvalds vn->vn_data = data; 18791da177e4SLinus Torvalds 18801da177e4SLinus Torvalds RFALSE(mode == M_INSERT && !vn->vn_ins_ih, 18811da177e4SLinus Torvalds "vs-8255: ins_ih can not be 0 in insert mode"); 18821da177e4SLinus Torvalds 18831da177e4SLinus Torvalds if (tb->insert_size[h] > 0) 18841da177e4SLinus Torvalds /* Calculate balance parameters when size of node is increasing. */ 18851da177e4SLinus Torvalds return ip_check_balance(tb, h); 18861da177e4SLinus Torvalds 18871da177e4SLinus Torvalds /* Calculate balance parameters when size of node is decreasing. */ 18881da177e4SLinus Torvalds return dc_check_balance(tb, h); 18891da177e4SLinus Torvalds } 18901da177e4SLinus Torvalds 18911da177e4SLinus Torvalds /* Check whether parent at the path is the really parent of the current node.*/ 1892ee93961bSJeff Mahoney static int get_direct_parent(struct tree_balance *tb, int h) 1893bd4c625cSLinus Torvalds { 1894ad31a4fcSJeff Mahoney struct buffer_head *bh; 1895d68caa95SJeff Mahoney struct treepath *path = tb->tb_path; 1896ee93961bSJeff Mahoney int position, 1897ee93961bSJeff Mahoney path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h); 18981da177e4SLinus Torvalds 18991da177e4SLinus Torvalds /* We are in the root or in the new root. */ 1900ee93961bSJeff Mahoney if (path_offset <= FIRST_PATH_ELEMENT_OFFSET) { 19011da177e4SLinus Torvalds 1902ee93961bSJeff Mahoney RFALSE(path_offset < FIRST_PATH_ELEMENT_OFFSET - 1, 19031da177e4SLinus Torvalds "PAP-8260: invalid offset in the path"); 19041da177e4SLinus Torvalds 1905d68caa95SJeff Mahoney if (PATH_OFFSET_PBUFFER(path, FIRST_PATH_ELEMENT_OFFSET)-> 1906a063ae17SJeff Mahoney b_blocknr == SB_ROOT_BLOCK(tb->tb_sb)) { 19071da177e4SLinus Torvalds /* Root is not changed. */ 1908ee93961bSJeff Mahoney PATH_OFFSET_PBUFFER(path, path_offset - 1) = NULL; 1909ee93961bSJeff Mahoney PATH_OFFSET_POSITION(path, path_offset - 1) = 0; 19101da177e4SLinus Torvalds return CARRY_ON; 19111da177e4SLinus Torvalds } 19121da177e4SLinus Torvalds return REPEAT_SEARCH; /* Root is changed and we must recalculate the path. */ 19131da177e4SLinus Torvalds } 19141da177e4SLinus Torvalds 1915bd4c625cSLinus Torvalds if (!B_IS_IN_TREE 1916ee93961bSJeff Mahoney (bh = PATH_OFFSET_PBUFFER(path, path_offset - 1))) 19171da177e4SLinus Torvalds return REPEAT_SEARCH; /* Parent in the path is not in the tree. */ 19181da177e4SLinus Torvalds 1919ee93961bSJeff Mahoney if ((position = 1920d68caa95SJeff Mahoney PATH_OFFSET_POSITION(path, 1921ee93961bSJeff Mahoney path_offset - 1)) > B_NR_ITEMS(bh)) 19221da177e4SLinus Torvalds return REPEAT_SEARCH; 19231da177e4SLinus Torvalds 1924ee93961bSJeff Mahoney if (B_N_CHILD_NUM(bh, position) != 1925ee93961bSJeff Mahoney PATH_OFFSET_PBUFFER(path, path_offset)->b_blocknr) 19261da177e4SLinus Torvalds /* Parent in the path is not parent of the current node in the tree. */ 19271da177e4SLinus Torvalds return REPEAT_SEARCH; 19281da177e4SLinus Torvalds 1929ad31a4fcSJeff Mahoney if (buffer_locked(bh)) { 1930ad31a4fcSJeff Mahoney __wait_on_buffer(bh); 1931a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) 19321da177e4SLinus Torvalds return REPEAT_SEARCH; 19331da177e4SLinus Torvalds } 19341da177e4SLinus Torvalds 19351da177e4SLinus Torvalds return CARRY_ON; /* Parent in the path is unlocked and really parent of the current node. */ 19361da177e4SLinus Torvalds } 19371da177e4SLinus Torvalds 1938ee93961bSJeff Mahoney /* Using lnum[h] and rnum[h] we should determine what neighbors 1939ee93961bSJeff Mahoney * of S[h] we 1940ee93961bSJeff Mahoney * need in order to balance S[h], and get them if necessary. 19411da177e4SLinus Torvalds * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; 19421da177e4SLinus Torvalds * CARRY_ON - schedule didn't occur while the function worked; 19431da177e4SLinus Torvalds */ 1944ee93961bSJeff Mahoney static int get_neighbors(struct tree_balance *tb, int h) 1945bd4c625cSLinus Torvalds { 1946ee93961bSJeff Mahoney int child_position, 1947ee93961bSJeff Mahoney path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h + 1); 1948ee93961bSJeff Mahoney unsigned long son_number; 1949a063ae17SJeff Mahoney struct super_block *sb = tb->tb_sb; 1950ad31a4fcSJeff Mahoney struct buffer_head *bh; 19511da177e4SLinus Torvalds 1952ee93961bSJeff Mahoney PROC_INFO_INC(sb, get_neighbors[h]); 19531da177e4SLinus Torvalds 1954ee93961bSJeff Mahoney if (tb->lnum[h]) { 1955ee93961bSJeff Mahoney /* We need left neighbor to balance S[h]. */ 1956ee93961bSJeff Mahoney PROC_INFO_INC(sb, need_l_neighbor[h]); 1957ee93961bSJeff Mahoney bh = PATH_OFFSET_PBUFFER(tb->tb_path, path_offset); 19581da177e4SLinus Torvalds 1959ee93961bSJeff Mahoney RFALSE(bh == tb->FL[h] && 1960ee93961bSJeff Mahoney !PATH_OFFSET_POSITION(tb->tb_path, path_offset), 19611da177e4SLinus Torvalds "PAP-8270: invalid position in the parent"); 19621da177e4SLinus Torvalds 1963ee93961bSJeff Mahoney child_position = 1964ad31a4fcSJeff Mahoney (bh == 1965ee93961bSJeff Mahoney tb->FL[h]) ? tb->lkey[h] : B_NR_ITEMS(tb-> 1966ee93961bSJeff Mahoney FL[h]); 1967ee93961bSJeff Mahoney son_number = B_N_CHILD_NUM(tb->FL[h], child_position); 1968ee93961bSJeff Mahoney bh = sb_bread(sb, son_number); 1969ad31a4fcSJeff Mahoney if (!bh) 19701da177e4SLinus Torvalds return IO_ERROR; 1971a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) { 1972ad31a4fcSJeff Mahoney brelse(bh); 1973ee93961bSJeff Mahoney PROC_INFO_INC(sb, get_neighbors_restart[h]); 19741da177e4SLinus Torvalds return REPEAT_SEARCH; 19751da177e4SLinus Torvalds } 19761da177e4SLinus Torvalds 1977ee93961bSJeff Mahoney RFALSE(!B_IS_IN_TREE(tb->FL[h]) || 1978ee93961bSJeff Mahoney child_position > B_NR_ITEMS(tb->FL[h]) || 1979ee93961bSJeff Mahoney B_N_CHILD_NUM(tb->FL[h], child_position) != 1980ad31a4fcSJeff Mahoney bh->b_blocknr, "PAP-8275: invalid parent"); 1981ad31a4fcSJeff Mahoney RFALSE(!B_IS_IN_TREE(bh), "PAP-8280: invalid child"); 1982ee93961bSJeff Mahoney RFALSE(!h && 1983ad31a4fcSJeff Mahoney B_FREE_SPACE(bh) != 1984ad31a4fcSJeff Mahoney MAX_CHILD_SIZE(bh) - 1985ee93961bSJeff Mahoney dc_size(B_N_CHILD(tb->FL[0], child_position)), 19861da177e4SLinus Torvalds "PAP-8290: invalid child size of left neighbor"); 19871da177e4SLinus Torvalds 1988ee93961bSJeff Mahoney brelse(tb->L[h]); 1989ee93961bSJeff Mahoney tb->L[h] = bh; 19901da177e4SLinus Torvalds } 19911da177e4SLinus Torvalds 1992ee93961bSJeff Mahoney /* We need right neighbor to balance S[path_offset]. */ 1993ee93961bSJeff Mahoney if (tb->rnum[h]) { /* We need right neighbor to balance S[path_offset]. */ 1994ee93961bSJeff Mahoney PROC_INFO_INC(sb, need_r_neighbor[h]); 1995ee93961bSJeff Mahoney bh = PATH_OFFSET_PBUFFER(tb->tb_path, path_offset); 19961da177e4SLinus Torvalds 1997ee93961bSJeff Mahoney RFALSE(bh == tb->FR[h] && 1998a063ae17SJeff Mahoney PATH_OFFSET_POSITION(tb->tb_path, 1999ee93961bSJeff Mahoney path_offset) >= 2000ad31a4fcSJeff Mahoney B_NR_ITEMS(bh), 20011da177e4SLinus Torvalds "PAP-8295: invalid position in the parent"); 20021da177e4SLinus Torvalds 2003ee93961bSJeff Mahoney child_position = 2004ee93961bSJeff Mahoney (bh == tb->FR[h]) ? tb->rkey[h] + 1 : 0; 2005ee93961bSJeff Mahoney son_number = B_N_CHILD_NUM(tb->FR[h], child_position); 2006ee93961bSJeff Mahoney bh = sb_bread(sb, son_number); 2007ad31a4fcSJeff Mahoney if (!bh) 20081da177e4SLinus Torvalds return IO_ERROR; 2009a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) { 2010ad31a4fcSJeff Mahoney brelse(bh); 2011ee93961bSJeff Mahoney PROC_INFO_INC(sb, get_neighbors_restart[h]); 20121da177e4SLinus Torvalds return REPEAT_SEARCH; 20131da177e4SLinus Torvalds } 2014ee93961bSJeff Mahoney brelse(tb->R[h]); 2015ee93961bSJeff Mahoney tb->R[h] = bh; 20161da177e4SLinus Torvalds 2017ee93961bSJeff Mahoney RFALSE(!h 2018ad31a4fcSJeff Mahoney && B_FREE_SPACE(bh) != 2019ad31a4fcSJeff Mahoney MAX_CHILD_SIZE(bh) - 2020ee93961bSJeff Mahoney dc_size(B_N_CHILD(tb->FR[0], child_position)), 20211da177e4SLinus Torvalds "PAP-8300: invalid child size of right neighbor (%d != %d - %d)", 2022ad31a4fcSJeff Mahoney B_FREE_SPACE(bh), MAX_CHILD_SIZE(bh), 2023ee93961bSJeff Mahoney dc_size(B_N_CHILD(tb->FR[0], child_position))); 20241da177e4SLinus Torvalds 20251da177e4SLinus Torvalds } 20261da177e4SLinus Torvalds return CARRY_ON; 20271da177e4SLinus Torvalds } 20281da177e4SLinus Torvalds 20291da177e4SLinus Torvalds static int get_virtual_node_size(struct super_block *sb, struct buffer_head *bh) 20301da177e4SLinus Torvalds { 20311da177e4SLinus Torvalds int max_num_of_items; 20321da177e4SLinus Torvalds int max_num_of_entries; 20331da177e4SLinus Torvalds unsigned long blocksize = sb->s_blocksize; 20341da177e4SLinus Torvalds 20351da177e4SLinus Torvalds #define MIN_NAME_LEN 1 20361da177e4SLinus Torvalds 20371da177e4SLinus Torvalds max_num_of_items = (blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN); 20381da177e4SLinus Torvalds max_num_of_entries = (blocksize - BLKH_SIZE - IH_SIZE) / 20391da177e4SLinus Torvalds (DEH_SIZE + MIN_NAME_LEN); 20401da177e4SLinus Torvalds 20411da177e4SLinus Torvalds return sizeof(struct virtual_node) + 20421da177e4SLinus Torvalds max(max_num_of_items * sizeof(struct virtual_item), 20431da177e4SLinus Torvalds sizeof(struct virtual_item) + sizeof(struct direntry_uarea) + 20441da177e4SLinus Torvalds (max_num_of_entries - 1) * sizeof(__u16)); 20451da177e4SLinus Torvalds } 20461da177e4SLinus Torvalds 20471da177e4SLinus Torvalds /* maybe we should fail balancing we are going to perform when kmalloc 20481da177e4SLinus Torvalds fails several times. But now it will loop until kmalloc gets 20491da177e4SLinus Torvalds required memory */ 20501da177e4SLinus Torvalds static int get_mem_for_virtual_node(struct tree_balance *tb) 20511da177e4SLinus Torvalds { 20521da177e4SLinus Torvalds int check_fs = 0; 20531da177e4SLinus Torvalds int size; 20541da177e4SLinus Torvalds char *buf; 20551da177e4SLinus Torvalds 20561da177e4SLinus Torvalds size = get_virtual_node_size(tb->tb_sb, PATH_PLAST_BUFFER(tb->tb_path)); 20571da177e4SLinus Torvalds 20581da177e4SLinus Torvalds if (size > tb->vn_buf_size) { 20591da177e4SLinus Torvalds /* we have to allocate more memory for virtual node */ 20601da177e4SLinus Torvalds if (tb->vn_buf) { 20611da177e4SLinus Torvalds /* free memory allocated before */ 2062d739b42bSPekka Enberg kfree(tb->vn_buf); 20631da177e4SLinus Torvalds /* this is not needed if kfree is atomic */ 20641da177e4SLinus Torvalds check_fs = 1; 20651da177e4SLinus Torvalds } 20661da177e4SLinus Torvalds 20671da177e4SLinus Torvalds /* virtual node requires now more memory */ 20681da177e4SLinus Torvalds tb->vn_buf_size = size; 20691da177e4SLinus Torvalds 20701da177e4SLinus Torvalds /* get memory for virtual item */ 2071d739b42bSPekka Enberg buf = kmalloc(size, GFP_ATOMIC | __GFP_NOWARN); 20721da177e4SLinus Torvalds if (!buf) { 20731da177e4SLinus Torvalds /* getting memory with GFP_KERNEL priority may involve 20741da177e4SLinus Torvalds balancing now (due to indirect_to_direct conversion on 20751da177e4SLinus Torvalds dcache shrinking). So, release path and collected 20761da177e4SLinus Torvalds resources here */ 20771da177e4SLinus Torvalds free_buffers_in_tb(tb); 2078d739b42bSPekka Enberg buf = kmalloc(size, GFP_NOFS); 20791da177e4SLinus Torvalds if (!buf) { 20801da177e4SLinus Torvalds tb->vn_buf_size = 0; 20811da177e4SLinus Torvalds } 20821da177e4SLinus Torvalds tb->vn_buf = buf; 20831da177e4SLinus Torvalds schedule(); 20841da177e4SLinus Torvalds return REPEAT_SEARCH; 20851da177e4SLinus Torvalds } 20861da177e4SLinus Torvalds 20871da177e4SLinus Torvalds tb->vn_buf = buf; 20881da177e4SLinus Torvalds } 20891da177e4SLinus Torvalds 20901da177e4SLinus Torvalds if (check_fs && FILESYSTEM_CHANGED_TB(tb)) 20911da177e4SLinus Torvalds return REPEAT_SEARCH; 20921da177e4SLinus Torvalds 20931da177e4SLinus Torvalds return CARRY_ON; 20941da177e4SLinus Torvalds } 20951da177e4SLinus Torvalds 20961da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK 2097a9dd3643SJeff Mahoney static void tb_buffer_sanity_check(struct super_block *sb, 2098ad31a4fcSJeff Mahoney struct buffer_head *bh, 2099bd4c625cSLinus Torvalds const char *descr, int level) 2100bd4c625cSLinus Torvalds { 2101ad31a4fcSJeff Mahoney if (bh) { 2102ad31a4fcSJeff Mahoney if (atomic_read(&(bh->b_count)) <= 0) 21031da177e4SLinus Torvalds 2104a9dd3643SJeff Mahoney reiserfs_panic(sb, "jmacd-1", "negative or zero " 2105c3a9c210SJeff Mahoney "reference counter for buffer %s[%d] " 2106ad31a4fcSJeff Mahoney "(%b)", descr, level, bh); 21071da177e4SLinus Torvalds 2108ad31a4fcSJeff Mahoney if (!buffer_uptodate(bh)) 2109a9dd3643SJeff Mahoney reiserfs_panic(sb, "jmacd-2", "buffer is not up " 2110c3a9c210SJeff Mahoney "to date %s[%d] (%b)", 2111ad31a4fcSJeff Mahoney descr, level, bh); 21121da177e4SLinus Torvalds 2113ad31a4fcSJeff Mahoney if (!B_IS_IN_TREE(bh)) 2114a9dd3643SJeff Mahoney reiserfs_panic(sb, "jmacd-3", "buffer is not " 2115c3a9c210SJeff Mahoney "in tree %s[%d] (%b)", 2116ad31a4fcSJeff Mahoney descr, level, bh); 21171da177e4SLinus Torvalds 2118ad31a4fcSJeff Mahoney if (bh->b_bdev != sb->s_bdev) 2119a9dd3643SJeff Mahoney reiserfs_panic(sb, "jmacd-4", "buffer has wrong " 2120c3a9c210SJeff Mahoney "device %s[%d] (%b)", 2121ad31a4fcSJeff Mahoney descr, level, bh); 21221da177e4SLinus Torvalds 2123ad31a4fcSJeff Mahoney if (bh->b_size != sb->s_blocksize) 2124a9dd3643SJeff Mahoney reiserfs_panic(sb, "jmacd-5", "buffer has wrong " 2125c3a9c210SJeff Mahoney "blocksize %s[%d] (%b)", 2126ad31a4fcSJeff Mahoney descr, level, bh); 21271da177e4SLinus Torvalds 2128ad31a4fcSJeff Mahoney if (bh->b_blocknr > SB_BLOCK_COUNT(sb)) 2129a9dd3643SJeff Mahoney reiserfs_panic(sb, "jmacd-6", "buffer block " 2130c3a9c210SJeff Mahoney "number too high %s[%d] (%b)", 2131ad31a4fcSJeff Mahoney descr, level, bh); 21321da177e4SLinus Torvalds } 21331da177e4SLinus Torvalds } 21341da177e4SLinus Torvalds #else 2135a9dd3643SJeff Mahoney static void tb_buffer_sanity_check(struct super_block *sb, 2136ad31a4fcSJeff Mahoney struct buffer_head *bh, 21371da177e4SLinus Torvalds const char *descr, int level) 2138bd4c625cSLinus Torvalds {; 2139bd4c625cSLinus Torvalds } 21401da177e4SLinus Torvalds #endif 21411da177e4SLinus Torvalds 2142bd4c625cSLinus Torvalds static int clear_all_dirty_bits(struct super_block *s, struct buffer_head *bh) 2143bd4c625cSLinus Torvalds { 21441da177e4SLinus Torvalds return reiserfs_prepare_for_journal(s, bh, 0); 21451da177e4SLinus Torvalds } 21461da177e4SLinus Torvalds 2147a063ae17SJeff Mahoney static int wait_tb_buffers_until_unlocked(struct tree_balance *tb) 21481da177e4SLinus Torvalds { 21491da177e4SLinus Torvalds struct buffer_head *locked; 21501da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK 21511da177e4SLinus Torvalds int repeat_counter = 0; 21521da177e4SLinus Torvalds #endif 21531da177e4SLinus Torvalds int i; 21541da177e4SLinus Torvalds 21551da177e4SLinus Torvalds do { 21561da177e4SLinus Torvalds 21571da177e4SLinus Torvalds locked = NULL; 21581da177e4SLinus Torvalds 2159a063ae17SJeff Mahoney for (i = tb->tb_path->path_length; 2160bd4c625cSLinus Torvalds !locked && i > ILLEGAL_PATH_ELEMENT_OFFSET; i--) { 2161a063ae17SJeff Mahoney if (PATH_OFFSET_PBUFFER(tb->tb_path, i)) { 21621da177e4SLinus Torvalds /* if I understand correctly, we can only be sure the last buffer 21631da177e4SLinus Torvalds ** in the path is in the tree --clm 21641da177e4SLinus Torvalds */ 21651da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK 2166a063ae17SJeff Mahoney if (PATH_PLAST_BUFFER(tb->tb_path) == 2167a063ae17SJeff Mahoney PATH_OFFSET_PBUFFER(tb->tb_path, i)) 2168a063ae17SJeff Mahoney tb_buffer_sanity_check(tb->tb_sb, 2169bd4c625cSLinus Torvalds PATH_OFFSET_PBUFFER 2170a063ae17SJeff Mahoney (tb->tb_path, 2171bd4c625cSLinus Torvalds i), "S", 2172a063ae17SJeff Mahoney tb->tb_path-> 2173bd4c625cSLinus Torvalds path_length - i); 21741da177e4SLinus Torvalds #endif 2175a063ae17SJeff Mahoney if (!clear_all_dirty_bits(tb->tb_sb, 2176bd4c625cSLinus Torvalds PATH_OFFSET_PBUFFER 2177a063ae17SJeff Mahoney (tb->tb_path, 2178bd4c625cSLinus Torvalds i))) { 2179bd4c625cSLinus Torvalds locked = 2180a063ae17SJeff Mahoney PATH_OFFSET_PBUFFER(tb->tb_path, 2181bd4c625cSLinus Torvalds i); 21821da177e4SLinus Torvalds } 21831da177e4SLinus Torvalds } 21841da177e4SLinus Torvalds } 21851da177e4SLinus Torvalds 2186a063ae17SJeff Mahoney for (i = 0; !locked && i < MAX_HEIGHT && tb->insert_size[i]; 2187bd4c625cSLinus Torvalds i++) { 21881da177e4SLinus Torvalds 2189a063ae17SJeff Mahoney if (tb->lnum[i]) { 21901da177e4SLinus Torvalds 2191a063ae17SJeff Mahoney if (tb->L[i]) { 2192a063ae17SJeff Mahoney tb_buffer_sanity_check(tb->tb_sb, 2193a063ae17SJeff Mahoney tb->L[i], 2194bd4c625cSLinus Torvalds "L", i); 2195bd4c625cSLinus Torvalds if (!clear_all_dirty_bits 2196a063ae17SJeff Mahoney (tb->tb_sb, tb->L[i])) 2197a063ae17SJeff Mahoney locked = tb->L[i]; 21981da177e4SLinus Torvalds } 21991da177e4SLinus Torvalds 2200a063ae17SJeff Mahoney if (!locked && tb->FL[i]) { 2201a063ae17SJeff Mahoney tb_buffer_sanity_check(tb->tb_sb, 2202a063ae17SJeff Mahoney tb->FL[i], 2203bd4c625cSLinus Torvalds "FL", i); 2204bd4c625cSLinus Torvalds if (!clear_all_dirty_bits 2205a063ae17SJeff Mahoney (tb->tb_sb, tb->FL[i])) 2206a063ae17SJeff Mahoney locked = tb->FL[i]; 22071da177e4SLinus Torvalds } 22081da177e4SLinus Torvalds 2209a063ae17SJeff Mahoney if (!locked && tb->CFL[i]) { 2210a063ae17SJeff Mahoney tb_buffer_sanity_check(tb->tb_sb, 2211a063ae17SJeff Mahoney tb->CFL[i], 2212bd4c625cSLinus Torvalds "CFL", i); 2213bd4c625cSLinus Torvalds if (!clear_all_dirty_bits 2214a063ae17SJeff Mahoney (tb->tb_sb, tb->CFL[i])) 2215a063ae17SJeff Mahoney locked = tb->CFL[i]; 22161da177e4SLinus Torvalds } 22171da177e4SLinus Torvalds 22181da177e4SLinus Torvalds } 22191da177e4SLinus Torvalds 2220a063ae17SJeff Mahoney if (!locked && (tb->rnum[i])) { 22211da177e4SLinus Torvalds 2222a063ae17SJeff Mahoney if (tb->R[i]) { 2223a063ae17SJeff Mahoney tb_buffer_sanity_check(tb->tb_sb, 2224a063ae17SJeff Mahoney tb->R[i], 2225bd4c625cSLinus Torvalds "R", i); 2226bd4c625cSLinus Torvalds if (!clear_all_dirty_bits 2227a063ae17SJeff Mahoney (tb->tb_sb, tb->R[i])) 2228a063ae17SJeff Mahoney locked = tb->R[i]; 22291da177e4SLinus Torvalds } 22301da177e4SLinus Torvalds 2231a063ae17SJeff Mahoney if (!locked && tb->FR[i]) { 2232a063ae17SJeff Mahoney tb_buffer_sanity_check(tb->tb_sb, 2233a063ae17SJeff Mahoney tb->FR[i], 2234bd4c625cSLinus Torvalds "FR", i); 2235bd4c625cSLinus Torvalds if (!clear_all_dirty_bits 2236a063ae17SJeff Mahoney (tb->tb_sb, tb->FR[i])) 2237a063ae17SJeff Mahoney locked = tb->FR[i]; 22381da177e4SLinus Torvalds } 22391da177e4SLinus Torvalds 2240a063ae17SJeff Mahoney if (!locked && tb->CFR[i]) { 2241a063ae17SJeff Mahoney tb_buffer_sanity_check(tb->tb_sb, 2242a063ae17SJeff Mahoney tb->CFR[i], 2243bd4c625cSLinus Torvalds "CFR", i); 2244bd4c625cSLinus Torvalds if (!clear_all_dirty_bits 2245a063ae17SJeff Mahoney (tb->tb_sb, tb->CFR[i])) 2246a063ae17SJeff Mahoney locked = tb->CFR[i]; 22471da177e4SLinus Torvalds } 22481da177e4SLinus Torvalds } 22491da177e4SLinus Torvalds } 22501da177e4SLinus Torvalds /* as far as I can tell, this is not required. The FEB list seems 22511da177e4SLinus Torvalds ** to be full of newly allocated nodes, which will never be locked, 22521da177e4SLinus Torvalds ** dirty, or anything else. 22531da177e4SLinus Torvalds ** To be safe, I'm putting in the checks and waits in. For the moment, 22541da177e4SLinus Torvalds ** they are needed to keep the code in journal.c from complaining 22551da177e4SLinus Torvalds ** about the buffer. That code is inside CONFIG_REISERFS_CHECK as well. 22561da177e4SLinus Torvalds ** --clm 22571da177e4SLinus Torvalds */ 22581da177e4SLinus Torvalds for (i = 0; !locked && i < MAX_FEB_SIZE; i++) { 2259a063ae17SJeff Mahoney if (tb->FEB[i]) { 2260bd4c625cSLinus Torvalds if (!clear_all_dirty_bits 2261a063ae17SJeff Mahoney (tb->tb_sb, tb->FEB[i])) 2262a063ae17SJeff Mahoney locked = tb->FEB[i]; 22631da177e4SLinus Torvalds } 22641da177e4SLinus Torvalds } 22651da177e4SLinus Torvalds 22661da177e4SLinus Torvalds if (locked) { 22671da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK 22681da177e4SLinus Torvalds repeat_counter++; 22691da177e4SLinus Torvalds if ((repeat_counter % 10000) == 0) { 2270a063ae17SJeff Mahoney reiserfs_warning(tb->tb_sb, "reiserfs-8200", 227145b03d5eSJeff Mahoney "too many iterations waiting " 227245b03d5eSJeff Mahoney "for buffer to unlock " 22731da177e4SLinus Torvalds "(%b)", locked); 22741da177e4SLinus Torvalds 22751da177e4SLinus Torvalds /* Don't loop forever. Try to recover from possible error. */ 22761da177e4SLinus Torvalds 2277a063ae17SJeff Mahoney return (FILESYSTEM_CHANGED_TB(tb)) ? 2278bd4c625cSLinus Torvalds REPEAT_SEARCH : CARRY_ON; 22791da177e4SLinus Torvalds } 22801da177e4SLinus Torvalds #endif 22811da177e4SLinus Torvalds __wait_on_buffer(locked); 2282a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) 22831da177e4SLinus Torvalds return REPEAT_SEARCH; 22841da177e4SLinus Torvalds } 22851da177e4SLinus Torvalds 22861da177e4SLinus Torvalds } while (locked); 22871da177e4SLinus Torvalds 22881da177e4SLinus Torvalds return CARRY_ON; 22891da177e4SLinus Torvalds } 22901da177e4SLinus Torvalds 22911da177e4SLinus Torvalds /* Prepare for balancing, that is 22921da177e4SLinus Torvalds * get all necessary parents, and neighbors; 22931da177e4SLinus Torvalds * analyze what and where should be moved; 22941da177e4SLinus Torvalds * get sufficient number of new nodes; 22951da177e4SLinus Torvalds * Balancing will start only after all resources will be collected at a time. 22961da177e4SLinus Torvalds * 22971da177e4SLinus Torvalds * When ported to SMP kernels, only at the last moment after all needed nodes 22981da177e4SLinus Torvalds * are collected in cache, will the resources be locked using the usual 22991da177e4SLinus Torvalds * textbook ordered lock acquisition algorithms. Note that ensuring that 23001da177e4SLinus Torvalds * this code neither write locks what it does not need to write lock nor locks out of order 23011da177e4SLinus Torvalds * will be a pain in the butt that could have been avoided. Grumble grumble. -Hans 23021da177e4SLinus Torvalds * 23031da177e4SLinus Torvalds * fix is meant in the sense of render unchanging 23041da177e4SLinus Torvalds * 23051da177e4SLinus Torvalds * Latency might be improved by first gathering a list of what buffers are needed 23061da177e4SLinus Torvalds * and then getting as many of them in parallel as possible? -Hans 23071da177e4SLinus Torvalds * 23081da177e4SLinus Torvalds * Parameters: 23091da177e4SLinus Torvalds * op_mode i - insert, d - delete, c - cut (truncate), p - paste (append) 23101da177e4SLinus Torvalds * tb tree_balance structure; 23111da177e4SLinus Torvalds * inum item number in S[h]; 23121da177e4SLinus Torvalds * pos_in_item - comment this if you can 2313a063ae17SJeff Mahoney * ins_ih item head of item being inserted 2314a063ae17SJeff Mahoney * data inserted item or data to be pasted 23151da177e4SLinus Torvalds * Returns: 1 - schedule occurred while the function worked; 23161da177e4SLinus Torvalds * 0 - schedule didn't occur while the function worked; 23171da177e4SLinus Torvalds * -1 - if no_disk_space 23181da177e4SLinus Torvalds */ 23191da177e4SLinus Torvalds 2320ee93961bSJeff Mahoney int fix_nodes(int op_mode, struct tree_balance *tb, 2321d68caa95SJeff Mahoney struct item_head *ins_ih, const void *data) 2322bd4c625cSLinus Torvalds { 2323ee93961bSJeff Mahoney int ret, h, item_num = PATH_LAST_POSITION(tb->tb_path); 2324ee93961bSJeff Mahoney int pos_in_item; 23251da177e4SLinus Torvalds 23261da177e4SLinus Torvalds /* we set wait_tb_buffers_run when we have to restore any dirty bits cleared 23271da177e4SLinus Torvalds ** during wait_tb_buffers_run 23281da177e4SLinus Torvalds */ 23291da177e4SLinus Torvalds int wait_tb_buffers_run = 0; 2330a063ae17SJeff Mahoney struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path); 23311da177e4SLinus Torvalds 2332a063ae17SJeff Mahoney ++REISERFS_SB(tb->tb_sb)->s_fix_nodes; 23331da177e4SLinus Torvalds 2334ee93961bSJeff Mahoney pos_in_item = tb->tb_path->pos_in_item; 23351da177e4SLinus Torvalds 2336a063ae17SJeff Mahoney tb->fs_gen = get_generation(tb->tb_sb); 23371da177e4SLinus Torvalds 23381da177e4SLinus Torvalds /* we prepare and log the super here so it will already be in the 23391da177e4SLinus Torvalds ** transaction when do_balance needs to change it. 23401da177e4SLinus Torvalds ** This way do_balance won't have to schedule when trying to prepare 23411da177e4SLinus Torvalds ** the super for logging 23421da177e4SLinus Torvalds */ 2343a063ae17SJeff Mahoney reiserfs_prepare_for_journal(tb->tb_sb, 2344a063ae17SJeff Mahoney SB_BUFFER_WITH_SB(tb->tb_sb), 1); 2345a063ae17SJeff Mahoney journal_mark_dirty(tb->transaction_handle, tb->tb_sb, 2346a063ae17SJeff Mahoney SB_BUFFER_WITH_SB(tb->tb_sb)); 2347a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) 23481da177e4SLinus Torvalds return REPEAT_SEARCH; 23491da177e4SLinus Torvalds 23501da177e4SLinus Torvalds /* if it possible in indirect_to_direct conversion */ 2351a063ae17SJeff Mahoney if (buffer_locked(tbS0)) { 2352a063ae17SJeff Mahoney __wait_on_buffer(tbS0); 2353a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) 23541da177e4SLinus Torvalds return REPEAT_SEARCH; 23551da177e4SLinus Torvalds } 23561da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK 23571da177e4SLinus Torvalds if (cur_tb) { 23581da177e4SLinus Torvalds print_cur_tb("fix_nodes"); 2359a063ae17SJeff Mahoney reiserfs_panic(tb->tb_sb, "PAP-8305", 2360c3a9c210SJeff Mahoney "there is pending do_balance"); 23611da177e4SLinus Torvalds } 23621da177e4SLinus Torvalds 2363a063ae17SJeff Mahoney if (!buffer_uptodate(tbS0) || !B_IS_IN_TREE(tbS0)) 2364a063ae17SJeff Mahoney reiserfs_panic(tb->tb_sb, "PAP-8320", "S[0] (%b %z) is " 2365c3a9c210SJeff Mahoney "not uptodate at the beginning of fix_nodes " 2366c3a9c210SJeff Mahoney "or not in tree (mode %c)", 2367ee93961bSJeff Mahoney tbS0, tbS0, op_mode); 23681da177e4SLinus Torvalds 23691da177e4SLinus Torvalds /* Check parameters. */ 2370ee93961bSJeff Mahoney switch (op_mode) { 23711da177e4SLinus Torvalds case M_INSERT: 2372ee93961bSJeff Mahoney if (item_num <= 0 || item_num > B_NR_ITEMS(tbS0)) 2373a063ae17SJeff Mahoney reiserfs_panic(tb->tb_sb, "PAP-8330", "Incorrect " 2374c3a9c210SJeff Mahoney "item number %d (in S0 - %d) in case " 2375ee93961bSJeff Mahoney "of insert", item_num, 2376a063ae17SJeff Mahoney B_NR_ITEMS(tbS0)); 23771da177e4SLinus Torvalds break; 23781da177e4SLinus Torvalds case M_PASTE: 23791da177e4SLinus Torvalds case M_DELETE: 23801da177e4SLinus Torvalds case M_CUT: 2381ee93961bSJeff Mahoney if (item_num < 0 || item_num >= B_NR_ITEMS(tbS0)) { 2382a063ae17SJeff Mahoney print_block(tbS0, 0, -1, -1); 2383a063ae17SJeff Mahoney reiserfs_panic(tb->tb_sb, "PAP-8335", "Incorrect " 2384c3a9c210SJeff Mahoney "item number(%d); mode = %c " 2385c3a9c210SJeff Mahoney "insert_size = %d", 2386ee93961bSJeff Mahoney item_num, op_mode, 2387a063ae17SJeff Mahoney tb->insert_size[0]); 23881da177e4SLinus Torvalds } 23891da177e4SLinus Torvalds break; 23901da177e4SLinus Torvalds default: 2391a063ae17SJeff Mahoney reiserfs_panic(tb->tb_sb, "PAP-8340", "Incorrect mode " 2392c3a9c210SJeff Mahoney "of operation"); 23931da177e4SLinus Torvalds } 23941da177e4SLinus Torvalds #endif 23951da177e4SLinus Torvalds 2396a063ae17SJeff Mahoney if (get_mem_for_virtual_node(tb) == REPEAT_SEARCH) 23971da177e4SLinus Torvalds // FIXME: maybe -ENOMEM when tb->vn_buf == 0? Now just repeat 23981da177e4SLinus Torvalds return REPEAT_SEARCH; 23991da177e4SLinus Torvalds 2400ee93961bSJeff Mahoney /* Starting from the leaf level; for all levels h of the tree. */ 2401ee93961bSJeff Mahoney for (h = 0; h < MAX_HEIGHT && tb->insert_size[h]; h++) { 2402ee93961bSJeff Mahoney ret = get_direct_parent(tb, h); 2403ee93961bSJeff Mahoney if (ret != CARRY_ON) 24041da177e4SLinus Torvalds goto repeat; 24051da177e4SLinus Torvalds 2406ee93961bSJeff Mahoney ret = check_balance(op_mode, tb, h, item_num, 2407ee93961bSJeff Mahoney pos_in_item, ins_ih, data); 2408ee93961bSJeff Mahoney if (ret != CARRY_ON) { 2409ee93961bSJeff Mahoney if (ret == NO_BALANCING_NEEDED) { 24101da177e4SLinus Torvalds /* No balancing for higher levels needed. */ 2411ee93961bSJeff Mahoney ret = get_neighbors(tb, h); 2412ee93961bSJeff Mahoney if (ret != CARRY_ON) 24131da177e4SLinus Torvalds goto repeat; 2414ee93961bSJeff Mahoney if (h != MAX_HEIGHT - 1) 2415ee93961bSJeff Mahoney tb->insert_size[h + 1] = 0; 24161da177e4SLinus Torvalds /* ok, analysis and resource gathering are complete */ 24171da177e4SLinus Torvalds break; 24181da177e4SLinus Torvalds } 24191da177e4SLinus Torvalds goto repeat; 24201da177e4SLinus Torvalds } 24211da177e4SLinus Torvalds 2422ee93961bSJeff Mahoney ret = get_neighbors(tb, h); 2423ee93961bSJeff Mahoney if (ret != CARRY_ON) 24241da177e4SLinus Torvalds goto repeat; 24251da177e4SLinus Torvalds 2426a063ae17SJeff Mahoney /* No disk space, or schedule occurred and analysis may be 2427a063ae17SJeff Mahoney * invalid and needs to be redone. */ 2428ee93961bSJeff Mahoney ret = get_empty_nodes(tb, h); 2429ee93961bSJeff Mahoney if (ret != CARRY_ON) 2430a063ae17SJeff Mahoney goto repeat; 24311da177e4SLinus Torvalds 2432ee93961bSJeff Mahoney if (!PATH_H_PBUFFER(tb->tb_path, h)) { 24331da177e4SLinus Torvalds /* We have a positive insert size but no nodes exist on this 24341da177e4SLinus Torvalds level, this means that we are creating a new root. */ 24351da177e4SLinus Torvalds 2436ee93961bSJeff Mahoney RFALSE(tb->blknum[h] != 1, 24371da177e4SLinus Torvalds "PAP-8350: creating new empty root"); 24381da177e4SLinus Torvalds 2439ee93961bSJeff Mahoney if (h < MAX_HEIGHT - 1) 2440ee93961bSJeff Mahoney tb->insert_size[h + 1] = 0; 2441ee93961bSJeff Mahoney } else if (!PATH_H_PBUFFER(tb->tb_path, h + 1)) { 2442ee93961bSJeff Mahoney if (tb->blknum[h] > 1) { 2443ee93961bSJeff Mahoney /* The tree needs to be grown, so this node S[h] 24441da177e4SLinus Torvalds which is the root node is split into two nodes, 2445ee93961bSJeff Mahoney and a new node (S[h+1]) will be created to 24461da177e4SLinus Torvalds become the root node. */ 24471da177e4SLinus Torvalds 2448ee93961bSJeff Mahoney RFALSE(h == MAX_HEIGHT - 1, 24491da177e4SLinus Torvalds "PAP-8355: attempt to create too high of a tree"); 24501da177e4SLinus Torvalds 2451ee93961bSJeff Mahoney tb->insert_size[h + 1] = 2452bd4c625cSLinus Torvalds (DC_SIZE + 2453ee93961bSJeff Mahoney KEY_SIZE) * (tb->blknum[h] - 1) + 2454bd4c625cSLinus Torvalds DC_SIZE; 2455ee93961bSJeff Mahoney } else if (h < MAX_HEIGHT - 1) 2456ee93961bSJeff Mahoney tb->insert_size[h + 1] = 0; 2457bd4c625cSLinus Torvalds } else 2458ee93961bSJeff Mahoney tb->insert_size[h + 1] = 2459ee93961bSJeff Mahoney (DC_SIZE + KEY_SIZE) * (tb->blknum[h] - 1); 24601da177e4SLinus Torvalds } 24611da177e4SLinus Torvalds 2462ee93961bSJeff Mahoney ret = wait_tb_buffers_until_unlocked(tb); 2463ee93961bSJeff Mahoney if (ret == CARRY_ON) { 2464a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) { 24651da177e4SLinus Torvalds wait_tb_buffers_run = 1; 2466ee93961bSJeff Mahoney ret = REPEAT_SEARCH; 24671da177e4SLinus Torvalds goto repeat; 24681da177e4SLinus Torvalds } else { 24691da177e4SLinus Torvalds return CARRY_ON; 24701da177e4SLinus Torvalds } 24711da177e4SLinus Torvalds } else { 24721da177e4SLinus Torvalds wait_tb_buffers_run = 1; 24731da177e4SLinus Torvalds goto repeat; 24741da177e4SLinus Torvalds } 24751da177e4SLinus Torvalds 24761da177e4SLinus Torvalds repeat: 24771da177e4SLinus Torvalds // fix_nodes was unable to perform its calculation due to 24781da177e4SLinus Torvalds // filesystem got changed under us, lack of free disk space or i/o 24791da177e4SLinus Torvalds // failure. If the first is the case - the search will be 24801da177e4SLinus Torvalds // repeated. For now - free all resources acquired so far except 24811da177e4SLinus Torvalds // for the new allocated nodes 24821da177e4SLinus Torvalds { 24831da177e4SLinus Torvalds int i; 24841da177e4SLinus Torvalds 24851da177e4SLinus Torvalds /* Release path buffers. */ 24861da177e4SLinus Torvalds if (wait_tb_buffers_run) { 2487a063ae17SJeff Mahoney pathrelse_and_restore(tb->tb_sb, tb->tb_path); 24881da177e4SLinus Torvalds } else { 2489a063ae17SJeff Mahoney pathrelse(tb->tb_path); 24901da177e4SLinus Torvalds } 24911da177e4SLinus Torvalds /* brelse all resources collected for balancing */ 24921da177e4SLinus Torvalds for (i = 0; i < MAX_HEIGHT; i++) { 24931da177e4SLinus Torvalds if (wait_tb_buffers_run) { 2494a063ae17SJeff Mahoney reiserfs_restore_prepared_buffer(tb->tb_sb, 2495a063ae17SJeff Mahoney tb->L[i]); 2496a063ae17SJeff Mahoney reiserfs_restore_prepared_buffer(tb->tb_sb, 2497a063ae17SJeff Mahoney tb->R[i]); 2498a063ae17SJeff Mahoney reiserfs_restore_prepared_buffer(tb->tb_sb, 2499a063ae17SJeff Mahoney tb->FL[i]); 2500a063ae17SJeff Mahoney reiserfs_restore_prepared_buffer(tb->tb_sb, 2501a063ae17SJeff Mahoney tb->FR[i]); 2502a063ae17SJeff Mahoney reiserfs_restore_prepared_buffer(tb->tb_sb, 2503a063ae17SJeff Mahoney tb-> 2504bd4c625cSLinus Torvalds CFL[i]); 2505a063ae17SJeff Mahoney reiserfs_restore_prepared_buffer(tb->tb_sb, 2506a063ae17SJeff Mahoney tb-> 2507bd4c625cSLinus Torvalds CFR[i]); 25081da177e4SLinus Torvalds } 25091da177e4SLinus Torvalds 2510a063ae17SJeff Mahoney brelse(tb->L[i]); 2511a063ae17SJeff Mahoney brelse(tb->R[i]); 2512a063ae17SJeff Mahoney brelse(tb->FL[i]); 2513a063ae17SJeff Mahoney brelse(tb->FR[i]); 2514a063ae17SJeff Mahoney brelse(tb->CFL[i]); 2515a063ae17SJeff Mahoney brelse(tb->CFR[i]); 25163cd6dbe6SJeff Mahoney 2517a063ae17SJeff Mahoney tb->L[i] = NULL; 2518a063ae17SJeff Mahoney tb->R[i] = NULL; 2519a063ae17SJeff Mahoney tb->FL[i] = NULL; 2520a063ae17SJeff Mahoney tb->FR[i] = NULL; 2521a063ae17SJeff Mahoney tb->CFL[i] = NULL; 2522a063ae17SJeff Mahoney tb->CFR[i] = NULL; 25231da177e4SLinus Torvalds } 25241da177e4SLinus Torvalds 25251da177e4SLinus Torvalds if (wait_tb_buffers_run) { 25261da177e4SLinus Torvalds for (i = 0; i < MAX_FEB_SIZE; i++) { 2527a063ae17SJeff Mahoney if (tb->FEB[i]) 2528bd4c625cSLinus Torvalds reiserfs_restore_prepared_buffer 2529a063ae17SJeff Mahoney (tb->tb_sb, tb->FEB[i]); 25301da177e4SLinus Torvalds } 25311da177e4SLinus Torvalds } 2532ee93961bSJeff Mahoney return ret; 25331da177e4SLinus Torvalds } 25341da177e4SLinus Torvalds 25351da177e4SLinus Torvalds } 25361da177e4SLinus Torvalds 2537a063ae17SJeff Mahoney /* Anatoly will probably forgive me renaming tb to tb. I just 25381da177e4SLinus Torvalds wanted to make lines shorter */ 25391da177e4SLinus Torvalds void unfix_nodes(struct tree_balance *tb) 25401da177e4SLinus Torvalds { 25411da177e4SLinus Torvalds int i; 25421da177e4SLinus Torvalds 25431da177e4SLinus Torvalds /* Release path buffers. */ 25441da177e4SLinus Torvalds pathrelse_and_restore(tb->tb_sb, tb->tb_path); 25451da177e4SLinus Torvalds 25461da177e4SLinus Torvalds /* brelse all resources collected for balancing */ 25471da177e4SLinus Torvalds for (i = 0; i < MAX_HEIGHT; i++) { 25481da177e4SLinus Torvalds reiserfs_restore_prepared_buffer(tb->tb_sb, tb->L[i]); 25491da177e4SLinus Torvalds reiserfs_restore_prepared_buffer(tb->tb_sb, tb->R[i]); 25501da177e4SLinus Torvalds reiserfs_restore_prepared_buffer(tb->tb_sb, tb->FL[i]); 25511da177e4SLinus Torvalds reiserfs_restore_prepared_buffer(tb->tb_sb, tb->FR[i]); 25521da177e4SLinus Torvalds reiserfs_restore_prepared_buffer(tb->tb_sb, tb->CFL[i]); 25531da177e4SLinus Torvalds reiserfs_restore_prepared_buffer(tb->tb_sb, tb->CFR[i]); 25541da177e4SLinus Torvalds 25551da177e4SLinus Torvalds brelse(tb->L[i]); 25561da177e4SLinus Torvalds brelse(tb->R[i]); 25571da177e4SLinus Torvalds brelse(tb->FL[i]); 25581da177e4SLinus Torvalds brelse(tb->FR[i]); 25591da177e4SLinus Torvalds brelse(tb->CFL[i]); 25601da177e4SLinus Torvalds brelse(tb->CFR[i]); 25611da177e4SLinus Torvalds } 25621da177e4SLinus Torvalds 25631da177e4SLinus Torvalds /* deal with list of allocated (used and unused) nodes */ 25641da177e4SLinus Torvalds for (i = 0; i < MAX_FEB_SIZE; i++) { 25651da177e4SLinus Torvalds if (tb->FEB[i]) { 25661da177e4SLinus Torvalds b_blocknr_t blocknr = tb->FEB[i]->b_blocknr; 25671da177e4SLinus Torvalds /* de-allocated block which was not used by balancing and 25681da177e4SLinus Torvalds bforget about buffer for it */ 25691da177e4SLinus Torvalds brelse(tb->FEB[i]); 2570bd4c625cSLinus Torvalds reiserfs_free_block(tb->transaction_handle, NULL, 2571bd4c625cSLinus Torvalds blocknr, 0); 25721da177e4SLinus Torvalds } 25731da177e4SLinus Torvalds if (tb->used[i]) { 25741da177e4SLinus Torvalds /* release used as new nodes including a new root */ 25751da177e4SLinus Torvalds brelse(tb->used[i]); 25761da177e4SLinus Torvalds } 25771da177e4SLinus Torvalds } 25781da177e4SLinus Torvalds 2579d739b42bSPekka Enberg kfree(tb->vn_buf); 25801da177e4SLinus Torvalds 25811da177e4SLinus Torvalds } 2582