11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README 31da177e4SLinus Torvalds */ 41da177e4SLinus Torvalds 51da177e4SLinus Torvalds #include <linux/time.h> 65a0e3ad6STejun Heo #include <linux/slab.h> 71da177e4SLinus Torvalds #include <linux/string.h> 8f466c6fdSAl Viro #include "reiserfs.h" 91da177e4SLinus Torvalds #include <linux/buffer_head.h> 101da177e4SLinus Torvalds 11098297b2SJeff Mahoney /* 12098297b2SJeff Mahoney * To make any changes in the tree we find a node that contains item 13098297b2SJeff Mahoney * to be changed/deleted or position in the node we insert a new item 14098297b2SJeff Mahoney * to. We call this node S. To do balancing we need to decide what we 15098297b2SJeff Mahoney * will shift to left/right neighbor, or to a new node, where new item 16098297b2SJeff Mahoney * will be etc. To make this analysis simpler we build virtual 17098297b2SJeff Mahoney * node. Virtual node is an array of items, that will replace items of 18098297b2SJeff Mahoney * node S. (For instance if we are going to delete an item, virtual 19098297b2SJeff Mahoney * node does not contain it). Virtual node keeps information about 20098297b2SJeff Mahoney * item sizes and types, mergeability of first and last items, sizes 21098297b2SJeff Mahoney * of all entries in directory item. We use this array of items when 22098297b2SJeff Mahoney * calculating what we can shift to neighbors and how many nodes we 23098297b2SJeff Mahoney * have to have if we do not any shiftings, if we shift to left/right 24098297b2SJeff Mahoney * neighbor or to both. 25098297b2SJeff Mahoney */ 261da177e4SLinus Torvalds 27098297b2SJeff Mahoney /* 28098297b2SJeff Mahoney * Takes item number in virtual node, returns number of item 29098297b2SJeff Mahoney * that it has in source buffer 30098297b2SJeff Mahoney */ 311da177e4SLinus Torvalds static inline int old_item_num(int new_num, int affected_item_num, int mode) 321da177e4SLinus Torvalds { 331da177e4SLinus Torvalds if (mode == M_PASTE || mode == M_CUT || new_num < affected_item_num) 341da177e4SLinus Torvalds return new_num; 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds if (mode == M_INSERT) { 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds RFALSE(new_num == 0, 391da177e4SLinus Torvalds "vs-8005: for INSERT mode and item number of inserted item"); 401da177e4SLinus Torvalds 411da177e4SLinus Torvalds return new_num - 1; 421da177e4SLinus Torvalds } 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds RFALSE(mode != M_DELETE, 45bd4c625cSLinus Torvalds "vs-8010: old_item_num: mode must be M_DELETE (mode = \'%c\'", 46bd4c625cSLinus Torvalds mode); 471da177e4SLinus Torvalds /* delete mode */ 481da177e4SLinus Torvalds return new_num + 1; 491da177e4SLinus Torvalds } 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds static void create_virtual_node(struct tree_balance *tb, int h) 521da177e4SLinus Torvalds { 531da177e4SLinus Torvalds struct item_head *ih; 541da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 551da177e4SLinus Torvalds int new_num; 561da177e4SLinus Torvalds struct buffer_head *Sh; /* this comes from tb->S[h] */ 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds Sh = PATH_H_PBUFFER(tb->tb_path, h); 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds /* size of changed node */ 61bd4c625cSLinus Torvalds vn->vn_size = 62bd4c625cSLinus Torvalds MAX_CHILD_SIZE(Sh) - B_FREE_SPACE(Sh) + tb->insert_size[h]; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds /* for internal nodes array if virtual items is not created */ 651da177e4SLinus Torvalds if (h) { 661da177e4SLinus Torvalds vn->vn_nr_item = (vn->vn_size - DC_SIZE) / (DC_SIZE + KEY_SIZE); 671da177e4SLinus Torvalds return; 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds /* number of items in virtual node */ 71bd4c625cSLinus Torvalds vn->vn_nr_item = 72bd4c625cSLinus Torvalds B_NR_ITEMS(Sh) + ((vn->vn_mode == M_INSERT) ? 1 : 0) - 73bd4c625cSLinus Torvalds ((vn->vn_mode == M_DELETE) ? 1 : 0); 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds /* first virtual item */ 761da177e4SLinus Torvalds vn->vn_vi = (struct virtual_item *)(tb->tb_vn + 1); 771da177e4SLinus Torvalds memset(vn->vn_vi, 0, vn->vn_nr_item * sizeof(struct virtual_item)); 781da177e4SLinus Torvalds vn->vn_free_ptr += vn->vn_nr_item * sizeof(struct virtual_item); 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds /* first item in the node */ 814cf5f7adSJeff Mahoney ih = item_head(Sh, 0); 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds /* define the mergeability for 0-th item (if it is not being deleted) */ 84bd4c625cSLinus Torvalds if (op_is_left_mergeable(&(ih->ih_key), Sh->b_size) 85bd4c625cSLinus Torvalds && (vn->vn_mode != M_DELETE || vn->vn_affected_item_num)) 861da177e4SLinus Torvalds vn->vn_vi[0].vi_type |= VI_TYPE_LEFT_MERGEABLE; 871da177e4SLinus Torvalds 88098297b2SJeff Mahoney /* 89098297b2SJeff Mahoney * go through all items that remain in the virtual 90098297b2SJeff Mahoney * node (except for the new (inserted) one) 91098297b2SJeff Mahoney */ 921da177e4SLinus Torvalds for (new_num = 0; new_num < vn->vn_nr_item; new_num++) { 931da177e4SLinus Torvalds int j; 941da177e4SLinus Torvalds struct virtual_item *vi = vn->vn_vi + new_num; 95bd4c625cSLinus Torvalds int is_affected = 96bd4c625cSLinus Torvalds ((new_num != vn->vn_affected_item_num) ? 0 : 1); 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds if (is_affected && vn->vn_mode == M_INSERT) 991da177e4SLinus Torvalds continue; 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds /* get item number in source node */ 102bd4c625cSLinus Torvalds j = old_item_num(new_num, vn->vn_affected_item_num, 103bd4c625cSLinus Torvalds vn->vn_mode); 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds vi->vi_item_len += ih_item_len(ih + j) + IH_SIZE; 1061da177e4SLinus Torvalds vi->vi_ih = ih + j; 1074cf5f7adSJeff Mahoney vi->vi_item = ih_item_body(Sh, ih + j); 1081da177e4SLinus Torvalds vi->vi_uarea = vn->vn_free_ptr; 1091da177e4SLinus Torvalds 110098297b2SJeff Mahoney /* 111098297b2SJeff Mahoney * FIXME: there is no check that item operation did not 112098297b2SJeff Mahoney * consume too much memory 113098297b2SJeff Mahoney */ 114bd4c625cSLinus Torvalds vn->vn_free_ptr += 115bd4c625cSLinus Torvalds op_create_vi(vn, vi, is_affected, tb->insert_size[0]); 1161da177e4SLinus Torvalds if (tb->vn_buf + tb->vn_buf_size < vn->vn_free_ptr) 117c3a9c210SJeff Mahoney reiserfs_panic(tb->tb_sb, "vs-8030", 1181da177e4SLinus Torvalds "virtual node space consumed"); 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds if (!is_affected) 1211da177e4SLinus Torvalds /* this is not being changed */ 1221da177e4SLinus Torvalds continue; 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds if (vn->vn_mode == M_PASTE || vn->vn_mode == M_CUT) { 1251da177e4SLinus Torvalds vn->vn_vi[new_num].vi_item_len += tb->insert_size[0]; 126098297b2SJeff Mahoney /* pointer to data which is going to be pasted */ 127098297b2SJeff Mahoney vi->vi_new_data = vn->vn_data; 1281da177e4SLinus Torvalds } 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds /* virtual inserted item is not defined yet */ 1321da177e4SLinus Torvalds if (vn->vn_mode == M_INSERT) { 1331da177e4SLinus Torvalds struct virtual_item *vi = vn->vn_vi + vn->vn_affected_item_num; 1341da177e4SLinus Torvalds 1359dce07f1SAl Viro RFALSE(vn->vn_ins_ih == NULL, 1361da177e4SLinus Torvalds "vs-8040: item header of inserted item is not specified"); 1371da177e4SLinus Torvalds vi->vi_item_len = tb->insert_size[0]; 1381da177e4SLinus Torvalds vi->vi_ih = vn->vn_ins_ih; 1391da177e4SLinus Torvalds vi->vi_item = vn->vn_data; 1401da177e4SLinus Torvalds vi->vi_uarea = vn->vn_free_ptr; 1411da177e4SLinus Torvalds 142bd4c625cSLinus Torvalds op_create_vi(vn, vi, 0 /*not pasted or cut */ , 143bd4c625cSLinus Torvalds tb->insert_size[0]); 1441da177e4SLinus Torvalds } 1451da177e4SLinus Torvalds 146098297b2SJeff Mahoney /* 147098297b2SJeff Mahoney * set right merge flag we take right delimiting key and 148098297b2SJeff Mahoney * check whether it is a mergeable item 149098297b2SJeff Mahoney */ 1501da177e4SLinus Torvalds if (tb->CFR[0]) { 1511da177e4SLinus Torvalds struct reiserfs_key *key; 1521da177e4SLinus Torvalds 1534cf5f7adSJeff Mahoney key = internal_key(tb->CFR[0], tb->rkey[0]); 154bd4c625cSLinus Torvalds if (op_is_left_mergeable(key, Sh->b_size) 155bd4c625cSLinus Torvalds && (vn->vn_mode != M_DELETE 156bd4c625cSLinus Torvalds || vn->vn_affected_item_num != B_NR_ITEMS(Sh) - 1)) 157bd4c625cSLinus Torvalds vn->vn_vi[vn->vn_nr_item - 1].vi_type |= 158bd4c625cSLinus Torvalds VI_TYPE_RIGHT_MERGEABLE; 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK 1611da177e4SLinus Torvalds if (op_is_left_mergeable(key, Sh->b_size) && 162bd4c625cSLinus Torvalds !(vn->vn_mode != M_DELETE 163bd4c625cSLinus Torvalds || vn->vn_affected_item_num != B_NR_ITEMS(Sh) - 1)) { 164098297b2SJeff Mahoney /* 165098297b2SJeff Mahoney * we delete last item and it could be merged 166098297b2SJeff Mahoney * with right neighbor's first item 167098297b2SJeff Mahoney */ 168bd4c625cSLinus Torvalds if (! 169bd4c625cSLinus Torvalds (B_NR_ITEMS(Sh) == 1 1704cf5f7adSJeff Mahoney && is_direntry_le_ih(item_head(Sh, 0)) 1714cf5f7adSJeff Mahoney && ih_entry_count(item_head(Sh, 0)) == 1)) { 172098297b2SJeff Mahoney /* 173098297b2SJeff Mahoney * node contains more than 1 item, or item 174098297b2SJeff Mahoney * is not directory item, or this item 175098297b2SJeff Mahoney * contains more than 1 entry 176098297b2SJeff Mahoney */ 1771da177e4SLinus Torvalds print_block(Sh, 0, -1, -1); 178c3a9c210SJeff Mahoney reiserfs_panic(tb->tb_sb, "vs-8045", 179c3a9c210SJeff Mahoney "rdkey %k, affected item==%d " 180c3a9c210SJeff Mahoney "(mode==%c) Must be %c", 181bd4c625cSLinus Torvalds key, vn->vn_affected_item_num, 182bd4c625cSLinus Torvalds vn->vn_mode, M_DELETE); 183cd02b966SVladimir V. Saveliev } 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds #endif 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds } 1881da177e4SLinus Torvalds } 1891da177e4SLinus Torvalds 190098297b2SJeff Mahoney /* 191098297b2SJeff Mahoney * Using virtual node check, how many items can be 192098297b2SJeff Mahoney * shifted to left neighbor 193098297b2SJeff Mahoney */ 1941da177e4SLinus Torvalds static void check_left(struct tree_balance *tb, int h, int cur_free) 1951da177e4SLinus Torvalds { 1961da177e4SLinus Torvalds int i; 1971da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 1981da177e4SLinus Torvalds struct virtual_item *vi; 1991da177e4SLinus Torvalds int d_size, ih_size; 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds RFALSE(cur_free < 0, "vs-8050: cur_free (%d) < 0", cur_free); 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds /* internal level */ 2041da177e4SLinus Torvalds if (h > 0) { 2051da177e4SLinus Torvalds tb->lnum[h] = cur_free / (DC_SIZE + KEY_SIZE); 2061da177e4SLinus Torvalds return; 2071da177e4SLinus Torvalds } 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds /* leaf level */ 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds if (!cur_free || !vn->vn_nr_item) { 2121da177e4SLinus Torvalds /* no free space or nothing to move */ 2131da177e4SLinus Torvalds tb->lnum[h] = 0; 2141da177e4SLinus Torvalds tb->lbytes = -1; 2151da177e4SLinus Torvalds return; 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds RFALSE(!PATH_H_PPARENT(tb->tb_path, 0), 2191da177e4SLinus Torvalds "vs-8055: parent does not exist or invalid"); 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds vi = vn->vn_vi; 222bd4c625cSLinus Torvalds if ((unsigned int)cur_free >= 223bd4c625cSLinus Torvalds (vn->vn_size - 224bd4c625cSLinus Torvalds ((vi->vi_type & VI_TYPE_LEFT_MERGEABLE) ? IH_SIZE : 0))) { 2251da177e4SLinus Torvalds /* all contents of S[0] fits into L[0] */ 2261da177e4SLinus Torvalds 2271da177e4SLinus Torvalds RFALSE(vn->vn_mode == M_INSERT || vn->vn_mode == M_PASTE, 2281da177e4SLinus Torvalds "vs-8055: invalid mode or balance condition failed"); 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds tb->lnum[0] = vn->vn_nr_item; 2311da177e4SLinus Torvalds tb->lbytes = -1; 2321da177e4SLinus Torvalds return; 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds d_size = 0, ih_size = IH_SIZE; 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds /* first item may be merge with last item in left neighbor */ 2381da177e4SLinus Torvalds if (vi->vi_type & VI_TYPE_LEFT_MERGEABLE) 2391da177e4SLinus Torvalds d_size = -((int)IH_SIZE), ih_size = 0; 2401da177e4SLinus Torvalds 2411da177e4SLinus Torvalds tb->lnum[0] = 0; 242bd4c625cSLinus Torvalds for (i = 0; i < vn->vn_nr_item; 243bd4c625cSLinus Torvalds i++, ih_size = IH_SIZE, d_size = 0, vi++) { 2441da177e4SLinus Torvalds d_size += vi->vi_item_len; 2451da177e4SLinus Torvalds if (cur_free >= d_size) { 2461da177e4SLinus Torvalds /* the item can be shifted entirely */ 2471da177e4SLinus Torvalds cur_free -= d_size; 2481da177e4SLinus Torvalds tb->lnum[0]++; 2491da177e4SLinus Torvalds continue; 2501da177e4SLinus Torvalds } 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds /* the item cannot be shifted entirely, try to split it */ 253098297b2SJeff Mahoney /* 254098297b2SJeff Mahoney * check whether L[0] can hold ih and at least one byte 255098297b2SJeff Mahoney * of the item body 256098297b2SJeff Mahoney */ 257098297b2SJeff Mahoney 2581da177e4SLinus Torvalds /* cannot shift even a part of the current item */ 259098297b2SJeff Mahoney if (cur_free <= ih_size) { 2601da177e4SLinus Torvalds tb->lbytes = -1; 2611da177e4SLinus Torvalds return; 2621da177e4SLinus Torvalds } 2631da177e4SLinus Torvalds cur_free -= ih_size; 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds tb->lbytes = op_check_left(vi, cur_free, 0, 0); 2661da177e4SLinus Torvalds if (tb->lbytes != -1) 2671da177e4SLinus Torvalds /* count partially shifted item */ 2681da177e4SLinus Torvalds tb->lnum[0]++; 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds break; 2711da177e4SLinus Torvalds } 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds return; 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 276098297b2SJeff Mahoney /* 277098297b2SJeff Mahoney * Using virtual node check, how many items can be 278098297b2SJeff Mahoney * shifted to right neighbor 279098297b2SJeff Mahoney */ 2801da177e4SLinus Torvalds static void check_right(struct tree_balance *tb, int h, int cur_free) 2811da177e4SLinus Torvalds { 2821da177e4SLinus Torvalds int i; 2831da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 2841da177e4SLinus Torvalds struct virtual_item *vi; 2851da177e4SLinus Torvalds int d_size, ih_size; 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds RFALSE(cur_free < 0, "vs-8070: cur_free < 0"); 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds /* internal level */ 2901da177e4SLinus Torvalds if (h > 0) { 2911da177e4SLinus Torvalds tb->rnum[h] = cur_free / (DC_SIZE + KEY_SIZE); 2921da177e4SLinus Torvalds return; 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds /* leaf level */ 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds if (!cur_free || !vn->vn_nr_item) { 2981da177e4SLinus Torvalds /* no free space */ 2991da177e4SLinus Torvalds tb->rnum[h] = 0; 3001da177e4SLinus Torvalds tb->rbytes = -1; 3011da177e4SLinus Torvalds return; 3021da177e4SLinus Torvalds } 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds RFALSE(!PATH_H_PPARENT(tb->tb_path, 0), 3051da177e4SLinus Torvalds "vs-8075: parent does not exist or invalid"); 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds vi = vn->vn_vi + vn->vn_nr_item - 1; 308bd4c625cSLinus Torvalds if ((unsigned int)cur_free >= 309bd4c625cSLinus Torvalds (vn->vn_size - 310bd4c625cSLinus Torvalds ((vi->vi_type & VI_TYPE_RIGHT_MERGEABLE) ? IH_SIZE : 0))) { 3111da177e4SLinus Torvalds /* all contents of S[0] fits into R[0] */ 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds RFALSE(vn->vn_mode == M_INSERT || vn->vn_mode == M_PASTE, 3141da177e4SLinus Torvalds "vs-8080: invalid mode or balance condition failed"); 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds tb->rnum[h] = vn->vn_nr_item; 3171da177e4SLinus Torvalds tb->rbytes = -1; 3181da177e4SLinus Torvalds return; 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds d_size = 0, ih_size = IH_SIZE; 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds /* last item may be merge with first item in right neighbor */ 3241da177e4SLinus Torvalds if (vi->vi_type & VI_TYPE_RIGHT_MERGEABLE) 3251da177e4SLinus Torvalds d_size = -(int)IH_SIZE, ih_size = 0; 3261da177e4SLinus Torvalds 3271da177e4SLinus Torvalds tb->rnum[0] = 0; 328bd4c625cSLinus Torvalds for (i = vn->vn_nr_item - 1; i >= 0; 329bd4c625cSLinus Torvalds i--, d_size = 0, ih_size = IH_SIZE, vi--) { 3301da177e4SLinus Torvalds d_size += vi->vi_item_len; 3311da177e4SLinus Torvalds if (cur_free >= d_size) { 3321da177e4SLinus Torvalds /* the item can be shifted entirely */ 3331da177e4SLinus Torvalds cur_free -= d_size; 3341da177e4SLinus Torvalds tb->rnum[0]++; 3351da177e4SLinus Torvalds continue; 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds 338098297b2SJeff Mahoney /* 339098297b2SJeff Mahoney * check whether R[0] can hold ih and at least one 340098297b2SJeff Mahoney * byte of the item body 341098297b2SJeff Mahoney */ 342098297b2SJeff Mahoney 343098297b2SJeff Mahoney /* cannot shift even a part of the current item */ 344098297b2SJeff Mahoney if (cur_free <= ih_size) { 3451da177e4SLinus Torvalds tb->rbytes = -1; 3461da177e4SLinus Torvalds return; 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds 349098297b2SJeff Mahoney /* 350098297b2SJeff Mahoney * R[0] can hold the header of the item and at least 351098297b2SJeff Mahoney * one byte of its body 352098297b2SJeff Mahoney */ 3531da177e4SLinus Torvalds cur_free -= ih_size; /* cur_free is still > 0 */ 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds tb->rbytes = op_check_right(vi, cur_free); 3561da177e4SLinus Torvalds if (tb->rbytes != -1) 3571da177e4SLinus Torvalds /* count partially shifted item */ 3581da177e4SLinus Torvalds tb->rnum[0]++; 3591da177e4SLinus Torvalds 3601da177e4SLinus Torvalds break; 3611da177e4SLinus Torvalds } 3621da177e4SLinus Torvalds 3631da177e4SLinus Torvalds return; 3641da177e4SLinus Torvalds } 3651da177e4SLinus Torvalds 3661da177e4SLinus Torvalds /* 3671da177e4SLinus Torvalds * from - number of items, which are shifted to left neighbor entirely 3681da177e4SLinus Torvalds * to - number of item, which are shifted to right neighbor entirely 369098297b2SJeff Mahoney * from_bytes - number of bytes of boundary item (or directory entries) 370098297b2SJeff Mahoney * which are shifted to left neighbor 371098297b2SJeff Mahoney * to_bytes - number of bytes of boundary item (or directory entries) 372098297b2SJeff Mahoney * which are shifted to right neighbor 373098297b2SJeff Mahoney */ 3741da177e4SLinus Torvalds static int get_num_ver(int mode, struct tree_balance *tb, int h, 3751da177e4SLinus Torvalds int from, int from_bytes, 376bd4c625cSLinus Torvalds int to, int to_bytes, short *snum012, int flow) 3771da177e4SLinus Torvalds { 3781da177e4SLinus Torvalds int i; 3791da177e4SLinus Torvalds int cur_free; 3801da177e4SLinus Torvalds int units; 3811da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 3821da177e4SLinus Torvalds int total_node_size, max_node_size, current_item_size; 3831da177e4SLinus Torvalds int needed_nodes; 384098297b2SJeff Mahoney 385098297b2SJeff Mahoney /* position of item we start filling node from */ 386098297b2SJeff Mahoney int start_item; 387098297b2SJeff Mahoney 388098297b2SJeff Mahoney /* position of item we finish filling node by */ 389098297b2SJeff Mahoney int end_item; 390098297b2SJeff Mahoney 391098297b2SJeff Mahoney /* 392098297b2SJeff Mahoney * number of first bytes (entries for directory) of start_item-th item 393098297b2SJeff Mahoney * we do not include into node that is being filled 394098297b2SJeff Mahoney */ 395098297b2SJeff Mahoney int start_bytes; 396098297b2SJeff Mahoney 397098297b2SJeff Mahoney /* 398098297b2SJeff Mahoney * number of last bytes (entries for directory) of end_item-th item 399098297b2SJeff Mahoney * we do node include into node that is being filled 400098297b2SJeff Mahoney */ 401098297b2SJeff Mahoney int end_bytes; 402098297b2SJeff Mahoney 403098297b2SJeff Mahoney /* 404098297b2SJeff Mahoney * these are positions in virtual item of items, that are split 405098297b2SJeff Mahoney * between S[0] and S1new and S1new and S2new 406098297b2SJeff Mahoney */ 407098297b2SJeff Mahoney int split_item_positions[2]; 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds split_item_positions[0] = -1; 4101da177e4SLinus Torvalds split_item_positions[1] = -1; 4111da177e4SLinus Torvalds 412098297b2SJeff Mahoney /* 413098297b2SJeff Mahoney * We only create additional nodes if we are in insert or paste mode 414098297b2SJeff Mahoney * or we are in replace mode at the internal level. If h is 0 and 415098297b2SJeff Mahoney * the mode is M_REPLACE then in fix_nodes we change the mode to 416098297b2SJeff Mahoney * paste or insert before we get here in the code. 417098297b2SJeff Mahoney */ 4181da177e4SLinus Torvalds RFALSE(tb->insert_size[h] < 0 || (mode != M_INSERT && mode != M_PASTE), 4191da177e4SLinus Torvalds "vs-8100: insert_size < 0 in overflow"); 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds max_node_size = MAX_CHILD_SIZE(PATH_H_PBUFFER(tb->tb_path, h)); 4221da177e4SLinus Torvalds 423098297b2SJeff Mahoney /* 424098297b2SJeff Mahoney * snum012 [0-2] - number of items, that lay 425098297b2SJeff Mahoney * to S[0], first new node and second new node 426098297b2SJeff Mahoney */ 4271da177e4SLinus Torvalds snum012[3] = -1; /* s1bytes */ 4281da177e4SLinus Torvalds snum012[4] = -1; /* s2bytes */ 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds /* internal level */ 4311da177e4SLinus Torvalds if (h > 0) { 4321da177e4SLinus Torvalds i = ((to - from) * (KEY_SIZE + DC_SIZE) + DC_SIZE); 4331da177e4SLinus Torvalds if (i == max_node_size) 4341da177e4SLinus Torvalds return 1; 4351da177e4SLinus Torvalds return (i / max_node_size + 1); 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds /* leaf level */ 4391da177e4SLinus Torvalds needed_nodes = 1; 4401da177e4SLinus Torvalds total_node_size = 0; 4411da177e4SLinus Torvalds cur_free = max_node_size; 4421da177e4SLinus Torvalds 443098297b2SJeff Mahoney /* start from 'from'-th item */ 4441da177e4SLinus Torvalds start_item = from; 445098297b2SJeff Mahoney /* skip its first 'start_bytes' units */ 4461da177e4SLinus Torvalds start_bytes = ((from_bytes != -1) ? from_bytes : 0); 4471da177e4SLinus Torvalds 448098297b2SJeff Mahoney /* last included item is the 'end_item'-th one */ 4491da177e4SLinus Torvalds end_item = vn->vn_nr_item - to - 1; 450098297b2SJeff Mahoney /* do not count last 'end_bytes' units of 'end_item'-th item */ 4511da177e4SLinus Torvalds end_bytes = (to_bytes != -1) ? to_bytes : 0; 4521da177e4SLinus Torvalds 453098297b2SJeff Mahoney /* 454098297b2SJeff Mahoney * go through all item beginning from the start_item-th item 455098297b2SJeff Mahoney * and ending by the end_item-th item. Do not count first 456098297b2SJeff Mahoney * 'start_bytes' units of 'start_item'-th item and last 457098297b2SJeff Mahoney * 'end_bytes' of 'end_item'-th item 458098297b2SJeff Mahoney */ 4591da177e4SLinus Torvalds for (i = start_item; i <= end_item; i++) { 4601da177e4SLinus Torvalds struct virtual_item *vi = vn->vn_vi + i; 4611da177e4SLinus Torvalds int skip_from_end = ((i == end_item) ? end_bytes : 0); 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds RFALSE(needed_nodes > 3, "vs-8105: too many nodes are needed"); 4641da177e4SLinus Torvalds 4651da177e4SLinus Torvalds /* get size of current item */ 4661da177e4SLinus Torvalds current_item_size = vi->vi_item_len; 4671da177e4SLinus Torvalds 468098297b2SJeff Mahoney /* 469098297b2SJeff Mahoney * do not take in calculation head part (from_bytes) 470098297b2SJeff Mahoney * of from-th item 471098297b2SJeff Mahoney */ 472bd4c625cSLinus Torvalds current_item_size -= 473bd4c625cSLinus Torvalds op_part_size(vi, 0 /*from start */ , start_bytes); 4741da177e4SLinus Torvalds 4751da177e4SLinus Torvalds /* do not take in calculation tail part of last item */ 476bd4c625cSLinus Torvalds current_item_size -= 477bd4c625cSLinus Torvalds op_part_size(vi, 1 /*from end */ , skip_from_end); 4781da177e4SLinus Torvalds 4791da177e4SLinus Torvalds /* if item fits into current node entierly */ 4801da177e4SLinus Torvalds if (total_node_size + current_item_size <= max_node_size) { 4811da177e4SLinus Torvalds snum012[needed_nodes - 1]++; 4821da177e4SLinus Torvalds total_node_size += current_item_size; 4831da177e4SLinus Torvalds start_bytes = 0; 4841da177e4SLinus Torvalds continue; 4851da177e4SLinus Torvalds } 4861da177e4SLinus Torvalds 487098297b2SJeff Mahoney /* 488098297b2SJeff Mahoney * virtual item length is longer, than max size of item in 489098297b2SJeff Mahoney * a node. It is impossible for direct item 490098297b2SJeff Mahoney */ 4911da177e4SLinus Torvalds if (current_item_size > max_node_size) { 4921da177e4SLinus Torvalds RFALSE(is_direct_le_ih(vi->vi_ih), 4931da177e4SLinus Torvalds "vs-8110: " 4941da177e4SLinus Torvalds "direct item length is %d. It can not be longer than %d", 4951da177e4SLinus Torvalds current_item_size, max_node_size); 4961da177e4SLinus Torvalds /* we will try to split it */ 4971da177e4SLinus Torvalds flow = 1; 4981da177e4SLinus Torvalds } 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds /* as we do not split items, take new node and continue */ 501098297b2SJeff Mahoney if (!flow) { 502bd4c625cSLinus Torvalds needed_nodes++; 503bd4c625cSLinus Torvalds i--; 504bd4c625cSLinus Torvalds total_node_size = 0; 5051da177e4SLinus Torvalds continue; 5061da177e4SLinus Torvalds } 507098297b2SJeff Mahoney 508098297b2SJeff Mahoney /* 509098297b2SJeff Mahoney * calculate number of item units which fit into node being 510098297b2SJeff Mahoney * filled 511098297b2SJeff Mahoney */ 5121da177e4SLinus Torvalds { 5131da177e4SLinus Torvalds int free_space; 5141da177e4SLinus Torvalds 5151da177e4SLinus Torvalds free_space = max_node_size - total_node_size - IH_SIZE; 516bd4c625cSLinus Torvalds units = 517bd4c625cSLinus Torvalds op_check_left(vi, free_space, start_bytes, 518bd4c625cSLinus Torvalds skip_from_end); 519098297b2SJeff Mahoney /* 520098297b2SJeff Mahoney * nothing fits into current node, take new 521098297b2SJeff Mahoney * node and continue 522098297b2SJeff Mahoney */ 5231da177e4SLinus Torvalds if (units == -1) { 5241da177e4SLinus Torvalds needed_nodes++, i--, total_node_size = 0; 5251da177e4SLinus Torvalds continue; 5261da177e4SLinus Torvalds } 5271da177e4SLinus Torvalds } 5281da177e4SLinus Torvalds 5291da177e4SLinus Torvalds /* something fits into the current node */ 5301da177e4SLinus Torvalds start_bytes += units; 5311da177e4SLinus Torvalds snum012[needed_nodes - 1 + 3] = units; 5321da177e4SLinus Torvalds 5331da177e4SLinus Torvalds if (needed_nodes > 2) 53445b03d5eSJeff Mahoney reiserfs_warning(tb->tb_sb, "vs-8111", 53545b03d5eSJeff Mahoney "split_item_position is out of range"); 5361da177e4SLinus Torvalds snum012[needed_nodes - 1]++; 5371da177e4SLinus Torvalds split_item_positions[needed_nodes - 1] = i; 5381da177e4SLinus Torvalds needed_nodes++; 5391da177e4SLinus Torvalds /* continue from the same item with start_bytes != -1 */ 5401da177e4SLinus Torvalds start_item = i; 5411da177e4SLinus Torvalds i--; 5421da177e4SLinus Torvalds total_node_size = 0; 5431da177e4SLinus Torvalds } 5441da177e4SLinus Torvalds 545098297b2SJeff Mahoney /* 546098297b2SJeff Mahoney * sum012[4] (if it is not -1) contains number of units of which 547098297b2SJeff Mahoney * are to be in S1new, snum012[3] - to be in S0. They are supposed 548098297b2SJeff Mahoney * to be S1bytes and S2bytes correspondingly, so recalculate 549098297b2SJeff Mahoney */ 5501da177e4SLinus Torvalds if (snum012[4] > 0) { 5511da177e4SLinus Torvalds int split_item_num; 5521da177e4SLinus Torvalds int bytes_to_r, bytes_to_l; 5531da177e4SLinus Torvalds int bytes_to_S1new; 5541da177e4SLinus Torvalds 5551da177e4SLinus Torvalds split_item_num = split_item_positions[1]; 556bd4c625cSLinus Torvalds bytes_to_l = 557bd4c625cSLinus Torvalds ((from == split_item_num 558bd4c625cSLinus Torvalds && from_bytes != -1) ? from_bytes : 0); 559bd4c625cSLinus Torvalds bytes_to_r = 560bd4c625cSLinus Torvalds ((end_item == split_item_num 561bd4c625cSLinus Torvalds && end_bytes != -1) ? end_bytes : 0); 562bd4c625cSLinus Torvalds bytes_to_S1new = 563bd4c625cSLinus Torvalds ((split_item_positions[0] == 564bd4c625cSLinus Torvalds split_item_positions[1]) ? snum012[3] : 0); 5651da177e4SLinus Torvalds 566098297b2SJeff Mahoney /* s2bytes */ 567bd4c625cSLinus Torvalds snum012[4] = 568bd4c625cSLinus Torvalds op_unit_num(&vn->vn_vi[split_item_num]) - snum012[4] - 569bd4c625cSLinus Torvalds bytes_to_r - bytes_to_l - bytes_to_S1new; 5701da177e4SLinus Torvalds 5711da177e4SLinus Torvalds if (vn->vn_vi[split_item_num].vi_index != TYPE_DIRENTRY && 5721da177e4SLinus Torvalds vn->vn_vi[split_item_num].vi_index != TYPE_INDIRECT) 57345b03d5eSJeff Mahoney reiserfs_warning(tb->tb_sb, "vs-8115", 57445b03d5eSJeff Mahoney "not directory or indirect item"); 5751da177e4SLinus Torvalds } 5761da177e4SLinus Torvalds 5771da177e4SLinus Torvalds /* now we know S2bytes, calculate S1bytes */ 5781da177e4SLinus Torvalds if (snum012[3] > 0) { 5791da177e4SLinus Torvalds int split_item_num; 5801da177e4SLinus Torvalds int bytes_to_r, bytes_to_l; 5811da177e4SLinus Torvalds int bytes_to_S2new; 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds split_item_num = split_item_positions[0]; 584bd4c625cSLinus Torvalds bytes_to_l = 585bd4c625cSLinus Torvalds ((from == split_item_num 586bd4c625cSLinus Torvalds && from_bytes != -1) ? from_bytes : 0); 587bd4c625cSLinus Torvalds bytes_to_r = 588bd4c625cSLinus Torvalds ((end_item == split_item_num 589bd4c625cSLinus Torvalds && end_bytes != -1) ? end_bytes : 0); 590bd4c625cSLinus Torvalds bytes_to_S2new = 591bd4c625cSLinus Torvalds ((split_item_positions[0] == split_item_positions[1] 592bd4c625cSLinus Torvalds && snum012[4] != -1) ? snum012[4] : 0); 5931da177e4SLinus Torvalds 594098297b2SJeff Mahoney /* s1bytes */ 595bd4c625cSLinus Torvalds snum012[3] = 596bd4c625cSLinus Torvalds op_unit_num(&vn->vn_vi[split_item_num]) - snum012[3] - 597bd4c625cSLinus Torvalds bytes_to_r - bytes_to_l - bytes_to_S2new; 5981da177e4SLinus Torvalds } 5991da177e4SLinus Torvalds 6001da177e4SLinus Torvalds return needed_nodes; 6011da177e4SLinus Torvalds } 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds 604098297b2SJeff Mahoney /* 605098297b2SJeff Mahoney * Set parameters for balancing. 6061da177e4SLinus Torvalds * Performs write of results of analysis of balancing into structure tb, 6071da177e4SLinus Torvalds * where it will later be used by the functions that actually do the balancing. 6081da177e4SLinus Torvalds * Parameters: 6091da177e4SLinus Torvalds * tb tree_balance structure; 6101da177e4SLinus Torvalds * h current level of the node; 6111da177e4SLinus Torvalds * lnum number of items from S[h] that must be shifted to L[h]; 6121da177e4SLinus Torvalds * rnum number of items from S[h] that must be shifted to R[h]; 6131da177e4SLinus Torvalds * blk_num number of blocks that S[h] will be splitted into; 6141da177e4SLinus Torvalds * s012 number of items that fall into splitted nodes. 615098297b2SJeff Mahoney * lbytes number of bytes which flow to the left neighbor from the 616098297b2SJeff Mahoney * item that is not not shifted entirely 617098297b2SJeff Mahoney * rbytes number of bytes which flow to the right neighbor from the 618098297b2SJeff Mahoney * item that is not not shifted entirely 619098297b2SJeff Mahoney * s1bytes number of bytes which flow to the first new node when 620098297b2SJeff Mahoney * S[0] splits (this number is contained in s012 array) 6211da177e4SLinus Torvalds */ 6221da177e4SLinus Torvalds 6231da177e4SLinus Torvalds static void set_parameters(struct tree_balance *tb, int h, int lnum, 6241da177e4SLinus Torvalds int rnum, int blk_num, short *s012, int lb, int rb) 6251da177e4SLinus Torvalds { 6261da177e4SLinus Torvalds 6271da177e4SLinus Torvalds tb->lnum[h] = lnum; 6281da177e4SLinus Torvalds tb->rnum[h] = rnum; 6291da177e4SLinus Torvalds tb->blknum[h] = blk_num; 6301da177e4SLinus Torvalds 631098297b2SJeff Mahoney /* only for leaf level */ 632098297b2SJeff Mahoney if (h == 0) { 633bd4c625cSLinus Torvalds if (s012 != NULL) { 6341da177e4SLinus Torvalds tb->s0num = *s012++, 635bd4c625cSLinus Torvalds tb->s1num = *s012++, tb->s2num = *s012++; 6361da177e4SLinus Torvalds tb->s1bytes = *s012++; 6371da177e4SLinus Torvalds tb->s2bytes = *s012; 6381da177e4SLinus Torvalds } 6391da177e4SLinus Torvalds tb->lbytes = lb; 6401da177e4SLinus Torvalds tb->rbytes = rb; 6411da177e4SLinus Torvalds } 6421da177e4SLinus Torvalds PROC_INFO_ADD(tb->tb_sb, lnum[h], lnum); 6431da177e4SLinus Torvalds PROC_INFO_ADD(tb->tb_sb, rnum[h], rnum); 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds PROC_INFO_ADD(tb->tb_sb, lbytes[h], lb); 6461da177e4SLinus Torvalds PROC_INFO_ADD(tb->tb_sb, rbytes[h], rb); 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds 649098297b2SJeff Mahoney /* 650098297b2SJeff Mahoney * check if node disappears if we shift tb->lnum[0] items to left 651098297b2SJeff Mahoney * neighbor and tb->rnum[0] to the right one. 652098297b2SJeff Mahoney */ 6531da177e4SLinus Torvalds static int is_leaf_removable(struct tree_balance *tb) 6541da177e4SLinus Torvalds { 6551da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 6561da177e4SLinus Torvalds int to_left, to_right; 6571da177e4SLinus Torvalds int size; 6581da177e4SLinus Torvalds int remain_items; 6591da177e4SLinus Torvalds 660098297b2SJeff Mahoney /* 661098297b2SJeff Mahoney * number of items that will be shifted to left (right) neighbor 662098297b2SJeff Mahoney * entirely 663098297b2SJeff Mahoney */ 6641da177e4SLinus Torvalds to_left = tb->lnum[0] - ((tb->lbytes != -1) ? 1 : 0); 6651da177e4SLinus Torvalds to_right = tb->rnum[0] - ((tb->rbytes != -1) ? 1 : 0); 6661da177e4SLinus Torvalds remain_items = vn->vn_nr_item; 6671da177e4SLinus Torvalds 6681da177e4SLinus Torvalds /* how many items remain in S[0] after shiftings to neighbors */ 6691da177e4SLinus Torvalds remain_items -= (to_left + to_right); 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds /* all content of node can be shifted to neighbors */ 672098297b2SJeff Mahoney if (remain_items < 1) { 673bd4c625cSLinus Torvalds set_parameters(tb, 0, to_left, vn->vn_nr_item - to_left, 0, 674bd4c625cSLinus Torvalds NULL, -1, -1); 6751da177e4SLinus Torvalds return 1; 6761da177e4SLinus Torvalds } 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds /* S[0] is not removable */ 679098297b2SJeff Mahoney if (remain_items > 1 || tb->lbytes == -1 || tb->rbytes == -1) 6801da177e4SLinus Torvalds return 0; 6811da177e4SLinus Torvalds 682098297b2SJeff Mahoney /* check whether we can divide 1 remaining item between neighbors */ 6831da177e4SLinus Torvalds 6841da177e4SLinus Torvalds /* get size of remaining item (in item units) */ 6851da177e4SLinus Torvalds size = op_unit_num(&(vn->vn_vi[to_left])); 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds if (tb->lbytes + tb->rbytes >= size) { 688bd4c625cSLinus Torvalds set_parameters(tb, 0, to_left + 1, to_right + 1, 0, NULL, 689bd4c625cSLinus Torvalds tb->lbytes, -1); 6901da177e4SLinus Torvalds return 1; 6911da177e4SLinus Torvalds } 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds return 0; 6941da177e4SLinus Torvalds } 6951da177e4SLinus Torvalds 6961da177e4SLinus Torvalds /* check whether L, S, R can be joined in one node */ 6971da177e4SLinus Torvalds static int are_leaves_removable(struct tree_balance *tb, int lfree, int rfree) 6981da177e4SLinus Torvalds { 6991da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 7001da177e4SLinus Torvalds int ih_size; 7011da177e4SLinus Torvalds struct buffer_head *S0; 7021da177e4SLinus Torvalds 7031da177e4SLinus Torvalds S0 = PATH_H_PBUFFER(tb->tb_path, 0); 7041da177e4SLinus Torvalds 7051da177e4SLinus Torvalds ih_size = 0; 7061da177e4SLinus Torvalds if (vn->vn_nr_item) { 7071da177e4SLinus Torvalds if (vn->vn_vi[0].vi_type & VI_TYPE_LEFT_MERGEABLE) 7081da177e4SLinus Torvalds ih_size += IH_SIZE; 7091da177e4SLinus Torvalds 710bd4c625cSLinus Torvalds if (vn->vn_vi[vn->vn_nr_item - 1]. 711bd4c625cSLinus Torvalds vi_type & VI_TYPE_RIGHT_MERGEABLE) 7121da177e4SLinus Torvalds ih_size += IH_SIZE; 7131da177e4SLinus Torvalds } else { 7141da177e4SLinus Torvalds /* there was only one item and it will be deleted */ 7151da177e4SLinus Torvalds struct item_head *ih; 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds RFALSE(B_NR_ITEMS(S0) != 1, 718bd4c625cSLinus Torvalds "vs-8125: item number must be 1: it is %d", 719bd4c625cSLinus Torvalds B_NR_ITEMS(S0)); 7201da177e4SLinus Torvalds 7214cf5f7adSJeff Mahoney ih = item_head(S0, 0); 722bd4c625cSLinus Torvalds if (tb->CFR[0] 723bd4c625cSLinus Torvalds && !comp_short_le_keys(&(ih->ih_key), 7244cf5f7adSJeff Mahoney internal_key(tb->CFR[0], 725bd4c625cSLinus Torvalds tb->rkey[0]))) 726098297b2SJeff Mahoney /* 727098297b2SJeff Mahoney * Directory must be in correct state here: that is 728098297b2SJeff Mahoney * somewhere at the left side should exist first 729098297b2SJeff Mahoney * directory item. But the item being deleted can 730098297b2SJeff Mahoney * not be that first one because its right neighbor 731098297b2SJeff Mahoney * is item of the same directory. (But first item 732098297b2SJeff Mahoney * always gets deleted in last turn). So, neighbors 733098297b2SJeff Mahoney * of deleted item can be merged, so we can save 734098297b2SJeff Mahoney * ih_size 735098297b2SJeff Mahoney */ 7361da177e4SLinus Torvalds if (is_direntry_le_ih(ih)) { 7371da177e4SLinus Torvalds ih_size = IH_SIZE; 7381da177e4SLinus Torvalds 739098297b2SJeff Mahoney /* 740098297b2SJeff Mahoney * we might check that left neighbor exists 741098297b2SJeff Mahoney * and is of the same directory 742098297b2SJeff Mahoney */ 7431da177e4SLinus Torvalds RFALSE(le_ih_k_offset(ih) == DOT_OFFSET, 7441da177e4SLinus Torvalds "vs-8130: first directory item can not be removed until directory is not empty"); 7451da177e4SLinus Torvalds } 7461da177e4SLinus Torvalds 7471da177e4SLinus Torvalds } 7481da177e4SLinus Torvalds 7491da177e4SLinus Torvalds if (MAX_CHILD_SIZE(S0) + vn->vn_size <= rfree + lfree + ih_size) { 7501da177e4SLinus Torvalds set_parameters(tb, 0, -1, -1, -1, NULL, -1, -1); 7511da177e4SLinus Torvalds PROC_INFO_INC(tb->tb_sb, leaves_removable); 7521da177e4SLinus Torvalds return 1; 7531da177e4SLinus Torvalds } 7541da177e4SLinus Torvalds return 0; 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds } 7571da177e4SLinus Torvalds 7581da177e4SLinus Torvalds /* when we do not split item, lnum and rnum are numbers of entire items */ 7591da177e4SLinus Torvalds #define SET_PAR_SHIFT_LEFT \ 7601da177e4SLinus Torvalds if (h)\ 7611da177e4SLinus Torvalds {\ 7621da177e4SLinus Torvalds int to_l;\ 7631da177e4SLinus Torvalds \ 7641da177e4SLinus Torvalds to_l = (MAX_NR_KEY(Sh)+1 - lpar + vn->vn_nr_item + 1) / 2 -\ 7651da177e4SLinus Torvalds (MAX_NR_KEY(Sh) + 1 - lpar);\ 7661da177e4SLinus Torvalds \ 7671da177e4SLinus Torvalds set_parameters (tb, h, to_l, 0, lnver, NULL, -1, -1);\ 7681da177e4SLinus Torvalds }\ 7691da177e4SLinus Torvalds else \ 7701da177e4SLinus Torvalds {\ 7711da177e4SLinus Torvalds if (lset==LEFT_SHIFT_FLOW)\ 7721da177e4SLinus Torvalds set_parameters (tb, h, lpar, 0, lnver, snum012+lset,\ 7731da177e4SLinus Torvalds tb->lbytes, -1);\ 7741da177e4SLinus Torvalds else\ 7751da177e4SLinus Torvalds set_parameters (tb, h, lpar - (tb->lbytes!=-1), 0, lnver, snum012+lset,\ 7761da177e4SLinus Torvalds -1, -1);\ 7771da177e4SLinus Torvalds } 7781da177e4SLinus Torvalds 7791da177e4SLinus Torvalds #define SET_PAR_SHIFT_RIGHT \ 7801da177e4SLinus Torvalds if (h)\ 7811da177e4SLinus Torvalds {\ 7821da177e4SLinus Torvalds int to_r;\ 7831da177e4SLinus Torvalds \ 7841da177e4SLinus Torvalds to_r = (MAX_NR_KEY(Sh)+1 - rpar + vn->vn_nr_item + 1) / 2 - (MAX_NR_KEY(Sh) + 1 - rpar);\ 7851da177e4SLinus Torvalds \ 7861da177e4SLinus Torvalds set_parameters (tb, h, 0, to_r, rnver, NULL, -1, -1);\ 7871da177e4SLinus Torvalds }\ 7881da177e4SLinus Torvalds else \ 7891da177e4SLinus Torvalds {\ 7901da177e4SLinus Torvalds if (rset==RIGHT_SHIFT_FLOW)\ 7911da177e4SLinus Torvalds set_parameters (tb, h, 0, rpar, rnver, snum012+rset,\ 7921da177e4SLinus Torvalds -1, tb->rbytes);\ 7931da177e4SLinus Torvalds else\ 7941da177e4SLinus Torvalds set_parameters (tb, h, 0, rpar - (tb->rbytes!=-1), rnver, snum012+rset,\ 7951da177e4SLinus Torvalds -1, -1);\ 7961da177e4SLinus Torvalds } 7971da177e4SLinus Torvalds 798a063ae17SJeff Mahoney static void free_buffers_in_tb(struct tree_balance *tb) 799bd4c625cSLinus Torvalds { 800ee93961bSJeff Mahoney int i; 8011da177e4SLinus Torvalds 802a063ae17SJeff Mahoney pathrelse(tb->tb_path); 8031da177e4SLinus Torvalds 804ee93961bSJeff Mahoney for (i = 0; i < MAX_HEIGHT; i++) { 805ee93961bSJeff Mahoney brelse(tb->L[i]); 806ee93961bSJeff Mahoney brelse(tb->R[i]); 807ee93961bSJeff Mahoney brelse(tb->FL[i]); 808ee93961bSJeff Mahoney brelse(tb->FR[i]); 809ee93961bSJeff Mahoney brelse(tb->CFL[i]); 810ee93961bSJeff Mahoney brelse(tb->CFR[i]); 8113cd6dbe6SJeff Mahoney 812ee93961bSJeff Mahoney tb->L[i] = NULL; 813ee93961bSJeff Mahoney tb->R[i] = NULL; 814ee93961bSJeff Mahoney tb->FL[i] = NULL; 815ee93961bSJeff Mahoney tb->FR[i] = NULL; 816ee93961bSJeff Mahoney tb->CFL[i] = NULL; 817ee93961bSJeff Mahoney tb->CFR[i] = NULL; 8181da177e4SLinus Torvalds } 8191da177e4SLinus Torvalds } 8201da177e4SLinus Torvalds 821098297b2SJeff Mahoney /* 822098297b2SJeff Mahoney * Get new buffers for storing new nodes that are created while balancing. 8231da177e4SLinus Torvalds * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; 8241da177e4SLinus Torvalds * CARRY_ON - schedule didn't occur while the function worked; 8251da177e4SLinus Torvalds * NO_DISK_SPACE - no disk space. 8261da177e4SLinus Torvalds */ 8271da177e4SLinus Torvalds /* The function is NOT SCHEDULE-SAFE! */ 828ee93961bSJeff Mahoney static int get_empty_nodes(struct tree_balance *tb, int h) 829bd4c625cSLinus Torvalds { 830098297b2SJeff Mahoney struct buffer_head *new_bh, *Sh = PATH_H_PBUFFER(tb->tb_path, h); 831ee93961bSJeff Mahoney b_blocknr_t *blocknr, blocknrs[MAX_AMOUNT_NEEDED] = { 0, }; 832098297b2SJeff Mahoney int counter, number_of_freeblk; 833098297b2SJeff Mahoney int amount_needed; /* number of needed empty blocks */ 834098297b2SJeff Mahoney int retval = CARRY_ON; 835a063ae17SJeff Mahoney struct super_block *sb = tb->tb_sb; 8361da177e4SLinus Torvalds 837098297b2SJeff Mahoney /* 838098297b2SJeff Mahoney * number_of_freeblk is the number of empty blocks which have been 839098297b2SJeff Mahoney * acquired for use by the balancing algorithm minus the number of 840098297b2SJeff Mahoney * empty blocks used in the previous levels of the analysis, 841098297b2SJeff Mahoney * number_of_freeblk = tb->cur_blknum can be non-zero if a schedule 842098297b2SJeff Mahoney * occurs after empty blocks are acquired, and the balancing analysis 843098297b2SJeff Mahoney * is then restarted, amount_needed is the number needed by this 844098297b2SJeff Mahoney * level (h) of the balancing analysis. 845098297b2SJeff Mahoney * 846098297b2SJeff Mahoney * Note that for systems with many processes writing, it would be 847098297b2SJeff Mahoney * more layout optimal to calculate the total number needed by all 848098297b2SJeff Mahoney * levels and then to run reiserfs_new_blocks to get all of them at 849098297b2SJeff Mahoney * once. 850098297b2SJeff Mahoney */ 8511da177e4SLinus Torvalds 852098297b2SJeff Mahoney /* 853098297b2SJeff Mahoney * Initiate number_of_freeblk to the amount acquired prior to the 854098297b2SJeff Mahoney * restart of the analysis or 0 if not restarted, then subtract the 855098297b2SJeff Mahoney * amount needed by all of the levels of the tree below h. 856098297b2SJeff Mahoney */ 857ee93961bSJeff Mahoney /* blknum includes S[h], so we subtract 1 in this calculation */ 858ee93961bSJeff Mahoney for (counter = 0, number_of_freeblk = tb->cur_blknum; 859ee93961bSJeff Mahoney counter < h; counter++) 860ee93961bSJeff Mahoney number_of_freeblk -= 861ee93961bSJeff Mahoney (tb->blknum[counter]) ? (tb->blknum[counter] - 862bd4c625cSLinus Torvalds 1) : 0; 8631da177e4SLinus Torvalds 8641da177e4SLinus Torvalds /* Allocate missing empty blocks. */ 865d68caa95SJeff Mahoney /* if Sh == 0 then we are getting a new root */ 866ee93961bSJeff Mahoney amount_needed = (Sh) ? (tb->blknum[h] - 1) : 1; 867098297b2SJeff Mahoney /* 868098297b2SJeff Mahoney * Amount_needed = the amount that we need more than the 869098297b2SJeff Mahoney * amount that we have. 870098297b2SJeff Mahoney */ 871ee93961bSJeff Mahoney if (amount_needed > number_of_freeblk) 872ee93961bSJeff Mahoney amount_needed -= number_of_freeblk; 8731da177e4SLinus Torvalds else /* If we have enough already then there is nothing to do. */ 8741da177e4SLinus Torvalds return CARRY_ON; 8751da177e4SLinus Torvalds 876098297b2SJeff Mahoney /* 877098297b2SJeff Mahoney * No need to check quota - is not allocated for blocks used 878098297b2SJeff Mahoney * for formatted nodes 879098297b2SJeff Mahoney */ 880ee93961bSJeff Mahoney if (reiserfs_new_form_blocknrs(tb, blocknrs, 881ee93961bSJeff Mahoney amount_needed) == NO_DISK_SPACE) 8821da177e4SLinus Torvalds return NO_DISK_SPACE; 8831da177e4SLinus Torvalds 8841da177e4SLinus Torvalds /* for each blocknumber we just got, get a buffer and stick it on FEB */ 885ee93961bSJeff Mahoney for (blocknr = blocknrs, counter = 0; 886ee93961bSJeff Mahoney counter < amount_needed; blocknr++, counter++) { 8871da177e4SLinus Torvalds 888d68caa95SJeff Mahoney RFALSE(!*blocknr, 8891da177e4SLinus Torvalds "PAP-8135: reiserfs_new_blocknrs failed when got new blocks"); 8901da177e4SLinus Torvalds 891d68caa95SJeff Mahoney new_bh = sb_getblk(sb, *blocknr); 892d68caa95SJeff Mahoney RFALSE(buffer_dirty(new_bh) || 893d68caa95SJeff Mahoney buffer_journaled(new_bh) || 894d68caa95SJeff Mahoney buffer_journal_dirty(new_bh), 895febe29d9SAdam Buchbinder "PAP-8140: journaled or dirty buffer %b for the new block", 896d68caa95SJeff Mahoney new_bh); 8971da177e4SLinus Torvalds 8981da177e4SLinus Torvalds /* Put empty buffers into the array. */ 899a063ae17SJeff Mahoney RFALSE(tb->FEB[tb->cur_blknum], 9001da177e4SLinus Torvalds "PAP-8141: busy slot for new buffer"); 9011da177e4SLinus Torvalds 902d68caa95SJeff Mahoney set_buffer_journal_new(new_bh); 903d68caa95SJeff Mahoney tb->FEB[tb->cur_blknum++] = new_bh; 9041da177e4SLinus Torvalds } 9051da177e4SLinus Torvalds 906ee93961bSJeff Mahoney if (retval == CARRY_ON && FILESYSTEM_CHANGED_TB(tb)) 907ee93961bSJeff Mahoney retval = REPEAT_SEARCH; 9081da177e4SLinus Torvalds 909ee93961bSJeff Mahoney return retval; 9101da177e4SLinus Torvalds } 9111da177e4SLinus Torvalds 912098297b2SJeff Mahoney /* 913098297b2SJeff Mahoney * Get free space of the left neighbor, which is stored in the parent 914098297b2SJeff Mahoney * node of the left neighbor. 915098297b2SJeff Mahoney */ 9161da177e4SLinus Torvalds static int get_lfree(struct tree_balance *tb, int h) 9171da177e4SLinus Torvalds { 9181da177e4SLinus Torvalds struct buffer_head *l, *f; 9191da177e4SLinus Torvalds int order; 9201da177e4SLinus Torvalds 9219dce07f1SAl Viro if ((f = PATH_H_PPARENT(tb->tb_path, h)) == NULL || 9229dce07f1SAl Viro (l = tb->FL[h]) == NULL) 9231da177e4SLinus Torvalds return 0; 9241da177e4SLinus Torvalds 9251da177e4SLinus Torvalds if (f == l) 9261da177e4SLinus Torvalds order = PATH_H_B_ITEM_ORDER(tb->tb_path, h) - 1; 9271da177e4SLinus Torvalds else { 9281da177e4SLinus Torvalds order = B_NR_ITEMS(l); 9291da177e4SLinus Torvalds f = l; 9301da177e4SLinus Torvalds } 9311da177e4SLinus Torvalds 9321da177e4SLinus Torvalds return (MAX_CHILD_SIZE(f) - dc_size(B_N_CHILD(f, order))); 9331da177e4SLinus Torvalds } 9341da177e4SLinus Torvalds 935098297b2SJeff Mahoney /* 936098297b2SJeff Mahoney * Get free space of the right neighbor, 9371da177e4SLinus Torvalds * which is stored in the parent node of the right neighbor. 9381da177e4SLinus Torvalds */ 9391da177e4SLinus Torvalds static int get_rfree(struct tree_balance *tb, int h) 9401da177e4SLinus Torvalds { 9411da177e4SLinus Torvalds struct buffer_head *r, *f; 9421da177e4SLinus Torvalds int order; 9431da177e4SLinus Torvalds 9449dce07f1SAl Viro if ((f = PATH_H_PPARENT(tb->tb_path, h)) == NULL || 9459dce07f1SAl Viro (r = tb->FR[h]) == NULL) 9461da177e4SLinus Torvalds return 0; 9471da177e4SLinus Torvalds 9481da177e4SLinus Torvalds if (f == r) 9491da177e4SLinus Torvalds order = PATH_H_B_ITEM_ORDER(tb->tb_path, h) + 1; 9501da177e4SLinus Torvalds else { 9511da177e4SLinus Torvalds order = 0; 9521da177e4SLinus Torvalds f = r; 9531da177e4SLinus Torvalds } 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds return (MAX_CHILD_SIZE(f) - dc_size(B_N_CHILD(f, order))); 9561da177e4SLinus Torvalds 9571da177e4SLinus Torvalds } 9581da177e4SLinus Torvalds 9591da177e4SLinus Torvalds /* Check whether left neighbor is in memory. */ 960ee93961bSJeff Mahoney static int is_left_neighbor_in_cache(struct tree_balance *tb, int h) 961bd4c625cSLinus Torvalds { 962d68caa95SJeff Mahoney struct buffer_head *father, *left; 963a063ae17SJeff Mahoney struct super_block *sb = tb->tb_sb; 964ee93961bSJeff Mahoney b_blocknr_t left_neighbor_blocknr; 965ee93961bSJeff Mahoney int left_neighbor_position; 9661da177e4SLinus Torvalds 967a063ae17SJeff Mahoney /* Father of the left neighbor does not exist. */ 968ee93961bSJeff Mahoney if (!tb->FL[h]) 9691da177e4SLinus Torvalds return 0; 9701da177e4SLinus Torvalds 9711da177e4SLinus Torvalds /* Calculate father of the node to be balanced. */ 972ee93961bSJeff Mahoney father = PATH_H_PBUFFER(tb->tb_path, h + 1); 9731da177e4SLinus Torvalds 974d68caa95SJeff Mahoney RFALSE(!father || 975d68caa95SJeff Mahoney !B_IS_IN_TREE(father) || 976ee93961bSJeff Mahoney !B_IS_IN_TREE(tb->FL[h]) || 977d68caa95SJeff Mahoney !buffer_uptodate(father) || 978ee93961bSJeff Mahoney !buffer_uptodate(tb->FL[h]), 9791da177e4SLinus Torvalds "vs-8165: F[h] (%b) or FL[h] (%b) is invalid", 980ee93961bSJeff Mahoney father, tb->FL[h]); 9811da177e4SLinus Torvalds 982098297b2SJeff Mahoney /* 983098297b2SJeff Mahoney * Get position of the pointer to the left neighbor 984098297b2SJeff Mahoney * into the left father. 985098297b2SJeff Mahoney */ 986ee93961bSJeff Mahoney left_neighbor_position = (father == tb->FL[h]) ? 987ee93961bSJeff Mahoney tb->lkey[h] : B_NR_ITEMS(tb->FL[h]); 9881da177e4SLinus Torvalds /* Get left neighbor block number. */ 989ee93961bSJeff Mahoney left_neighbor_blocknr = 990ee93961bSJeff Mahoney B_N_CHILD_NUM(tb->FL[h], left_neighbor_position); 9911da177e4SLinus Torvalds /* Look for the left neighbor in the cache. */ 992ee93961bSJeff Mahoney if ((left = sb_find_get_block(sb, left_neighbor_blocknr))) { 9931da177e4SLinus Torvalds 9941da177e4SLinus Torvalds RFALSE(buffer_uptodate(left) && !B_IS_IN_TREE(left), 995bd4c625cSLinus Torvalds "vs-8170: left neighbor (%b %z) is not in the tree", 996bd4c625cSLinus Torvalds left, left); 9971da177e4SLinus Torvalds put_bh(left); 9981da177e4SLinus Torvalds return 1; 9991da177e4SLinus Torvalds } 10001da177e4SLinus Torvalds 10011da177e4SLinus Torvalds return 0; 10021da177e4SLinus Torvalds } 10031da177e4SLinus Torvalds 10041da177e4SLinus Torvalds #define LEFT_PARENTS 'l' 10051da177e4SLinus Torvalds #define RIGHT_PARENTS 'r' 10061da177e4SLinus Torvalds 1007d68caa95SJeff Mahoney static void decrement_key(struct cpu_key *key) 10081da177e4SLinus Torvalds { 1009098297b2SJeff Mahoney /* call item specific function for this key */ 1010d68caa95SJeff Mahoney item_ops[cpu_key_k_type(key)]->decrement_key(key); 10111da177e4SLinus Torvalds } 10121da177e4SLinus Torvalds 1013098297b2SJeff Mahoney /* 1014098297b2SJeff Mahoney * Calculate far left/right parent of the left/right neighbor of the 1015098297b2SJeff Mahoney * current node, that is calculate the left/right (FL[h]/FR[h]) neighbor 1016098297b2SJeff Mahoney * of the parent F[h]. 10171da177e4SLinus Torvalds * Calculate left/right common parent of the current node and L[h]/R[h]. 10181da177e4SLinus Torvalds * Calculate left/right delimiting key position. 1019098297b2SJeff Mahoney * Returns: PATH_INCORRECT - path in the tree is not correct 1020098297b2SJeff Mahoney * SCHEDULE_OCCURRED - schedule occurred while the function worked 1021098297b2SJeff Mahoney * CARRY_ON - schedule didn't occur while the function 1022098297b2SJeff Mahoney * worked 10231da177e4SLinus Torvalds */ 1024a063ae17SJeff Mahoney static int get_far_parent(struct tree_balance *tb, 1025ee93961bSJeff Mahoney int h, 1026d68caa95SJeff Mahoney struct buffer_head **pfather, 1027d68caa95SJeff Mahoney struct buffer_head **pcom_father, char c_lr_par) 10281da177e4SLinus Torvalds { 1029d68caa95SJeff Mahoney struct buffer_head *parent; 10301da177e4SLinus Torvalds INITIALIZE_PATH(s_path_to_neighbor_father); 1031d68caa95SJeff Mahoney struct treepath *path = tb->tb_path; 10321da177e4SLinus Torvalds struct cpu_key s_lr_father_key; 1033ee93961bSJeff Mahoney int counter, 1034ee93961bSJeff Mahoney position = INT_MAX, 1035ee93961bSJeff Mahoney first_last_position = 0, 1036ee93961bSJeff Mahoney path_offset = PATH_H_PATH_OFFSET(path, h); 10371da177e4SLinus Torvalds 1038098297b2SJeff Mahoney /* 1039098297b2SJeff Mahoney * Starting from F[h] go upwards in the tree, and look for the common 1040098297b2SJeff Mahoney * ancestor of F[h], and its neighbor l/r, that should be obtained. 1041098297b2SJeff Mahoney */ 10421da177e4SLinus Torvalds 1043ee93961bSJeff Mahoney counter = path_offset; 10441da177e4SLinus Torvalds 1045ee93961bSJeff Mahoney RFALSE(counter < FIRST_PATH_ELEMENT_OFFSET, 10461da177e4SLinus Torvalds "PAP-8180: invalid path length"); 10471da177e4SLinus Torvalds 1048ee93961bSJeff Mahoney for (; counter > FIRST_PATH_ELEMENT_OFFSET; counter--) { 1049098297b2SJeff Mahoney /* 1050098297b2SJeff Mahoney * Check whether parent of the current buffer in the path 1051098297b2SJeff Mahoney * is really parent in the tree. 1052098297b2SJeff Mahoney */ 1053bd4c625cSLinus Torvalds if (!B_IS_IN_TREE 1054ee93961bSJeff Mahoney (parent = PATH_OFFSET_PBUFFER(path, counter - 1))) 10551da177e4SLinus Torvalds return REPEAT_SEARCH; 1056098297b2SJeff Mahoney 10571da177e4SLinus Torvalds /* Check whether position in the parent is correct. */ 1058ee93961bSJeff Mahoney if ((position = 1059d68caa95SJeff Mahoney PATH_OFFSET_POSITION(path, 1060ee93961bSJeff Mahoney counter - 1)) > 1061d68caa95SJeff Mahoney B_NR_ITEMS(parent)) 10621da177e4SLinus Torvalds return REPEAT_SEARCH; 1063098297b2SJeff Mahoney 1064098297b2SJeff Mahoney /* 1065098297b2SJeff Mahoney * Check whether parent at the path really points 1066098297b2SJeff Mahoney * to the child. 1067098297b2SJeff Mahoney */ 1068ee93961bSJeff Mahoney if (B_N_CHILD_NUM(parent, position) != 1069ee93961bSJeff Mahoney PATH_OFFSET_PBUFFER(path, counter)->b_blocknr) 10701da177e4SLinus Torvalds return REPEAT_SEARCH; 1071098297b2SJeff Mahoney 1072098297b2SJeff Mahoney /* 1073098297b2SJeff Mahoney * Return delimiting key if position in the parent is not 1074098297b2SJeff Mahoney * equal to first/last one. 1075098297b2SJeff Mahoney */ 10761da177e4SLinus Torvalds if (c_lr_par == RIGHT_PARENTS) 1077ee93961bSJeff Mahoney first_last_position = B_NR_ITEMS(parent); 1078ee93961bSJeff Mahoney if (position != first_last_position) { 1079d68caa95SJeff Mahoney *pcom_father = parent; 1080d68caa95SJeff Mahoney get_bh(*pcom_father); 1081d68caa95SJeff Mahoney /*(*pcom_father = parent)->b_count++; */ 10821da177e4SLinus Torvalds break; 10831da177e4SLinus Torvalds } 10841da177e4SLinus Torvalds } 10851da177e4SLinus Torvalds 10861da177e4SLinus Torvalds /* if we are in the root of the tree, then there is no common father */ 1087ee93961bSJeff Mahoney if (counter == FIRST_PATH_ELEMENT_OFFSET) { 1088098297b2SJeff Mahoney /* 1089098297b2SJeff Mahoney * Check whether first buffer in the path is the 1090098297b2SJeff Mahoney * root of the tree. 1091098297b2SJeff Mahoney */ 1092bd4c625cSLinus Torvalds if (PATH_OFFSET_PBUFFER 1093a063ae17SJeff Mahoney (tb->tb_path, 1094bd4c625cSLinus Torvalds FIRST_PATH_ELEMENT_OFFSET)->b_blocknr == 1095a063ae17SJeff Mahoney SB_ROOT_BLOCK(tb->tb_sb)) { 1096d68caa95SJeff Mahoney *pfather = *pcom_father = NULL; 10971da177e4SLinus Torvalds return CARRY_ON; 10981da177e4SLinus Torvalds } 10991da177e4SLinus Torvalds return REPEAT_SEARCH; 11001da177e4SLinus Torvalds } 11011da177e4SLinus Torvalds 1102d68caa95SJeff Mahoney RFALSE(B_LEVEL(*pcom_father) <= DISK_LEAF_NODE_LEVEL, 11031da177e4SLinus Torvalds "PAP-8185: (%b %z) level too small", 1104d68caa95SJeff Mahoney *pcom_father, *pcom_father); 11051da177e4SLinus Torvalds 11061da177e4SLinus Torvalds /* Check whether the common parent is locked. */ 11071da177e4SLinus Torvalds 1108d68caa95SJeff Mahoney if (buffer_locked(*pcom_father)) { 11098ebc4232SFrederic Weisbecker 11108ebc4232SFrederic Weisbecker /* Release the write lock while the buffer is busy */ 1111278f6679SJeff Mahoney int depth = reiserfs_write_unlock_nested(tb->tb_sb); 1112d68caa95SJeff Mahoney __wait_on_buffer(*pcom_father); 1113278f6679SJeff Mahoney reiserfs_write_lock_nested(tb->tb_sb, depth); 1114a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) { 1115d68caa95SJeff Mahoney brelse(*pcom_father); 11161da177e4SLinus Torvalds return REPEAT_SEARCH; 11171da177e4SLinus Torvalds } 11181da177e4SLinus Torvalds } 11191da177e4SLinus Torvalds 1120098297b2SJeff Mahoney /* 1121098297b2SJeff Mahoney * So, we got common parent of the current node and its 1122098297b2SJeff Mahoney * left/right neighbor. Now we are getting the parent of the 1123098297b2SJeff Mahoney * left/right neighbor. 1124098297b2SJeff Mahoney */ 11251da177e4SLinus Torvalds 11261da177e4SLinus Torvalds /* Form key to get parent of the left/right neighbor. */ 1127bd4c625cSLinus Torvalds le_key2cpu_key(&s_lr_father_key, 11284cf5f7adSJeff Mahoney internal_key(*pcom_father, 1129bd4c625cSLinus Torvalds (c_lr_par == 1130ee93961bSJeff Mahoney LEFT_PARENTS) ? (tb->lkey[h - 1] = 1131ee93961bSJeff Mahoney position - 1132ee93961bSJeff Mahoney 1) : (tb->rkey[h - 1133bd4c625cSLinus Torvalds 1] = 1134ee93961bSJeff Mahoney position))); 11351da177e4SLinus Torvalds 11361da177e4SLinus Torvalds if (c_lr_par == LEFT_PARENTS) 11371da177e4SLinus Torvalds decrement_key(&s_lr_father_key); 11381da177e4SLinus Torvalds 1139bd4c625cSLinus Torvalds if (search_by_key 1140a063ae17SJeff Mahoney (tb->tb_sb, &s_lr_father_key, &s_path_to_neighbor_father, 1141ee93961bSJeff Mahoney h + 1) == IO_ERROR) 1142098297b2SJeff Mahoney /* path is released */ 11431da177e4SLinus Torvalds return IO_ERROR; 11441da177e4SLinus Torvalds 1145a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) { 11463cd6dbe6SJeff Mahoney pathrelse(&s_path_to_neighbor_father); 1147d68caa95SJeff Mahoney brelse(*pcom_father); 11481da177e4SLinus Torvalds return REPEAT_SEARCH; 11491da177e4SLinus Torvalds } 11501da177e4SLinus Torvalds 1151d68caa95SJeff Mahoney *pfather = PATH_PLAST_BUFFER(&s_path_to_neighbor_father); 11521da177e4SLinus Torvalds 1153ee93961bSJeff Mahoney RFALSE(B_LEVEL(*pfather) != h + 1, 1154d68caa95SJeff Mahoney "PAP-8190: (%b %z) level too small", *pfather, *pfather); 1155bd4c625cSLinus Torvalds RFALSE(s_path_to_neighbor_father.path_length < 1156bd4c625cSLinus Torvalds FIRST_PATH_ELEMENT_OFFSET, "PAP-8192: path length is too small"); 11571da177e4SLinus Torvalds 11581da177e4SLinus Torvalds s_path_to_neighbor_father.path_length--; 11593cd6dbe6SJeff Mahoney pathrelse(&s_path_to_neighbor_father); 11601da177e4SLinus Torvalds return CARRY_ON; 11611da177e4SLinus Torvalds } 11621da177e4SLinus Torvalds 1163098297b2SJeff Mahoney /* 1164098297b2SJeff Mahoney * Get parents of neighbors of node in the path(S[path_offset]) and 1165098297b2SJeff Mahoney * common parents of S[path_offset] and L[path_offset]/R[path_offset]: 1166098297b2SJeff Mahoney * F[path_offset], FL[path_offset], FR[path_offset], CFL[path_offset], 1167098297b2SJeff Mahoney * CFR[path_offset]. 1168098297b2SJeff Mahoney * Calculate numbers of left and right delimiting keys position: 1169098297b2SJeff Mahoney * lkey[path_offset], rkey[path_offset]. 1170098297b2SJeff Mahoney * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked 1171098297b2SJeff Mahoney * CARRY_ON - schedule didn't occur while the function worked 11721da177e4SLinus Torvalds */ 1173ee93961bSJeff Mahoney static int get_parents(struct tree_balance *tb, int h) 11741da177e4SLinus Torvalds { 1175d68caa95SJeff Mahoney struct treepath *path = tb->tb_path; 1176ee93961bSJeff Mahoney int position, 1177ee93961bSJeff Mahoney ret, 1178ee93961bSJeff Mahoney path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h); 1179d68caa95SJeff Mahoney struct buffer_head *curf, *curcf; 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds /* Current node is the root of the tree or will be root of the tree */ 1182ee93961bSJeff Mahoney if (path_offset <= FIRST_PATH_ELEMENT_OFFSET) { 1183098297b2SJeff Mahoney /* 1184098297b2SJeff Mahoney * The root can not have parents. 1185098297b2SJeff Mahoney * Release nodes which previously were obtained as 1186098297b2SJeff Mahoney * parents of the current node neighbors. 1187098297b2SJeff Mahoney */ 1188ee93961bSJeff Mahoney brelse(tb->FL[h]); 1189ee93961bSJeff Mahoney brelse(tb->CFL[h]); 1190ee93961bSJeff Mahoney brelse(tb->FR[h]); 1191ee93961bSJeff Mahoney brelse(tb->CFR[h]); 1192ee93961bSJeff Mahoney tb->FL[h] = NULL; 1193ee93961bSJeff Mahoney tb->CFL[h] = NULL; 1194ee93961bSJeff Mahoney tb->FR[h] = NULL; 1195ee93961bSJeff Mahoney tb->CFR[h] = NULL; 11961da177e4SLinus Torvalds return CARRY_ON; 11971da177e4SLinus Torvalds } 11981da177e4SLinus Torvalds 1199ee93961bSJeff Mahoney /* Get parent FL[path_offset] of L[path_offset]. */ 1200ee93961bSJeff Mahoney position = PATH_OFFSET_POSITION(path, path_offset - 1); 1201ee93961bSJeff Mahoney if (position) { 12021da177e4SLinus Torvalds /* Current node is not the first child of its parent. */ 1203ee93961bSJeff Mahoney curf = PATH_OFFSET_PBUFFER(path, path_offset - 1); 1204ee93961bSJeff Mahoney curcf = PATH_OFFSET_PBUFFER(path, path_offset - 1); 1205d68caa95SJeff Mahoney get_bh(curf); 1206d68caa95SJeff Mahoney get_bh(curf); 1207ee93961bSJeff Mahoney tb->lkey[h] = position - 1; 1208bd4c625cSLinus Torvalds } else { 1209098297b2SJeff Mahoney /* 1210098297b2SJeff Mahoney * Calculate current parent of L[path_offset], which is the 1211098297b2SJeff Mahoney * left neighbor of the current node. Calculate current 1212098297b2SJeff Mahoney * common parent of L[path_offset] and the current node. 1213098297b2SJeff Mahoney * Note that CFL[path_offset] not equal FL[path_offset] and 1214098297b2SJeff Mahoney * CFL[path_offset] not equal F[path_offset]. 1215098297b2SJeff Mahoney * Calculate lkey[path_offset]. 1216098297b2SJeff Mahoney */ 1217ee93961bSJeff Mahoney if ((ret = get_far_parent(tb, h + 1, &curf, 1218d68caa95SJeff Mahoney &curcf, 1219bd4c625cSLinus Torvalds LEFT_PARENTS)) != CARRY_ON) 1220ee93961bSJeff Mahoney return ret; 12211da177e4SLinus Torvalds } 12221da177e4SLinus Torvalds 1223ee93961bSJeff Mahoney brelse(tb->FL[h]); 1224ee93961bSJeff Mahoney tb->FL[h] = curf; /* New initialization of FL[h]. */ 1225ee93961bSJeff Mahoney brelse(tb->CFL[h]); 1226ee93961bSJeff Mahoney tb->CFL[h] = curcf; /* New initialization of CFL[h]. */ 12271da177e4SLinus Torvalds 1228d68caa95SJeff Mahoney RFALSE((curf && !B_IS_IN_TREE(curf)) || 1229d68caa95SJeff Mahoney (curcf && !B_IS_IN_TREE(curcf)), 1230d68caa95SJeff Mahoney "PAP-8195: FL (%b) or CFL (%b) is invalid", curf, curcf); 12311da177e4SLinus Torvalds 1232ee93961bSJeff Mahoney /* Get parent FR[h] of R[h]. */ 12331da177e4SLinus Torvalds 1234ee93961bSJeff Mahoney /* Current node is the last child of F[h]. FR[h] != F[h]. */ 1235ee93961bSJeff Mahoney if (position == B_NR_ITEMS(PATH_H_PBUFFER(path, h + 1))) { 1236098297b2SJeff Mahoney /* 1237098297b2SJeff Mahoney * Calculate current parent of R[h], which is the right 1238098297b2SJeff Mahoney * neighbor of F[h]. Calculate current common parent of 1239098297b2SJeff Mahoney * R[h] and current node. Note that CFR[h] not equal 1240098297b2SJeff Mahoney * FR[path_offset] and CFR[h] not equal F[h]. 1241098297b2SJeff Mahoney */ 1242ee93961bSJeff Mahoney if ((ret = 1243ee93961bSJeff Mahoney get_far_parent(tb, h + 1, &curf, &curcf, 1244bd4c625cSLinus Torvalds RIGHT_PARENTS)) != CARRY_ON) 1245ee93961bSJeff Mahoney return ret; 1246bd4c625cSLinus Torvalds } else { 1247ee93961bSJeff Mahoney /* Current node is not the last child of its parent F[h]. */ 1248ee93961bSJeff Mahoney curf = PATH_OFFSET_PBUFFER(path, path_offset - 1); 1249ee93961bSJeff Mahoney curcf = PATH_OFFSET_PBUFFER(path, path_offset - 1); 1250d68caa95SJeff Mahoney get_bh(curf); 1251d68caa95SJeff Mahoney get_bh(curf); 1252ee93961bSJeff Mahoney tb->rkey[h] = position; 12531da177e4SLinus Torvalds } 12541da177e4SLinus Torvalds 1255ee93961bSJeff Mahoney brelse(tb->FR[h]); 1256ee93961bSJeff Mahoney /* New initialization of FR[path_offset]. */ 1257ee93961bSJeff Mahoney tb->FR[h] = curf; 12581da177e4SLinus Torvalds 1259ee93961bSJeff Mahoney brelse(tb->CFR[h]); 1260ee93961bSJeff Mahoney /* New initialization of CFR[path_offset]. */ 1261ee93961bSJeff Mahoney tb->CFR[h] = curcf; 12621da177e4SLinus Torvalds 1263d68caa95SJeff Mahoney RFALSE((curf && !B_IS_IN_TREE(curf)) || 1264d68caa95SJeff Mahoney (curcf && !B_IS_IN_TREE(curcf)), 1265d68caa95SJeff Mahoney "PAP-8205: FR (%b) or CFR (%b) is invalid", curf, curcf); 12661da177e4SLinus Torvalds 12671da177e4SLinus Torvalds return CARRY_ON; 12681da177e4SLinus Torvalds } 12691da177e4SLinus Torvalds 1270098297b2SJeff Mahoney /* 1271098297b2SJeff Mahoney * it is possible to remove node as result of shiftings to 1272098297b2SJeff Mahoney * neighbors even when we insert or paste item. 1273098297b2SJeff Mahoney */ 1274bd4c625cSLinus Torvalds static inline int can_node_be_removed(int mode, int lfree, int sfree, int rfree, 1275bd4c625cSLinus Torvalds struct tree_balance *tb, int h) 12761da177e4SLinus Torvalds { 12771da177e4SLinus Torvalds struct buffer_head *Sh = PATH_H_PBUFFER(tb->tb_path, h); 12781da177e4SLinus Torvalds int levbytes = tb->insert_size[h]; 12791da177e4SLinus Torvalds struct item_head *ih; 12801da177e4SLinus Torvalds struct reiserfs_key *r_key = NULL; 12811da177e4SLinus Torvalds 12824cf5f7adSJeff Mahoney ih = item_head(Sh, 0); 12831da177e4SLinus Torvalds if (tb->CFR[h]) 12844cf5f7adSJeff Mahoney r_key = internal_key(tb->CFR[h], tb->rkey[h]); 12851da177e4SLinus Torvalds 1286bd4c625cSLinus Torvalds if (lfree + rfree + sfree < MAX_CHILD_SIZE(Sh) + levbytes 12871da177e4SLinus Torvalds /* shifting may merge items which might save space */ 1288bd4c625cSLinus Torvalds - 1289bd4c625cSLinus Torvalds ((!h 1290bd4c625cSLinus Torvalds && op_is_left_mergeable(&(ih->ih_key), Sh->b_size)) ? IH_SIZE : 0) 1291bd4c625cSLinus Torvalds - 1292bd4c625cSLinus Torvalds ((!h && r_key 1293bd4c625cSLinus Torvalds && op_is_left_mergeable(r_key, Sh->b_size)) ? IH_SIZE : 0) 1294bd4c625cSLinus Torvalds + ((h) ? KEY_SIZE : 0)) { 12951da177e4SLinus Torvalds /* node can not be removed */ 1296098297b2SJeff Mahoney if (sfree >= levbytes) { 1297098297b2SJeff Mahoney /* new item fits into node S[h] without any shifting */ 12981da177e4SLinus Torvalds if (!h) 1299bd4c625cSLinus Torvalds tb->s0num = 1300bd4c625cSLinus Torvalds B_NR_ITEMS(Sh) + 1301bd4c625cSLinus Torvalds ((mode == M_INSERT) ? 1 : 0); 13021da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 13031da177e4SLinus Torvalds return NO_BALANCING_NEEDED; 13041da177e4SLinus Torvalds } 13051da177e4SLinus Torvalds } 13061da177e4SLinus Torvalds PROC_INFO_INC(tb->tb_sb, can_node_be_removed[h]); 13071da177e4SLinus Torvalds return !NO_BALANCING_NEEDED; 13081da177e4SLinus Torvalds } 13091da177e4SLinus Torvalds 1310098297b2SJeff Mahoney /* 1311098297b2SJeff Mahoney * Check whether current node S[h] is balanced when increasing its size by 13121da177e4SLinus Torvalds * Inserting or Pasting. 13131da177e4SLinus Torvalds * Calculate parameters for balancing for current level h. 13141da177e4SLinus Torvalds * Parameters: 13151da177e4SLinus Torvalds * tb tree_balance structure; 13161da177e4SLinus Torvalds * h current level of the node; 13171da177e4SLinus Torvalds * inum item number in S[h]; 13181da177e4SLinus Torvalds * mode i - insert, p - paste; 13191da177e4SLinus Torvalds * Returns: 1 - schedule occurred; 13201da177e4SLinus Torvalds * 0 - balancing for higher levels needed; 13211da177e4SLinus Torvalds * -1 - no balancing for higher levels needed; 13221da177e4SLinus Torvalds * -2 - no disk space. 13231da177e4SLinus Torvalds */ 13241da177e4SLinus Torvalds /* ip means Inserting or Pasting */ 13251da177e4SLinus Torvalds static int ip_check_balance(struct tree_balance *tb, int h) 13261da177e4SLinus Torvalds { 13271da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 1328098297b2SJeff Mahoney /* 1329098297b2SJeff Mahoney * Number of bytes that must be inserted into (value is negative 1330098297b2SJeff Mahoney * if bytes are deleted) buffer which contains node being balanced. 1331098297b2SJeff Mahoney * The mnemonic is that the attempted change in node space used 1332098297b2SJeff Mahoney * level is levbytes bytes. 1333098297b2SJeff Mahoney */ 1334098297b2SJeff Mahoney int levbytes; 1335098297b2SJeff Mahoney int ret; 13361da177e4SLinus Torvalds 13371da177e4SLinus Torvalds int lfree, sfree, rfree /* free space in L, S and R */ ; 13381da177e4SLinus Torvalds 1339098297b2SJeff Mahoney /* 1340098297b2SJeff Mahoney * nver is short for number of vertixes, and lnver is the number if 1341098297b2SJeff Mahoney * we shift to the left, rnver is the number if we shift to the 1342098297b2SJeff Mahoney * right, and lrnver is the number if we shift in both directions. 1343098297b2SJeff Mahoney * The goal is to minimize first the number of vertixes, and second, 1344098297b2SJeff Mahoney * the number of vertixes whose contents are changed by shifting, 1345098297b2SJeff Mahoney * and third the number of uncached vertixes whose contents are 1346098297b2SJeff Mahoney * changed by shifting and must be read from disk. 1347098297b2SJeff Mahoney */ 13481da177e4SLinus Torvalds int nver, lnver, rnver, lrnver; 13491da177e4SLinus Torvalds 1350098297b2SJeff Mahoney /* 1351098297b2SJeff Mahoney * used at leaf level only, S0 = S[0] is the node being balanced, 1352098297b2SJeff Mahoney * sInum [ I = 0,1,2 ] is the number of items that will 1353098297b2SJeff Mahoney * remain in node SI after balancing. S1 and S2 are new 1354098297b2SJeff Mahoney * nodes that might be created. 1355098297b2SJeff Mahoney */ 13561da177e4SLinus Torvalds 1357098297b2SJeff Mahoney /* 1358098297b2SJeff Mahoney * we perform 8 calls to get_num_ver(). For each call we 1359098297b2SJeff Mahoney * calculate five parameters. where 4th parameter is s1bytes 1360098297b2SJeff Mahoney * and 5th - s2bytes 1361098297b2SJeff Mahoney * 1362098297b2SJeff Mahoney * s0num, s1num, s2num for 8 cases 1363098297b2SJeff Mahoney * 0,1 - do not shift and do not shift but bottle 1364098297b2SJeff Mahoney * 2 - shift only whole item to left 1365098297b2SJeff Mahoney * 3 - shift to left and bottle as much as possible 1366098297b2SJeff Mahoney * 4,5 - shift to right (whole items and as much as possible 1367098297b2SJeff Mahoney * 6,7 - shift to both directions (whole items and as much as possible) 13681da177e4SLinus Torvalds */ 1369098297b2SJeff Mahoney short snum012[40] = { 0, }; 13701da177e4SLinus Torvalds 13711da177e4SLinus Torvalds /* Sh is the node whose balance is currently being checked */ 13721da177e4SLinus Torvalds struct buffer_head *Sh; 13731da177e4SLinus Torvalds 13741da177e4SLinus Torvalds Sh = PATH_H_PBUFFER(tb->tb_path, h); 13751da177e4SLinus Torvalds levbytes = tb->insert_size[h]; 13761da177e4SLinus Torvalds 13771da177e4SLinus Torvalds /* Calculate balance parameters for creating new root. */ 13781da177e4SLinus Torvalds if (!Sh) { 13791da177e4SLinus Torvalds if (!h) 1380c3a9c210SJeff Mahoney reiserfs_panic(tb->tb_sb, "vs-8210", 1381c3a9c210SJeff Mahoney "S[0] can not be 0"); 1382ee93961bSJeff Mahoney switch (ret = get_empty_nodes(tb, h)) { 1383098297b2SJeff Mahoney /* no balancing for higher levels needed */ 13841da177e4SLinus Torvalds case CARRY_ON: 13851da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 1386098297b2SJeff Mahoney return NO_BALANCING_NEEDED; 13871da177e4SLinus Torvalds 13881da177e4SLinus Torvalds case NO_DISK_SPACE: 13891da177e4SLinus Torvalds case REPEAT_SEARCH: 1390ee93961bSJeff Mahoney return ret; 13911da177e4SLinus Torvalds default: 1392c3a9c210SJeff Mahoney reiserfs_panic(tb->tb_sb, "vs-8215", "incorrect " 1393c3a9c210SJeff Mahoney "return value of get_empty_nodes"); 13941da177e4SLinus Torvalds } 13951da177e4SLinus Torvalds } 13961da177e4SLinus Torvalds 1397098297b2SJeff Mahoney /* get parents of S[h] neighbors. */ 1398098297b2SJeff Mahoney ret = get_parents(tb, h); 1399098297b2SJeff Mahoney if (ret != CARRY_ON) 1400ee93961bSJeff Mahoney return ret; 14011da177e4SLinus Torvalds 14021da177e4SLinus Torvalds sfree = B_FREE_SPACE(Sh); 14031da177e4SLinus Torvalds 14041da177e4SLinus Torvalds /* get free space of neighbors */ 14051da177e4SLinus Torvalds rfree = get_rfree(tb, h); 14061da177e4SLinus Torvalds lfree = get_lfree(tb, h); 14071da177e4SLinus Torvalds 1408098297b2SJeff Mahoney /* and new item fits into node S[h] without any shifting */ 1409bd4c625cSLinus Torvalds if (can_node_be_removed(vn->vn_mode, lfree, sfree, rfree, tb, h) == 1410bd4c625cSLinus Torvalds NO_BALANCING_NEEDED) 14111da177e4SLinus Torvalds return NO_BALANCING_NEEDED; 14121da177e4SLinus Torvalds 14131da177e4SLinus Torvalds create_virtual_node(tb, h); 14141da177e4SLinus Torvalds 14151da177e4SLinus Torvalds /* 1416098297b2SJeff Mahoney * determine maximal number of items we can shift to the left 1417098297b2SJeff Mahoney * neighbor (in tb structure) and the maximal number of bytes 1418098297b2SJeff Mahoney * that can flow to the left neighbor from the left most liquid 1419098297b2SJeff Mahoney * item that cannot be shifted from S[0] entirely (returned value) 14201da177e4SLinus Torvalds */ 14211da177e4SLinus Torvalds check_left(tb, h, lfree); 14221da177e4SLinus Torvalds 14231da177e4SLinus Torvalds /* 1424098297b2SJeff Mahoney * determine maximal number of items we can shift to the right 1425098297b2SJeff Mahoney * neighbor (in tb structure) and the maximal number of bytes 1426098297b2SJeff Mahoney * that can flow to the right neighbor from the right most liquid 1427098297b2SJeff Mahoney * item that cannot be shifted from S[0] entirely (returned value) 14281da177e4SLinus Torvalds */ 14291da177e4SLinus Torvalds check_right(tb, h, rfree); 14301da177e4SLinus Torvalds 1431098297b2SJeff Mahoney /* 1432098297b2SJeff Mahoney * all contents of internal node S[h] can be moved into its 1433098297b2SJeff Mahoney * neighbors, S[h] will be removed after balancing 1434098297b2SJeff Mahoney */ 14351da177e4SLinus Torvalds if (h && (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1)) { 14361da177e4SLinus Torvalds int to_r; 14371da177e4SLinus Torvalds 1438098297b2SJeff Mahoney /* 1439098297b2SJeff Mahoney * Since we are working on internal nodes, and our internal 1440098297b2SJeff Mahoney * nodes have fixed size entries, then we can balance by the 1441098297b2SJeff Mahoney * number of items rather than the space they consume. In this 1442098297b2SJeff Mahoney * routine we set the left node equal to the right node, 1443098297b2SJeff Mahoney * allowing a difference of less than or equal to 1 child 1444098297b2SJeff Mahoney * pointer. 1445098297b2SJeff Mahoney */ 1446bd4c625cSLinus Torvalds to_r = 1447bd4c625cSLinus Torvalds ((MAX_NR_KEY(Sh) << 1) + 2 - tb->lnum[h] - tb->rnum[h] + 1448bd4c625cSLinus Torvalds vn->vn_nr_item + 1) / 2 - (MAX_NR_KEY(Sh) + 1 - 1449bd4c625cSLinus Torvalds tb->rnum[h]); 1450bd4c625cSLinus Torvalds set_parameters(tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, 1451bd4c625cSLinus Torvalds -1, -1); 14521da177e4SLinus Torvalds return CARRY_ON; 14531da177e4SLinus Torvalds } 14541da177e4SLinus Torvalds 1455098297b2SJeff Mahoney /* 1456098297b2SJeff Mahoney * this checks balance condition, that any two neighboring nodes 1457098297b2SJeff Mahoney * can not fit in one node 1458098297b2SJeff Mahoney */ 14591da177e4SLinus Torvalds RFALSE(h && 14601da177e4SLinus Torvalds (tb->lnum[h] >= vn->vn_nr_item + 1 || 14611da177e4SLinus Torvalds tb->rnum[h] >= vn->vn_nr_item + 1), 14621da177e4SLinus Torvalds "vs-8220: tree is not balanced on internal level"); 14631da177e4SLinus Torvalds RFALSE(!h && ((tb->lnum[h] >= vn->vn_nr_item && (tb->lbytes == -1)) || 14641da177e4SLinus Torvalds (tb->rnum[h] >= vn->vn_nr_item && (tb->rbytes == -1))), 14651da177e4SLinus Torvalds "vs-8225: tree is not balanced on leaf level"); 14661da177e4SLinus Torvalds 1467098297b2SJeff Mahoney /* 1468098297b2SJeff Mahoney * all contents of S[0] can be moved into its neighbors 1469098297b2SJeff Mahoney * S[0] will be removed after balancing. 1470098297b2SJeff Mahoney */ 14711da177e4SLinus Torvalds if (!h && is_leaf_removable(tb)) 14721da177e4SLinus Torvalds return CARRY_ON; 14731da177e4SLinus Torvalds 1474098297b2SJeff Mahoney /* 1475098297b2SJeff Mahoney * why do we perform this check here rather than earlier?? 1476098297b2SJeff Mahoney * Answer: we can win 1 node in some cases above. Moreover we 1477098297b2SJeff Mahoney * checked it above, when we checked, that S[0] is not removable 1478098297b2SJeff Mahoney * in principle 1479098297b2SJeff Mahoney */ 1480098297b2SJeff Mahoney 1481098297b2SJeff Mahoney /* new item fits into node S[h] without any shifting */ 1482098297b2SJeff Mahoney if (sfree >= levbytes) { 14831da177e4SLinus Torvalds if (!h) 14841da177e4SLinus Torvalds tb->s0num = vn->vn_nr_item; 14851da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 14861da177e4SLinus Torvalds return NO_BALANCING_NEEDED; 14871da177e4SLinus Torvalds } 14881da177e4SLinus Torvalds 14891da177e4SLinus Torvalds { 14901da177e4SLinus Torvalds int lpar, rpar, nset, lset, rset, lrset; 1491098297b2SJeff Mahoney /* regular overflowing of the node */ 14921da177e4SLinus Torvalds 1493098297b2SJeff Mahoney /* 1494098297b2SJeff Mahoney * get_num_ver works in 2 modes (FLOW & NO_FLOW) 1495098297b2SJeff Mahoney * lpar, rpar - number of items we can shift to left/right 1496098297b2SJeff Mahoney * neighbor (including splitting item) 1497098297b2SJeff Mahoney * nset, lset, rset, lrset - shows, whether flowing items 1498098297b2SJeff Mahoney * give better packing 14991da177e4SLinus Torvalds */ 15001da177e4SLinus Torvalds #define FLOW 1 15011da177e4SLinus Torvalds #define NO_FLOW 0 /* do not any splitting */ 15021da177e4SLinus Torvalds 1503098297b2SJeff Mahoney /* we choose one of the following */ 15041da177e4SLinus Torvalds #define NOTHING_SHIFT_NO_FLOW 0 15051da177e4SLinus Torvalds #define NOTHING_SHIFT_FLOW 5 15061da177e4SLinus Torvalds #define LEFT_SHIFT_NO_FLOW 10 15071da177e4SLinus Torvalds #define LEFT_SHIFT_FLOW 15 15081da177e4SLinus Torvalds #define RIGHT_SHIFT_NO_FLOW 20 15091da177e4SLinus Torvalds #define RIGHT_SHIFT_FLOW 25 15101da177e4SLinus Torvalds #define LR_SHIFT_NO_FLOW 30 15111da177e4SLinus Torvalds #define LR_SHIFT_FLOW 35 15121da177e4SLinus Torvalds 15131da177e4SLinus Torvalds lpar = tb->lnum[h]; 15141da177e4SLinus Torvalds rpar = tb->rnum[h]; 15151da177e4SLinus Torvalds 1516098297b2SJeff Mahoney /* 1517098297b2SJeff Mahoney * calculate number of blocks S[h] must be split into when 1518098297b2SJeff Mahoney * nothing is shifted to the neighbors, as well as number of 1519098297b2SJeff Mahoney * items in each part of the split node (s012 numbers), 1520098297b2SJeff Mahoney * and number of bytes (s1bytes) of the shared drop which 1521098297b2SJeff Mahoney * flow to S1 if any 1522098297b2SJeff Mahoney */ 15231da177e4SLinus Torvalds nset = NOTHING_SHIFT_NO_FLOW; 15241da177e4SLinus Torvalds nver = get_num_ver(vn->vn_mode, tb, h, 15251da177e4SLinus Torvalds 0, -1, h ? vn->vn_nr_item : 0, -1, 15261da177e4SLinus Torvalds snum012, NO_FLOW); 15271da177e4SLinus Torvalds 1528bd4c625cSLinus Torvalds if (!h) { 15291da177e4SLinus Torvalds int nver1; 15301da177e4SLinus Torvalds 1531098297b2SJeff Mahoney /* 1532098297b2SJeff Mahoney * note, that in this case we try to bottle 1533098297b2SJeff Mahoney * between S[0] and S1 (S1 - the first new node) 1534098297b2SJeff Mahoney */ 15351da177e4SLinus Torvalds nver1 = get_num_ver(vn->vn_mode, tb, h, 15361da177e4SLinus Torvalds 0, -1, 0, -1, 15371da177e4SLinus Torvalds snum012 + NOTHING_SHIFT_FLOW, FLOW); 15381da177e4SLinus Torvalds if (nver > nver1) 15391da177e4SLinus Torvalds nset = NOTHING_SHIFT_FLOW, nver = nver1; 15401da177e4SLinus Torvalds } 15411da177e4SLinus Torvalds 1542098297b2SJeff Mahoney /* 1543098297b2SJeff Mahoney * calculate number of blocks S[h] must be split into when 1544098297b2SJeff Mahoney * l_shift_num first items and l_shift_bytes of the right 1545098297b2SJeff Mahoney * most liquid item to be shifted are shifted to the left 1546098297b2SJeff Mahoney * neighbor, as well as number of items in each part of the 1547098297b2SJeff Mahoney * splitted node (s012 numbers), and number of bytes 1548098297b2SJeff Mahoney * (s1bytes) of the shared drop which flow to S1 if any 15491da177e4SLinus Torvalds */ 15501da177e4SLinus Torvalds lset = LEFT_SHIFT_NO_FLOW; 15511da177e4SLinus Torvalds lnver = get_num_ver(vn->vn_mode, tb, h, 1552bd4c625cSLinus Torvalds lpar - ((h || tb->lbytes == -1) ? 0 : 1), 1553bd4c625cSLinus Torvalds -1, h ? vn->vn_nr_item : 0, -1, 15541da177e4SLinus Torvalds snum012 + LEFT_SHIFT_NO_FLOW, NO_FLOW); 1555bd4c625cSLinus Torvalds if (!h) { 15561da177e4SLinus Torvalds int lnver1; 15571da177e4SLinus Torvalds 15581da177e4SLinus Torvalds lnver1 = get_num_ver(vn->vn_mode, tb, h, 1559bd4c625cSLinus Torvalds lpar - 1560bd4c625cSLinus Torvalds ((tb->lbytes != -1) ? 1 : 0), 1561bd4c625cSLinus Torvalds tb->lbytes, 0, -1, 15621da177e4SLinus Torvalds snum012 + LEFT_SHIFT_FLOW, FLOW); 15631da177e4SLinus Torvalds if (lnver > lnver1) 15641da177e4SLinus Torvalds lset = LEFT_SHIFT_FLOW, lnver = lnver1; 15651da177e4SLinus Torvalds } 15661da177e4SLinus Torvalds 1567098297b2SJeff Mahoney /* 1568098297b2SJeff Mahoney * calculate number of blocks S[h] must be split into when 1569098297b2SJeff Mahoney * r_shift_num first items and r_shift_bytes of the left most 1570098297b2SJeff Mahoney * liquid item to be shifted are shifted to the right neighbor, 1571098297b2SJeff Mahoney * as well as number of items in each part of the splitted 1572098297b2SJeff Mahoney * node (s012 numbers), and number of bytes (s1bytes) of the 1573098297b2SJeff Mahoney * shared drop which flow to S1 if any 15741da177e4SLinus Torvalds */ 15751da177e4SLinus Torvalds rset = RIGHT_SHIFT_NO_FLOW; 15761da177e4SLinus Torvalds rnver = get_num_ver(vn->vn_mode, tb, h, 1577bd4c625cSLinus Torvalds 0, -1, 1578bd4c625cSLinus Torvalds h ? (vn->vn_nr_item - rpar) : (rpar - 1579bd4c625cSLinus Torvalds ((tb-> 1580bd4c625cSLinus Torvalds rbytes != 1581bd4c625cSLinus Torvalds -1) ? 1 : 1582bd4c625cSLinus Torvalds 0)), -1, 15831da177e4SLinus Torvalds snum012 + RIGHT_SHIFT_NO_FLOW, NO_FLOW); 1584bd4c625cSLinus Torvalds if (!h) { 15851da177e4SLinus Torvalds int rnver1; 15861da177e4SLinus Torvalds 15871da177e4SLinus Torvalds rnver1 = get_num_ver(vn->vn_mode, tb, h, 1588bd4c625cSLinus Torvalds 0, -1, 1589bd4c625cSLinus Torvalds (rpar - 1590bd4c625cSLinus Torvalds ((tb->rbytes != -1) ? 1 : 0)), 1591bd4c625cSLinus Torvalds tb->rbytes, 15921da177e4SLinus Torvalds snum012 + RIGHT_SHIFT_FLOW, FLOW); 15931da177e4SLinus Torvalds 15941da177e4SLinus Torvalds if (rnver > rnver1) 15951da177e4SLinus Torvalds rset = RIGHT_SHIFT_FLOW, rnver = rnver1; 15961da177e4SLinus Torvalds } 15971da177e4SLinus Torvalds 1598098297b2SJeff Mahoney /* 1599098297b2SJeff Mahoney * calculate number of blocks S[h] must be split into when 1600098297b2SJeff Mahoney * items are shifted in both directions, as well as number 1601098297b2SJeff Mahoney * of items in each part of the splitted node (s012 numbers), 1602098297b2SJeff Mahoney * and number of bytes (s1bytes) of the shared drop which 1603098297b2SJeff Mahoney * flow to S1 if any 16041da177e4SLinus Torvalds */ 16051da177e4SLinus Torvalds lrset = LR_SHIFT_NO_FLOW; 16061da177e4SLinus Torvalds lrnver = get_num_ver(vn->vn_mode, tb, h, 1607bd4c625cSLinus Torvalds lpar - ((h || tb->lbytes == -1) ? 0 : 1), 1608bd4c625cSLinus Torvalds -1, 1609bd4c625cSLinus Torvalds h ? (vn->vn_nr_item - rpar) : (rpar - 1610bd4c625cSLinus Torvalds ((tb-> 1611bd4c625cSLinus Torvalds rbytes != 1612bd4c625cSLinus Torvalds -1) ? 1 : 1613bd4c625cSLinus Torvalds 0)), -1, 16141da177e4SLinus Torvalds snum012 + LR_SHIFT_NO_FLOW, NO_FLOW); 1615bd4c625cSLinus Torvalds if (!h) { 16161da177e4SLinus Torvalds int lrnver1; 16171da177e4SLinus Torvalds 16181da177e4SLinus Torvalds lrnver1 = get_num_ver(vn->vn_mode, tb, h, 1619bd4c625cSLinus Torvalds lpar - 1620bd4c625cSLinus Torvalds ((tb->lbytes != -1) ? 1 : 0), 1621bd4c625cSLinus Torvalds tb->lbytes, 1622bd4c625cSLinus Torvalds (rpar - 1623bd4c625cSLinus Torvalds ((tb->rbytes != -1) ? 1 : 0)), 1624bd4c625cSLinus Torvalds tb->rbytes, 16251da177e4SLinus Torvalds snum012 + LR_SHIFT_FLOW, FLOW); 16261da177e4SLinus Torvalds if (lrnver > lrnver1) 16271da177e4SLinus Torvalds lrset = LR_SHIFT_FLOW, lrnver = lrnver1; 16281da177e4SLinus Torvalds } 16291da177e4SLinus Torvalds 1630098297b2SJeff Mahoney /* 1631098297b2SJeff Mahoney * Our general shifting strategy is: 1632098297b2SJeff Mahoney * 1) to minimized number of new nodes; 1633098297b2SJeff Mahoney * 2) to minimized number of neighbors involved in shifting; 1634098297b2SJeff Mahoney * 3) to minimized number of disk reads; 1635098297b2SJeff Mahoney */ 16361da177e4SLinus Torvalds 16371da177e4SLinus Torvalds /* we can win TWO or ONE nodes by shifting in both directions */ 1638bd4c625cSLinus Torvalds if (lrnver < lnver && lrnver < rnver) { 16391da177e4SLinus Torvalds RFALSE(h && 16401da177e4SLinus Torvalds (tb->lnum[h] != 1 || 16411da177e4SLinus Torvalds tb->rnum[h] != 1 || 1642bd4c625cSLinus Torvalds lrnver != 1 || rnver != 2 || lnver != 2 1643bd4c625cSLinus Torvalds || h != 1), "vs-8230: bad h"); 16441da177e4SLinus Torvalds if (lrset == LR_SHIFT_FLOW) 1645bd4c625cSLinus Torvalds set_parameters(tb, h, tb->lnum[h], tb->rnum[h], 1646bd4c625cSLinus Torvalds lrnver, snum012 + lrset, 16471da177e4SLinus Torvalds tb->lbytes, tb->rbytes); 16481da177e4SLinus Torvalds else 1649bd4c625cSLinus Torvalds set_parameters(tb, h, 1650bd4c625cSLinus Torvalds tb->lnum[h] - 1651bd4c625cSLinus Torvalds ((tb->lbytes == -1) ? 0 : 1), 1652bd4c625cSLinus Torvalds tb->rnum[h] - 1653bd4c625cSLinus Torvalds ((tb->rbytes == -1) ? 0 : 1), 1654bd4c625cSLinus Torvalds lrnver, snum012 + lrset, -1, -1); 16551da177e4SLinus Torvalds 16561da177e4SLinus Torvalds return CARRY_ON; 16571da177e4SLinus Torvalds } 16581da177e4SLinus Torvalds 1659098297b2SJeff Mahoney /* 1660098297b2SJeff Mahoney * if shifting doesn't lead to better packing 1661098297b2SJeff Mahoney * then don't shift 1662098297b2SJeff Mahoney */ 1663bd4c625cSLinus Torvalds if (nver == lrnver) { 1664bd4c625cSLinus Torvalds set_parameters(tb, h, 0, 0, nver, snum012 + nset, -1, 1665bd4c625cSLinus Torvalds -1); 16661da177e4SLinus Torvalds return CARRY_ON; 16671da177e4SLinus Torvalds } 16681da177e4SLinus Torvalds 1669098297b2SJeff Mahoney /* 1670098297b2SJeff Mahoney * now we know that for better packing shifting in only one 1671098297b2SJeff Mahoney * direction either to the left or to the right is required 1672098297b2SJeff Mahoney */ 16731da177e4SLinus Torvalds 1674098297b2SJeff Mahoney /* 1675098297b2SJeff Mahoney * if shifting to the left is better than 1676098297b2SJeff Mahoney * shifting to the right 1677098297b2SJeff Mahoney */ 1678bd4c625cSLinus Torvalds if (lnver < rnver) { 16791da177e4SLinus Torvalds SET_PAR_SHIFT_LEFT; 16801da177e4SLinus Torvalds return CARRY_ON; 16811da177e4SLinus Torvalds } 16821da177e4SLinus Torvalds 1683098297b2SJeff Mahoney /* 1684098297b2SJeff Mahoney * if shifting to the right is better than 1685098297b2SJeff Mahoney * shifting to the left 1686098297b2SJeff Mahoney */ 1687bd4c625cSLinus Torvalds if (lnver > rnver) { 16881da177e4SLinus Torvalds SET_PAR_SHIFT_RIGHT; 16891da177e4SLinus Torvalds return CARRY_ON; 16901da177e4SLinus Torvalds } 16911da177e4SLinus Torvalds 1692098297b2SJeff Mahoney /* 1693098297b2SJeff Mahoney * now shifting in either direction gives the same number 1694098297b2SJeff Mahoney * of nodes and we can make use of the cached neighbors 1695098297b2SJeff Mahoney */ 1696bd4c625cSLinus Torvalds if (is_left_neighbor_in_cache(tb, h)) { 16971da177e4SLinus Torvalds SET_PAR_SHIFT_LEFT; 16981da177e4SLinus Torvalds return CARRY_ON; 16991da177e4SLinus Torvalds } 17001da177e4SLinus Torvalds 1701098297b2SJeff Mahoney /* 1702098297b2SJeff Mahoney * shift to the right independently on whether the 1703098297b2SJeff Mahoney * right neighbor in cache or not 1704098297b2SJeff Mahoney */ 17051da177e4SLinus Torvalds SET_PAR_SHIFT_RIGHT; 17061da177e4SLinus Torvalds return CARRY_ON; 17071da177e4SLinus Torvalds } 17081da177e4SLinus Torvalds } 17091da177e4SLinus Torvalds 1710098297b2SJeff Mahoney /* 1711098297b2SJeff Mahoney * Check whether current node S[h] is balanced when Decreasing its size by 17121da177e4SLinus Torvalds * Deleting or Cutting for INTERNAL node of S+tree. 17131da177e4SLinus Torvalds * Calculate parameters for balancing for current level h. 17141da177e4SLinus Torvalds * Parameters: 17151da177e4SLinus Torvalds * tb tree_balance structure; 17161da177e4SLinus Torvalds * h current level of the node; 17171da177e4SLinus Torvalds * inum item number in S[h]; 17181da177e4SLinus Torvalds * mode i - insert, p - paste; 17191da177e4SLinus Torvalds * Returns: 1 - schedule occurred; 17201da177e4SLinus Torvalds * 0 - balancing for higher levels needed; 17211da177e4SLinus Torvalds * -1 - no balancing for higher levels needed; 17221da177e4SLinus Torvalds * -2 - no disk space. 17231da177e4SLinus Torvalds * 17241da177e4SLinus Torvalds * Note: Items of internal nodes have fixed size, so the balance condition for 17251da177e4SLinus Torvalds * the internal part of S+tree is as for the B-trees. 17261da177e4SLinus Torvalds */ 17271da177e4SLinus Torvalds static int dc_check_balance_internal(struct tree_balance *tb, int h) 17281da177e4SLinus Torvalds { 17291da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 17301da177e4SLinus Torvalds 1731098297b2SJeff Mahoney /* 1732098297b2SJeff Mahoney * Sh is the node whose balance is currently being checked, 1733098297b2SJeff Mahoney * and Fh is its father. 1734098297b2SJeff Mahoney */ 17351da177e4SLinus Torvalds struct buffer_head *Sh, *Fh; 1736ee93961bSJeff Mahoney int maxsize, ret; 17371da177e4SLinus Torvalds int lfree, rfree /* free space in L and R */ ; 17381da177e4SLinus Torvalds 17391da177e4SLinus Torvalds Sh = PATH_H_PBUFFER(tb->tb_path, h); 17401da177e4SLinus Torvalds Fh = PATH_H_PPARENT(tb->tb_path, h); 17411da177e4SLinus Torvalds 17421da177e4SLinus Torvalds maxsize = MAX_CHILD_SIZE(Sh); 17431da177e4SLinus Torvalds 1744098297b2SJeff Mahoney /* 1745098297b2SJeff Mahoney * using tb->insert_size[h], which is negative in this case, 1746098297b2SJeff Mahoney * create_virtual_node calculates: 1747098297b2SJeff Mahoney * new_nr_item = number of items node would have if operation is 1748098297b2SJeff Mahoney * performed without balancing (new_nr_item); 1749098297b2SJeff Mahoney */ 17501da177e4SLinus Torvalds create_virtual_node(tb, h); 17511da177e4SLinus Torvalds 1752bd4c625cSLinus Torvalds if (!Fh) { /* S[h] is the root. */ 1753098297b2SJeff Mahoney /* no balancing for higher levels needed */ 1754bd4c625cSLinus Torvalds if (vn->vn_nr_item > 0) { 17551da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 1756098297b2SJeff Mahoney return NO_BALANCING_NEEDED; 17571da177e4SLinus Torvalds } 1758098297b2SJeff Mahoney /* 1759098297b2SJeff Mahoney * new_nr_item == 0. 17601da177e4SLinus Torvalds * Current root will be deleted resulting in 1761098297b2SJeff Mahoney * decrementing the tree height. 1762098297b2SJeff Mahoney */ 17631da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 0, NULL, -1, -1); 17641da177e4SLinus Torvalds return CARRY_ON; 17651da177e4SLinus Torvalds } 17661da177e4SLinus Torvalds 1767ee93961bSJeff Mahoney if ((ret = get_parents(tb, h)) != CARRY_ON) 1768ee93961bSJeff Mahoney return ret; 17691da177e4SLinus Torvalds 17701da177e4SLinus Torvalds /* get free space of neighbors */ 17711da177e4SLinus Torvalds rfree = get_rfree(tb, h); 17721da177e4SLinus Torvalds lfree = get_lfree(tb, h); 17731da177e4SLinus Torvalds 17741da177e4SLinus Torvalds /* determine maximal number of items we can fit into neighbors */ 17751da177e4SLinus Torvalds check_left(tb, h, lfree); 17761da177e4SLinus Torvalds check_right(tb, h, rfree); 17771da177e4SLinus Torvalds 1778098297b2SJeff Mahoney /* 1779098297b2SJeff Mahoney * Balance condition for the internal node is valid. 1780098297b2SJeff Mahoney * In this case we balance only if it leads to better packing. 1781098297b2SJeff Mahoney */ 1782098297b2SJeff Mahoney if (vn->vn_nr_item >= MIN_NR_KEY(Sh)) { 1783098297b2SJeff Mahoney /* 1784098297b2SJeff Mahoney * Here we join S[h] with one of its neighbors, 1785098297b2SJeff Mahoney * which is impossible with greater values of new_nr_item. 1786098297b2SJeff Mahoney */ 1787098297b2SJeff Mahoney if (vn->vn_nr_item == MIN_NR_KEY(Sh)) { 17881da177e4SLinus Torvalds /* All contents of S[h] can be moved to L[h]. */ 1789098297b2SJeff Mahoney if (tb->lnum[h] >= vn->vn_nr_item + 1) { 17901da177e4SLinus Torvalds int n; 17911da177e4SLinus Torvalds int order_L; 17921da177e4SLinus Torvalds 1793bd4c625cSLinus Torvalds order_L = 1794bd4c625cSLinus Torvalds ((n = 1795bd4c625cSLinus Torvalds PATH_H_B_ITEM_ORDER(tb->tb_path, 1796bd4c625cSLinus Torvalds h)) == 1797bd4c625cSLinus Torvalds 0) ? B_NR_ITEMS(tb->FL[h]) : n - 1; 1798bd4c625cSLinus Torvalds n = dc_size(B_N_CHILD(tb->FL[h], order_L)) / 1799bd4c625cSLinus Torvalds (DC_SIZE + KEY_SIZE); 1800bd4c625cSLinus Torvalds set_parameters(tb, h, -n - 1, 0, 0, NULL, -1, 1801bd4c625cSLinus Torvalds -1); 18021da177e4SLinus Torvalds return CARRY_ON; 18031da177e4SLinus Torvalds } 18041da177e4SLinus Torvalds 18051da177e4SLinus Torvalds /* All contents of S[h] can be moved to R[h]. */ 1806098297b2SJeff Mahoney if (tb->rnum[h] >= vn->vn_nr_item + 1) { 18071da177e4SLinus Torvalds int n; 18081da177e4SLinus Torvalds int order_R; 18091da177e4SLinus Torvalds 1810bd4c625cSLinus Torvalds order_R = 1811bd4c625cSLinus Torvalds ((n = 1812bd4c625cSLinus Torvalds PATH_H_B_ITEM_ORDER(tb->tb_path, 1813bd4c625cSLinus Torvalds h)) == 1814bd4c625cSLinus Torvalds B_NR_ITEMS(Fh)) ? 0 : n + 1; 1815bd4c625cSLinus Torvalds n = dc_size(B_N_CHILD(tb->FR[h], order_R)) / 1816bd4c625cSLinus Torvalds (DC_SIZE + KEY_SIZE); 1817bd4c625cSLinus Torvalds set_parameters(tb, h, 0, -n - 1, 0, NULL, -1, 1818bd4c625cSLinus Torvalds -1); 18191da177e4SLinus Torvalds return CARRY_ON; 18201da177e4SLinus Torvalds } 18211da177e4SLinus Torvalds } 18221da177e4SLinus Torvalds 1823098297b2SJeff Mahoney /* 1824098297b2SJeff Mahoney * All contents of S[h] can be moved to the neighbors 1825098297b2SJeff Mahoney * (L[h] & R[h]). 1826098297b2SJeff Mahoney */ 1827bd4c625cSLinus Torvalds if (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1) { 18281da177e4SLinus Torvalds int to_r; 18291da177e4SLinus Torvalds 1830bd4c625cSLinus Torvalds to_r = 1831bd4c625cSLinus Torvalds ((MAX_NR_KEY(Sh) << 1) + 2 - tb->lnum[h] - 1832bd4c625cSLinus Torvalds tb->rnum[h] + vn->vn_nr_item + 1) / 2 - 18331da177e4SLinus Torvalds (MAX_NR_KEY(Sh) + 1 - tb->rnum[h]); 1834bd4c625cSLinus Torvalds set_parameters(tb, h, vn->vn_nr_item + 1 - to_r, to_r, 1835bd4c625cSLinus Torvalds 0, NULL, -1, -1); 18361da177e4SLinus Torvalds return CARRY_ON; 18371da177e4SLinus Torvalds } 18381da177e4SLinus Torvalds 18391da177e4SLinus Torvalds /* Balancing does not lead to better packing. */ 18401da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 18411da177e4SLinus Torvalds return NO_BALANCING_NEEDED; 18421da177e4SLinus Torvalds } 18431da177e4SLinus Torvalds 1844098297b2SJeff Mahoney /* 1845098297b2SJeff Mahoney * Current node contain insufficient number of items. 1846098297b2SJeff Mahoney * Balancing is required. 1847098297b2SJeff Mahoney */ 18481da177e4SLinus Torvalds /* Check whether we can merge S[h] with left neighbor. */ 18491da177e4SLinus Torvalds if (tb->lnum[h] >= vn->vn_nr_item + 1) 1850bd4c625cSLinus Torvalds if (is_left_neighbor_in_cache(tb, h) 1851bd4c625cSLinus Torvalds || tb->rnum[h] < vn->vn_nr_item + 1 || !tb->FR[h]) { 18521da177e4SLinus Torvalds int n; 18531da177e4SLinus Torvalds int order_L; 18541da177e4SLinus Torvalds 1855bd4c625cSLinus Torvalds order_L = 1856bd4c625cSLinus Torvalds ((n = 1857bd4c625cSLinus Torvalds PATH_H_B_ITEM_ORDER(tb->tb_path, 1858bd4c625cSLinus Torvalds h)) == 1859bd4c625cSLinus Torvalds 0) ? B_NR_ITEMS(tb->FL[h]) : n - 1; 1860bd4c625cSLinus Torvalds n = dc_size(B_N_CHILD(tb->FL[h], order_L)) / (DC_SIZE + 1861bd4c625cSLinus Torvalds KEY_SIZE); 18621da177e4SLinus Torvalds set_parameters(tb, h, -n - 1, 0, 0, NULL, -1, -1); 18631da177e4SLinus Torvalds return CARRY_ON; 18641da177e4SLinus Torvalds } 18651da177e4SLinus Torvalds 18661da177e4SLinus Torvalds /* Check whether we can merge S[h] with right neighbor. */ 1867bd4c625cSLinus Torvalds if (tb->rnum[h] >= vn->vn_nr_item + 1) { 18681da177e4SLinus Torvalds int n; 18691da177e4SLinus Torvalds int order_R; 18701da177e4SLinus Torvalds 1871bd4c625cSLinus Torvalds order_R = 1872bd4c625cSLinus Torvalds ((n = 1873bd4c625cSLinus Torvalds PATH_H_B_ITEM_ORDER(tb->tb_path, 1874bd4c625cSLinus Torvalds h)) == B_NR_ITEMS(Fh)) ? 0 : (n + 1); 1875bd4c625cSLinus Torvalds n = dc_size(B_N_CHILD(tb->FR[h], order_R)) / (DC_SIZE + 1876bd4c625cSLinus Torvalds KEY_SIZE); 18771da177e4SLinus Torvalds set_parameters(tb, h, 0, -n - 1, 0, NULL, -1, -1); 18781da177e4SLinus Torvalds return CARRY_ON; 18791da177e4SLinus Torvalds } 18801da177e4SLinus Torvalds 18811da177e4SLinus Torvalds /* All contents of S[h] can be moved to the neighbors (L[h] & R[h]). */ 1882bd4c625cSLinus Torvalds if (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1) { 18831da177e4SLinus Torvalds int to_r; 18841da177e4SLinus Torvalds 1885bd4c625cSLinus Torvalds to_r = 1886bd4c625cSLinus Torvalds ((MAX_NR_KEY(Sh) << 1) + 2 - tb->lnum[h] - tb->rnum[h] + 1887bd4c625cSLinus Torvalds vn->vn_nr_item + 1) / 2 - (MAX_NR_KEY(Sh) + 1 - 1888bd4c625cSLinus Torvalds tb->rnum[h]); 1889bd4c625cSLinus Torvalds set_parameters(tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, 1890bd4c625cSLinus Torvalds -1, -1); 18911da177e4SLinus Torvalds return CARRY_ON; 18921da177e4SLinus Torvalds } 18931da177e4SLinus Torvalds 18941da177e4SLinus Torvalds /* For internal nodes try to borrow item from a neighbor */ 18951da177e4SLinus Torvalds RFALSE(!tb->FL[h] && !tb->FR[h], "vs-8235: trying to borrow for root"); 18961da177e4SLinus Torvalds 18971da177e4SLinus Torvalds /* Borrow one or two items from caching neighbor */ 1898bd4c625cSLinus Torvalds if (is_left_neighbor_in_cache(tb, h) || !tb->FR[h]) { 18991da177e4SLinus Torvalds int from_l; 19001da177e4SLinus Torvalds 1901bd4c625cSLinus Torvalds from_l = 1902bd4c625cSLinus Torvalds (MAX_NR_KEY(Sh) + 1 - tb->lnum[h] + vn->vn_nr_item + 1903bd4c625cSLinus Torvalds 1) / 2 - (vn->vn_nr_item + 1); 19041da177e4SLinus Torvalds set_parameters(tb, h, -from_l, 0, 1, NULL, -1, -1); 19051da177e4SLinus Torvalds return CARRY_ON; 19061da177e4SLinus Torvalds } 19071da177e4SLinus Torvalds 1908bd4c625cSLinus Torvalds set_parameters(tb, h, 0, 1909bd4c625cSLinus Torvalds -((MAX_NR_KEY(Sh) + 1 - tb->rnum[h] + vn->vn_nr_item + 1910bd4c625cSLinus Torvalds 1) / 2 - (vn->vn_nr_item + 1)), 1, NULL, -1, -1); 19111da177e4SLinus Torvalds return CARRY_ON; 19121da177e4SLinus Torvalds } 19131da177e4SLinus Torvalds 1914098297b2SJeff Mahoney /* 1915098297b2SJeff Mahoney * Check whether current node S[h] is balanced when Decreasing its size by 19161da177e4SLinus Torvalds * Deleting or Truncating for LEAF node of S+tree. 19171da177e4SLinus Torvalds * Calculate parameters for balancing for current level h. 19181da177e4SLinus Torvalds * Parameters: 19191da177e4SLinus Torvalds * tb tree_balance structure; 19201da177e4SLinus Torvalds * h current level of the node; 19211da177e4SLinus Torvalds * inum item number in S[h]; 19221da177e4SLinus Torvalds * mode i - insert, p - paste; 19231da177e4SLinus Torvalds * Returns: 1 - schedule occurred; 19241da177e4SLinus Torvalds * 0 - balancing for higher levels needed; 19251da177e4SLinus Torvalds * -1 - no balancing for higher levels needed; 19261da177e4SLinus Torvalds * -2 - no disk space. 19271da177e4SLinus Torvalds */ 19281da177e4SLinus Torvalds static int dc_check_balance_leaf(struct tree_balance *tb, int h) 19291da177e4SLinus Torvalds { 19301da177e4SLinus Torvalds struct virtual_node *vn = tb->tb_vn; 19311da177e4SLinus Torvalds 1932098297b2SJeff Mahoney /* 1933098297b2SJeff Mahoney * Number of bytes that must be deleted from 1934098297b2SJeff Mahoney * (value is negative if bytes are deleted) buffer which 1935098297b2SJeff Mahoney * contains node being balanced. The mnemonic is that the 1936098297b2SJeff Mahoney * attempted change in node space used level is levbytes bytes. 1937098297b2SJeff Mahoney */ 19381da177e4SLinus Torvalds int levbytes; 1939098297b2SJeff Mahoney 19401da177e4SLinus Torvalds /* the maximal item size */ 1941ee93961bSJeff Mahoney int maxsize, ret; 1942098297b2SJeff Mahoney 1943098297b2SJeff Mahoney /* 1944098297b2SJeff Mahoney * S0 is the node whose balance is currently being checked, 1945098297b2SJeff Mahoney * and F0 is its father. 1946098297b2SJeff Mahoney */ 19471da177e4SLinus Torvalds struct buffer_head *S0, *F0; 19481da177e4SLinus Torvalds int lfree, rfree /* free space in L and R */ ; 19491da177e4SLinus Torvalds 19501da177e4SLinus Torvalds S0 = PATH_H_PBUFFER(tb->tb_path, 0); 19511da177e4SLinus Torvalds F0 = PATH_H_PPARENT(tb->tb_path, 0); 19521da177e4SLinus Torvalds 19531da177e4SLinus Torvalds levbytes = tb->insert_size[h]; 19541da177e4SLinus Torvalds 19551da177e4SLinus Torvalds maxsize = MAX_CHILD_SIZE(S0); /* maximal possible size of an item */ 19561da177e4SLinus Torvalds 1957bd4c625cSLinus Torvalds if (!F0) { /* S[0] is the root now. */ 19581da177e4SLinus Torvalds 19591da177e4SLinus Torvalds RFALSE(-levbytes >= maxsize - B_FREE_SPACE(S0), 19601da177e4SLinus Torvalds "vs-8240: attempt to create empty buffer tree"); 19611da177e4SLinus Torvalds 19621da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 19631da177e4SLinus Torvalds return NO_BALANCING_NEEDED; 19641da177e4SLinus Torvalds } 19651da177e4SLinus Torvalds 1966ee93961bSJeff Mahoney if ((ret = get_parents(tb, h)) != CARRY_ON) 1967ee93961bSJeff Mahoney return ret; 19681da177e4SLinus Torvalds 19691da177e4SLinus Torvalds /* get free space of neighbors */ 19701da177e4SLinus Torvalds rfree = get_rfree(tb, h); 19711da177e4SLinus Torvalds lfree = get_lfree(tb, h); 19721da177e4SLinus Torvalds 19731da177e4SLinus Torvalds create_virtual_node(tb, h); 19741da177e4SLinus Torvalds 19751da177e4SLinus Torvalds /* if 3 leaves can be merge to one, set parameters and return */ 19761da177e4SLinus Torvalds if (are_leaves_removable(tb, lfree, rfree)) 19771da177e4SLinus Torvalds return CARRY_ON; 19781da177e4SLinus Torvalds 1979098297b2SJeff Mahoney /* 1980098297b2SJeff Mahoney * determine maximal number of items we can shift to the left/right 1981098297b2SJeff Mahoney * neighbor and the maximal number of bytes that can flow to the 1982098297b2SJeff Mahoney * left/right neighbor from the left/right most liquid item that 1983098297b2SJeff Mahoney * cannot be shifted from S[0] entirely 19841da177e4SLinus Torvalds */ 19851da177e4SLinus Torvalds check_left(tb, h, lfree); 19861da177e4SLinus Torvalds check_right(tb, h, rfree); 19871da177e4SLinus Torvalds 19881da177e4SLinus Torvalds /* check whether we can merge S with left neighbor. */ 19891da177e4SLinus Torvalds if (tb->lnum[0] >= vn->vn_nr_item && tb->lbytes == -1) 1990bd4c625cSLinus 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 */ 19911da177e4SLinus Torvalds !tb->FR[h]) { 19921da177e4SLinus Torvalds 1993bd4c625cSLinus Torvalds RFALSE(!tb->FL[h], 1994bd4c625cSLinus Torvalds "vs-8245: dc_check_balance_leaf: FL[h] must exist"); 19951da177e4SLinus Torvalds 19961da177e4SLinus Torvalds /* set parameter to merge S[0] with its left neighbor */ 19971da177e4SLinus Torvalds set_parameters(tb, h, -1, 0, 0, NULL, -1, -1); 19981da177e4SLinus Torvalds return CARRY_ON; 19991da177e4SLinus Torvalds } 20001da177e4SLinus Torvalds 20011da177e4SLinus Torvalds /* check whether we can merge S[0] with right neighbor. */ 20021da177e4SLinus Torvalds if (tb->rnum[0] >= vn->vn_nr_item && tb->rbytes == -1) { 20031da177e4SLinus Torvalds set_parameters(tb, h, 0, -1, 0, NULL, -1, -1); 20041da177e4SLinus Torvalds return CARRY_ON; 20051da177e4SLinus Torvalds } 20061da177e4SLinus Torvalds 2007098297b2SJeff Mahoney /* 2008098297b2SJeff Mahoney * All contents of S[0] can be moved to the neighbors (L[0] & R[0]). 2009098297b2SJeff Mahoney * Set parameters and return 2010098297b2SJeff Mahoney */ 20111da177e4SLinus Torvalds if (is_leaf_removable(tb)) 20121da177e4SLinus Torvalds return CARRY_ON; 20131da177e4SLinus Torvalds 20141da177e4SLinus Torvalds /* Balancing is not required. */ 20151da177e4SLinus Torvalds tb->s0num = vn->vn_nr_item; 20161da177e4SLinus Torvalds set_parameters(tb, h, 0, 0, 1, NULL, -1, -1); 20171da177e4SLinus Torvalds return NO_BALANCING_NEEDED; 20181da177e4SLinus Torvalds } 20191da177e4SLinus Torvalds 2020098297b2SJeff Mahoney /* 2021098297b2SJeff Mahoney * Check whether current node S[h] is balanced when Decreasing its size by 20221da177e4SLinus Torvalds * Deleting or Cutting. 20231da177e4SLinus Torvalds * Calculate parameters for balancing for current level h. 20241da177e4SLinus Torvalds * Parameters: 20251da177e4SLinus Torvalds * tb tree_balance structure; 20261da177e4SLinus Torvalds * h current level of the node; 20271da177e4SLinus Torvalds * inum item number in S[h]; 20281da177e4SLinus Torvalds * mode d - delete, c - cut. 20291da177e4SLinus Torvalds * Returns: 1 - schedule occurred; 20301da177e4SLinus Torvalds * 0 - balancing for higher levels needed; 20311da177e4SLinus Torvalds * -1 - no balancing for higher levels needed; 20321da177e4SLinus Torvalds * -2 - no disk space. 20331da177e4SLinus Torvalds */ 20341da177e4SLinus Torvalds static int dc_check_balance(struct tree_balance *tb, int h) 20351da177e4SLinus Torvalds { 2036bd4c625cSLinus Torvalds RFALSE(!(PATH_H_PBUFFER(tb->tb_path, h)), 2037bd4c625cSLinus Torvalds "vs-8250: S is not initialized"); 20381da177e4SLinus Torvalds 20391da177e4SLinus Torvalds if (h) 20401da177e4SLinus Torvalds return dc_check_balance_internal(tb, h); 20411da177e4SLinus Torvalds else 20421da177e4SLinus Torvalds return dc_check_balance_leaf(tb, h); 20431da177e4SLinus Torvalds } 20441da177e4SLinus Torvalds 2045098297b2SJeff Mahoney /* 2046098297b2SJeff Mahoney * Check whether current node S[h] is balanced. 20471da177e4SLinus Torvalds * Calculate parameters for balancing for current level h. 20481da177e4SLinus Torvalds * Parameters: 20491da177e4SLinus Torvalds * 20501da177e4SLinus Torvalds * tb tree_balance structure: 20511da177e4SLinus Torvalds * 2052098297b2SJeff Mahoney * tb is a large structure that must be read about in the header 2053098297b2SJeff Mahoney * file at the same time as this procedure if the reader is 2054098297b2SJeff Mahoney * to successfully understand this procedure 20551da177e4SLinus Torvalds * 20561da177e4SLinus Torvalds * h current level of the node; 20571da177e4SLinus Torvalds * inum item number in S[h]; 20581da177e4SLinus Torvalds * mode i - insert, p - paste, d - delete, c - cut. 20591da177e4SLinus Torvalds * Returns: 1 - schedule occurred; 20601da177e4SLinus Torvalds * 0 - balancing for higher levels needed; 20611da177e4SLinus Torvalds * -1 - no balancing for higher levels needed; 20621da177e4SLinus Torvalds * -2 - no disk space. 20631da177e4SLinus Torvalds */ 20641da177e4SLinus Torvalds static int check_balance(int mode, 20651da177e4SLinus Torvalds struct tree_balance *tb, 20661da177e4SLinus Torvalds int h, 20671da177e4SLinus Torvalds int inum, 20681da177e4SLinus Torvalds int pos_in_item, 2069bd4c625cSLinus Torvalds struct item_head *ins_ih, const void *data) 20701da177e4SLinus Torvalds { 20711da177e4SLinus Torvalds struct virtual_node *vn; 20721da177e4SLinus Torvalds 20731da177e4SLinus Torvalds vn = tb->tb_vn = (struct virtual_node *)(tb->vn_buf); 20741da177e4SLinus Torvalds vn->vn_free_ptr = (char *)(tb->tb_vn + 1); 20751da177e4SLinus Torvalds vn->vn_mode = mode; 20761da177e4SLinus Torvalds vn->vn_affected_item_num = inum; 20771da177e4SLinus Torvalds vn->vn_pos_in_item = pos_in_item; 20781da177e4SLinus Torvalds vn->vn_ins_ih = ins_ih; 20791da177e4SLinus Torvalds vn->vn_data = data; 20801da177e4SLinus Torvalds 20811da177e4SLinus Torvalds RFALSE(mode == M_INSERT && !vn->vn_ins_ih, 20821da177e4SLinus Torvalds "vs-8255: ins_ih can not be 0 in insert mode"); 20831da177e4SLinus Torvalds 20841da177e4SLinus Torvalds /* Calculate balance parameters when size of node is increasing. */ 2085098297b2SJeff Mahoney if (tb->insert_size[h] > 0) 20861da177e4SLinus Torvalds return ip_check_balance(tb, h); 20871da177e4SLinus Torvalds 20881da177e4SLinus Torvalds /* Calculate balance parameters when size of node is decreasing. */ 20891da177e4SLinus Torvalds return dc_check_balance(tb, h); 20901da177e4SLinus Torvalds } 20911da177e4SLinus Torvalds 20921da177e4SLinus Torvalds /* Check whether parent at the path is the really parent of the current node.*/ 2093ee93961bSJeff Mahoney static int get_direct_parent(struct tree_balance *tb, int h) 2094bd4c625cSLinus Torvalds { 2095ad31a4fcSJeff Mahoney struct buffer_head *bh; 2096d68caa95SJeff Mahoney struct treepath *path = tb->tb_path; 2097ee93961bSJeff Mahoney int position, 2098ee93961bSJeff Mahoney path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h); 20991da177e4SLinus Torvalds 21001da177e4SLinus Torvalds /* We are in the root or in the new root. */ 2101ee93961bSJeff Mahoney if (path_offset <= FIRST_PATH_ELEMENT_OFFSET) { 21021da177e4SLinus Torvalds 2103ee93961bSJeff Mahoney RFALSE(path_offset < FIRST_PATH_ELEMENT_OFFSET - 1, 21041da177e4SLinus Torvalds "PAP-8260: invalid offset in the path"); 21051da177e4SLinus Torvalds 2106d68caa95SJeff Mahoney if (PATH_OFFSET_PBUFFER(path, FIRST_PATH_ELEMENT_OFFSET)-> 2107a063ae17SJeff Mahoney b_blocknr == SB_ROOT_BLOCK(tb->tb_sb)) { 21081da177e4SLinus Torvalds /* Root is not changed. */ 2109ee93961bSJeff Mahoney PATH_OFFSET_PBUFFER(path, path_offset - 1) = NULL; 2110ee93961bSJeff Mahoney PATH_OFFSET_POSITION(path, path_offset - 1) = 0; 21111da177e4SLinus Torvalds return CARRY_ON; 21121da177e4SLinus Torvalds } 2113098297b2SJeff Mahoney /* Root is changed and we must recalculate the path. */ 2114098297b2SJeff Mahoney return REPEAT_SEARCH; 21151da177e4SLinus Torvalds } 21161da177e4SLinus Torvalds 2117098297b2SJeff Mahoney /* Parent in the path is not in the tree. */ 2118bd4c625cSLinus Torvalds if (!B_IS_IN_TREE 2119ee93961bSJeff Mahoney (bh = PATH_OFFSET_PBUFFER(path, path_offset - 1))) 2120098297b2SJeff Mahoney return REPEAT_SEARCH; 21211da177e4SLinus Torvalds 2122ee93961bSJeff Mahoney if ((position = 2123d68caa95SJeff Mahoney PATH_OFFSET_POSITION(path, 2124ee93961bSJeff Mahoney path_offset - 1)) > B_NR_ITEMS(bh)) 21251da177e4SLinus Torvalds return REPEAT_SEARCH; 21261da177e4SLinus Torvalds 2127098297b2SJeff Mahoney /* Parent in the path is not parent of the current node in the tree. */ 2128ee93961bSJeff Mahoney if (B_N_CHILD_NUM(bh, position) != 2129ee93961bSJeff Mahoney PATH_OFFSET_PBUFFER(path, path_offset)->b_blocknr) 21301da177e4SLinus Torvalds return REPEAT_SEARCH; 21311da177e4SLinus Torvalds 2132ad31a4fcSJeff Mahoney if (buffer_locked(bh)) { 2133278f6679SJeff Mahoney int depth = reiserfs_write_unlock_nested(tb->tb_sb); 2134ad31a4fcSJeff Mahoney __wait_on_buffer(bh); 2135278f6679SJeff Mahoney reiserfs_write_lock_nested(tb->tb_sb, depth); 2136a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) 21371da177e4SLinus Torvalds return REPEAT_SEARCH; 21381da177e4SLinus Torvalds } 21391da177e4SLinus Torvalds 2140098297b2SJeff Mahoney /* 2141098297b2SJeff Mahoney * Parent in the path is unlocked and really parent 2142098297b2SJeff Mahoney * of the current node. 2143098297b2SJeff Mahoney */ 2144098297b2SJeff Mahoney return CARRY_ON; 21451da177e4SLinus Torvalds } 21461da177e4SLinus Torvalds 2147098297b2SJeff Mahoney /* 2148098297b2SJeff Mahoney * Using lnum[h] and rnum[h] we should determine what neighbors 2149ee93961bSJeff Mahoney * of S[h] we 2150ee93961bSJeff Mahoney * need in order to balance S[h], and get them if necessary. 21511da177e4SLinus Torvalds * Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked; 21521da177e4SLinus Torvalds * CARRY_ON - schedule didn't occur while the function worked; 21531da177e4SLinus Torvalds */ 2154ee93961bSJeff Mahoney static int get_neighbors(struct tree_balance *tb, int h) 2155bd4c625cSLinus Torvalds { 2156ee93961bSJeff Mahoney int child_position, 2157ee93961bSJeff Mahoney path_offset = PATH_H_PATH_OFFSET(tb->tb_path, h + 1); 2158ee93961bSJeff Mahoney unsigned long son_number; 2159a063ae17SJeff Mahoney struct super_block *sb = tb->tb_sb; 2160ad31a4fcSJeff Mahoney struct buffer_head *bh; 2161278f6679SJeff Mahoney int depth; 21621da177e4SLinus Torvalds 2163ee93961bSJeff Mahoney PROC_INFO_INC(sb, get_neighbors[h]); 21641da177e4SLinus Torvalds 2165ee93961bSJeff Mahoney if (tb->lnum[h]) { 2166ee93961bSJeff Mahoney /* We need left neighbor to balance S[h]. */ 2167ee93961bSJeff Mahoney PROC_INFO_INC(sb, need_l_neighbor[h]); 2168ee93961bSJeff Mahoney bh = PATH_OFFSET_PBUFFER(tb->tb_path, path_offset); 21691da177e4SLinus Torvalds 2170ee93961bSJeff Mahoney RFALSE(bh == tb->FL[h] && 2171ee93961bSJeff Mahoney !PATH_OFFSET_POSITION(tb->tb_path, path_offset), 21721da177e4SLinus Torvalds "PAP-8270: invalid position in the parent"); 21731da177e4SLinus Torvalds 2174ee93961bSJeff Mahoney child_position = 2175ad31a4fcSJeff Mahoney (bh == 2176ee93961bSJeff Mahoney tb->FL[h]) ? tb->lkey[h] : B_NR_ITEMS(tb-> 2177ee93961bSJeff Mahoney FL[h]); 2178ee93961bSJeff Mahoney son_number = B_N_CHILD_NUM(tb->FL[h], child_position); 2179278f6679SJeff Mahoney depth = reiserfs_write_unlock_nested(tb->tb_sb); 2180ee93961bSJeff Mahoney bh = sb_bread(sb, son_number); 2181278f6679SJeff Mahoney reiserfs_write_lock_nested(tb->tb_sb, depth); 2182ad31a4fcSJeff Mahoney if (!bh) 21831da177e4SLinus Torvalds return IO_ERROR; 2184a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) { 2185ad31a4fcSJeff Mahoney brelse(bh); 2186ee93961bSJeff Mahoney PROC_INFO_INC(sb, get_neighbors_restart[h]); 21871da177e4SLinus Torvalds return REPEAT_SEARCH; 21881da177e4SLinus Torvalds } 21891da177e4SLinus Torvalds 2190ee93961bSJeff Mahoney RFALSE(!B_IS_IN_TREE(tb->FL[h]) || 2191ee93961bSJeff Mahoney child_position > B_NR_ITEMS(tb->FL[h]) || 2192ee93961bSJeff Mahoney B_N_CHILD_NUM(tb->FL[h], child_position) != 2193ad31a4fcSJeff Mahoney bh->b_blocknr, "PAP-8275: invalid parent"); 2194ad31a4fcSJeff Mahoney RFALSE(!B_IS_IN_TREE(bh), "PAP-8280: invalid child"); 2195ee93961bSJeff Mahoney RFALSE(!h && 2196ad31a4fcSJeff Mahoney B_FREE_SPACE(bh) != 2197ad31a4fcSJeff Mahoney MAX_CHILD_SIZE(bh) - 2198ee93961bSJeff Mahoney dc_size(B_N_CHILD(tb->FL[0], child_position)), 21991da177e4SLinus Torvalds "PAP-8290: invalid child size of left neighbor"); 22001da177e4SLinus Torvalds 2201ee93961bSJeff Mahoney brelse(tb->L[h]); 2202ee93961bSJeff Mahoney tb->L[h] = bh; 22031da177e4SLinus Torvalds } 22041da177e4SLinus Torvalds 2205ee93961bSJeff Mahoney /* We need right neighbor to balance S[path_offset]. */ 2206098297b2SJeff Mahoney if (tb->rnum[h]) { 2207ee93961bSJeff Mahoney PROC_INFO_INC(sb, need_r_neighbor[h]); 2208ee93961bSJeff Mahoney bh = PATH_OFFSET_PBUFFER(tb->tb_path, path_offset); 22091da177e4SLinus Torvalds 2210ee93961bSJeff Mahoney RFALSE(bh == tb->FR[h] && 2211a063ae17SJeff Mahoney PATH_OFFSET_POSITION(tb->tb_path, 2212ee93961bSJeff Mahoney path_offset) >= 2213ad31a4fcSJeff Mahoney B_NR_ITEMS(bh), 22141da177e4SLinus Torvalds "PAP-8295: invalid position in the parent"); 22151da177e4SLinus Torvalds 2216ee93961bSJeff Mahoney child_position = 2217ee93961bSJeff Mahoney (bh == tb->FR[h]) ? tb->rkey[h] + 1 : 0; 2218ee93961bSJeff Mahoney son_number = B_N_CHILD_NUM(tb->FR[h], child_position); 2219278f6679SJeff Mahoney depth = reiserfs_write_unlock_nested(tb->tb_sb); 2220ee93961bSJeff Mahoney bh = sb_bread(sb, son_number); 2221278f6679SJeff Mahoney reiserfs_write_lock_nested(tb->tb_sb, depth); 2222ad31a4fcSJeff Mahoney if (!bh) 22231da177e4SLinus Torvalds return IO_ERROR; 2224a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) { 2225ad31a4fcSJeff Mahoney brelse(bh); 2226ee93961bSJeff Mahoney PROC_INFO_INC(sb, get_neighbors_restart[h]); 22271da177e4SLinus Torvalds return REPEAT_SEARCH; 22281da177e4SLinus Torvalds } 2229ee93961bSJeff Mahoney brelse(tb->R[h]); 2230ee93961bSJeff Mahoney tb->R[h] = bh; 22311da177e4SLinus Torvalds 2232ee93961bSJeff Mahoney RFALSE(!h 2233ad31a4fcSJeff Mahoney && B_FREE_SPACE(bh) != 2234ad31a4fcSJeff Mahoney MAX_CHILD_SIZE(bh) - 2235ee93961bSJeff Mahoney dc_size(B_N_CHILD(tb->FR[0], child_position)), 22361da177e4SLinus Torvalds "PAP-8300: invalid child size of right neighbor (%d != %d - %d)", 2237ad31a4fcSJeff Mahoney B_FREE_SPACE(bh), MAX_CHILD_SIZE(bh), 2238ee93961bSJeff Mahoney dc_size(B_N_CHILD(tb->FR[0], child_position))); 22391da177e4SLinus Torvalds 22401da177e4SLinus Torvalds } 22411da177e4SLinus Torvalds return CARRY_ON; 22421da177e4SLinus Torvalds } 22431da177e4SLinus Torvalds 22441da177e4SLinus Torvalds static int get_virtual_node_size(struct super_block *sb, struct buffer_head *bh) 22451da177e4SLinus Torvalds { 22461da177e4SLinus Torvalds int max_num_of_items; 22471da177e4SLinus Torvalds int max_num_of_entries; 22481da177e4SLinus Torvalds unsigned long blocksize = sb->s_blocksize; 22491da177e4SLinus Torvalds 22501da177e4SLinus Torvalds #define MIN_NAME_LEN 1 22511da177e4SLinus Torvalds 22521da177e4SLinus Torvalds max_num_of_items = (blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN); 22531da177e4SLinus Torvalds max_num_of_entries = (blocksize - BLKH_SIZE - IH_SIZE) / 22541da177e4SLinus Torvalds (DEH_SIZE + MIN_NAME_LEN); 22551da177e4SLinus Torvalds 22561da177e4SLinus Torvalds return sizeof(struct virtual_node) + 22571da177e4SLinus Torvalds max(max_num_of_items * sizeof(struct virtual_item), 22581da177e4SLinus Torvalds sizeof(struct virtual_item) + sizeof(struct direntry_uarea) + 22591da177e4SLinus Torvalds (max_num_of_entries - 1) * sizeof(__u16)); 22601da177e4SLinus Torvalds } 22611da177e4SLinus Torvalds 2262098297b2SJeff Mahoney /* 2263098297b2SJeff Mahoney * maybe we should fail balancing we are going to perform when kmalloc 2264098297b2SJeff Mahoney * fails several times. But now it will loop until kmalloc gets 2265098297b2SJeff Mahoney * required memory 2266098297b2SJeff Mahoney */ 22671da177e4SLinus Torvalds static int get_mem_for_virtual_node(struct tree_balance *tb) 22681da177e4SLinus Torvalds { 22691da177e4SLinus Torvalds int check_fs = 0; 22701da177e4SLinus Torvalds int size; 22711da177e4SLinus Torvalds char *buf; 22721da177e4SLinus Torvalds 22731da177e4SLinus Torvalds size = get_virtual_node_size(tb->tb_sb, PATH_PLAST_BUFFER(tb->tb_path)); 22741da177e4SLinus Torvalds 22751da177e4SLinus Torvalds /* we have to allocate more memory for virtual node */ 2276098297b2SJeff Mahoney if (size > tb->vn_buf_size) { 22771da177e4SLinus Torvalds if (tb->vn_buf) { 22781da177e4SLinus Torvalds /* free memory allocated before */ 2279d739b42bSPekka Enberg kfree(tb->vn_buf); 22801da177e4SLinus Torvalds /* this is not needed if kfree is atomic */ 22811da177e4SLinus Torvalds check_fs = 1; 22821da177e4SLinus Torvalds } 22831da177e4SLinus Torvalds 22841da177e4SLinus Torvalds /* virtual node requires now more memory */ 22851da177e4SLinus Torvalds tb->vn_buf_size = size; 22861da177e4SLinus Torvalds 22871da177e4SLinus Torvalds /* get memory for virtual item */ 2288d739b42bSPekka Enberg buf = kmalloc(size, GFP_ATOMIC | __GFP_NOWARN); 22891da177e4SLinus Torvalds if (!buf) { 2290098297b2SJeff Mahoney /* 2291098297b2SJeff Mahoney * getting memory with GFP_KERNEL priority may involve 2292098297b2SJeff Mahoney * balancing now (due to indirect_to_direct conversion 2293098297b2SJeff Mahoney * on dcache shrinking). So, release path and collected 2294098297b2SJeff Mahoney * resources here 2295098297b2SJeff Mahoney */ 22961da177e4SLinus Torvalds free_buffers_in_tb(tb); 2297d739b42bSPekka Enberg buf = kmalloc(size, GFP_NOFS); 22981da177e4SLinus Torvalds if (!buf) { 22991da177e4SLinus Torvalds tb->vn_buf_size = 0; 23001da177e4SLinus Torvalds } 23011da177e4SLinus Torvalds tb->vn_buf = buf; 23021da177e4SLinus Torvalds schedule(); 23031da177e4SLinus Torvalds return REPEAT_SEARCH; 23041da177e4SLinus Torvalds } 23051da177e4SLinus Torvalds 23061da177e4SLinus Torvalds tb->vn_buf = buf; 23071da177e4SLinus Torvalds } 23081da177e4SLinus Torvalds 23091da177e4SLinus Torvalds if (check_fs && FILESYSTEM_CHANGED_TB(tb)) 23101da177e4SLinus Torvalds return REPEAT_SEARCH; 23111da177e4SLinus Torvalds 23121da177e4SLinus Torvalds return CARRY_ON; 23131da177e4SLinus Torvalds } 23141da177e4SLinus Torvalds 23151da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK 2316a9dd3643SJeff Mahoney static void tb_buffer_sanity_check(struct super_block *sb, 2317ad31a4fcSJeff Mahoney struct buffer_head *bh, 2318bd4c625cSLinus Torvalds const char *descr, int level) 2319bd4c625cSLinus Torvalds { 2320ad31a4fcSJeff Mahoney if (bh) { 2321ad31a4fcSJeff Mahoney if (atomic_read(&(bh->b_count)) <= 0) 23221da177e4SLinus Torvalds 2323a9dd3643SJeff Mahoney reiserfs_panic(sb, "jmacd-1", "negative or zero " 2324c3a9c210SJeff Mahoney "reference counter for buffer %s[%d] " 2325ad31a4fcSJeff Mahoney "(%b)", descr, level, bh); 23261da177e4SLinus Torvalds 2327ad31a4fcSJeff Mahoney if (!buffer_uptodate(bh)) 2328a9dd3643SJeff Mahoney reiserfs_panic(sb, "jmacd-2", "buffer is not up " 2329c3a9c210SJeff Mahoney "to date %s[%d] (%b)", 2330ad31a4fcSJeff Mahoney descr, level, bh); 23311da177e4SLinus Torvalds 2332ad31a4fcSJeff Mahoney if (!B_IS_IN_TREE(bh)) 2333a9dd3643SJeff Mahoney reiserfs_panic(sb, "jmacd-3", "buffer is not " 2334c3a9c210SJeff Mahoney "in tree %s[%d] (%b)", 2335ad31a4fcSJeff Mahoney descr, level, bh); 23361da177e4SLinus Torvalds 2337ad31a4fcSJeff Mahoney if (bh->b_bdev != sb->s_bdev) 2338a9dd3643SJeff Mahoney reiserfs_panic(sb, "jmacd-4", "buffer has wrong " 2339c3a9c210SJeff Mahoney "device %s[%d] (%b)", 2340ad31a4fcSJeff Mahoney descr, level, bh); 23411da177e4SLinus Torvalds 2342ad31a4fcSJeff Mahoney if (bh->b_size != sb->s_blocksize) 2343a9dd3643SJeff Mahoney reiserfs_panic(sb, "jmacd-5", "buffer has wrong " 2344c3a9c210SJeff Mahoney "blocksize %s[%d] (%b)", 2345ad31a4fcSJeff Mahoney descr, level, bh); 23461da177e4SLinus Torvalds 2347ad31a4fcSJeff Mahoney if (bh->b_blocknr > SB_BLOCK_COUNT(sb)) 2348a9dd3643SJeff Mahoney reiserfs_panic(sb, "jmacd-6", "buffer block " 2349c3a9c210SJeff Mahoney "number too high %s[%d] (%b)", 2350ad31a4fcSJeff Mahoney descr, level, bh); 23511da177e4SLinus Torvalds } 23521da177e4SLinus Torvalds } 23531da177e4SLinus Torvalds #else 2354a9dd3643SJeff Mahoney static void tb_buffer_sanity_check(struct super_block *sb, 2355ad31a4fcSJeff Mahoney struct buffer_head *bh, 23561da177e4SLinus Torvalds const char *descr, int level) 2357bd4c625cSLinus Torvalds {; 2358bd4c625cSLinus Torvalds } 23591da177e4SLinus Torvalds #endif 23601da177e4SLinus Torvalds 2361bd4c625cSLinus Torvalds static int clear_all_dirty_bits(struct super_block *s, struct buffer_head *bh) 2362bd4c625cSLinus Torvalds { 23631da177e4SLinus Torvalds return reiserfs_prepare_for_journal(s, bh, 0); 23641da177e4SLinus Torvalds } 23651da177e4SLinus Torvalds 2366a063ae17SJeff Mahoney static int wait_tb_buffers_until_unlocked(struct tree_balance *tb) 23671da177e4SLinus Torvalds { 23681da177e4SLinus Torvalds struct buffer_head *locked; 23691da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK 23701da177e4SLinus Torvalds int repeat_counter = 0; 23711da177e4SLinus Torvalds #endif 23721da177e4SLinus Torvalds int i; 23731da177e4SLinus Torvalds 23741da177e4SLinus Torvalds do { 23751da177e4SLinus Torvalds 23761da177e4SLinus Torvalds locked = NULL; 23771da177e4SLinus Torvalds 2378a063ae17SJeff Mahoney for (i = tb->tb_path->path_length; 2379bd4c625cSLinus Torvalds !locked && i > ILLEGAL_PATH_ELEMENT_OFFSET; i--) { 2380a063ae17SJeff Mahoney if (PATH_OFFSET_PBUFFER(tb->tb_path, i)) { 2381098297b2SJeff Mahoney /* 2382098297b2SJeff Mahoney * if I understand correctly, we can only 2383098297b2SJeff Mahoney * be sure the last buffer in the path is 2384098297b2SJeff Mahoney * in the tree --clm 23851da177e4SLinus Torvalds */ 23861da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK 2387a063ae17SJeff Mahoney if (PATH_PLAST_BUFFER(tb->tb_path) == 2388a063ae17SJeff Mahoney PATH_OFFSET_PBUFFER(tb->tb_path, i)) 2389a063ae17SJeff Mahoney tb_buffer_sanity_check(tb->tb_sb, 2390bd4c625cSLinus Torvalds PATH_OFFSET_PBUFFER 2391a063ae17SJeff Mahoney (tb->tb_path, 2392bd4c625cSLinus Torvalds i), "S", 2393a063ae17SJeff Mahoney tb->tb_path-> 2394bd4c625cSLinus Torvalds path_length - i); 23951da177e4SLinus Torvalds #endif 2396a063ae17SJeff Mahoney if (!clear_all_dirty_bits(tb->tb_sb, 2397bd4c625cSLinus Torvalds PATH_OFFSET_PBUFFER 2398a063ae17SJeff Mahoney (tb->tb_path, 2399bd4c625cSLinus Torvalds i))) { 2400bd4c625cSLinus Torvalds locked = 2401a063ae17SJeff Mahoney PATH_OFFSET_PBUFFER(tb->tb_path, 2402bd4c625cSLinus Torvalds i); 24031da177e4SLinus Torvalds } 24041da177e4SLinus Torvalds } 24051da177e4SLinus Torvalds } 24061da177e4SLinus Torvalds 2407a063ae17SJeff Mahoney for (i = 0; !locked && i < MAX_HEIGHT && tb->insert_size[i]; 2408bd4c625cSLinus Torvalds i++) { 24091da177e4SLinus Torvalds 2410a063ae17SJeff Mahoney if (tb->lnum[i]) { 24111da177e4SLinus Torvalds 2412a063ae17SJeff Mahoney if (tb->L[i]) { 2413a063ae17SJeff Mahoney tb_buffer_sanity_check(tb->tb_sb, 2414a063ae17SJeff Mahoney tb->L[i], 2415bd4c625cSLinus Torvalds "L", i); 2416bd4c625cSLinus Torvalds if (!clear_all_dirty_bits 2417a063ae17SJeff Mahoney (tb->tb_sb, tb->L[i])) 2418a063ae17SJeff Mahoney locked = tb->L[i]; 24191da177e4SLinus Torvalds } 24201da177e4SLinus Torvalds 2421a063ae17SJeff Mahoney if (!locked && tb->FL[i]) { 2422a063ae17SJeff Mahoney tb_buffer_sanity_check(tb->tb_sb, 2423a063ae17SJeff Mahoney tb->FL[i], 2424bd4c625cSLinus Torvalds "FL", i); 2425bd4c625cSLinus Torvalds if (!clear_all_dirty_bits 2426a063ae17SJeff Mahoney (tb->tb_sb, tb->FL[i])) 2427a063ae17SJeff Mahoney locked = tb->FL[i]; 24281da177e4SLinus Torvalds } 24291da177e4SLinus Torvalds 2430a063ae17SJeff Mahoney if (!locked && tb->CFL[i]) { 2431a063ae17SJeff Mahoney tb_buffer_sanity_check(tb->tb_sb, 2432a063ae17SJeff Mahoney tb->CFL[i], 2433bd4c625cSLinus Torvalds "CFL", i); 2434bd4c625cSLinus Torvalds if (!clear_all_dirty_bits 2435a063ae17SJeff Mahoney (tb->tb_sb, tb->CFL[i])) 2436a063ae17SJeff Mahoney locked = tb->CFL[i]; 24371da177e4SLinus Torvalds } 24381da177e4SLinus Torvalds 24391da177e4SLinus Torvalds } 24401da177e4SLinus Torvalds 2441a063ae17SJeff Mahoney if (!locked && (tb->rnum[i])) { 24421da177e4SLinus Torvalds 2443a063ae17SJeff Mahoney if (tb->R[i]) { 2444a063ae17SJeff Mahoney tb_buffer_sanity_check(tb->tb_sb, 2445a063ae17SJeff Mahoney tb->R[i], 2446bd4c625cSLinus Torvalds "R", i); 2447bd4c625cSLinus Torvalds if (!clear_all_dirty_bits 2448a063ae17SJeff Mahoney (tb->tb_sb, tb->R[i])) 2449a063ae17SJeff Mahoney locked = tb->R[i]; 24501da177e4SLinus Torvalds } 24511da177e4SLinus Torvalds 2452a063ae17SJeff Mahoney if (!locked && tb->FR[i]) { 2453a063ae17SJeff Mahoney tb_buffer_sanity_check(tb->tb_sb, 2454a063ae17SJeff Mahoney tb->FR[i], 2455bd4c625cSLinus Torvalds "FR", i); 2456bd4c625cSLinus Torvalds if (!clear_all_dirty_bits 2457a063ae17SJeff Mahoney (tb->tb_sb, tb->FR[i])) 2458a063ae17SJeff Mahoney locked = tb->FR[i]; 24591da177e4SLinus Torvalds } 24601da177e4SLinus Torvalds 2461a063ae17SJeff Mahoney if (!locked && tb->CFR[i]) { 2462a063ae17SJeff Mahoney tb_buffer_sanity_check(tb->tb_sb, 2463a063ae17SJeff Mahoney tb->CFR[i], 2464bd4c625cSLinus Torvalds "CFR", i); 2465bd4c625cSLinus Torvalds if (!clear_all_dirty_bits 2466a063ae17SJeff Mahoney (tb->tb_sb, tb->CFR[i])) 2467a063ae17SJeff Mahoney locked = tb->CFR[i]; 24681da177e4SLinus Torvalds } 24691da177e4SLinus Torvalds } 24701da177e4SLinus Torvalds } 2471098297b2SJeff Mahoney 2472098297b2SJeff Mahoney /* 2473098297b2SJeff Mahoney * as far as I can tell, this is not required. The FEB list 2474098297b2SJeff Mahoney * seems to be full of newly allocated nodes, which will 2475098297b2SJeff Mahoney * never be locked, dirty, or anything else. 2476098297b2SJeff Mahoney * To be safe, I'm putting in the checks and waits in. 2477098297b2SJeff Mahoney * For the moment, they are needed to keep the code in 2478098297b2SJeff Mahoney * journal.c from complaining about the buffer. 2479098297b2SJeff Mahoney * That code is inside CONFIG_REISERFS_CHECK as well. --clm 24801da177e4SLinus Torvalds */ 24811da177e4SLinus Torvalds for (i = 0; !locked && i < MAX_FEB_SIZE; i++) { 2482a063ae17SJeff Mahoney if (tb->FEB[i]) { 2483bd4c625cSLinus Torvalds if (!clear_all_dirty_bits 2484a063ae17SJeff Mahoney (tb->tb_sb, tb->FEB[i])) 2485a063ae17SJeff Mahoney locked = tb->FEB[i]; 24861da177e4SLinus Torvalds } 24871da177e4SLinus Torvalds } 24881da177e4SLinus Torvalds 24891da177e4SLinus Torvalds if (locked) { 2490278f6679SJeff Mahoney int depth; 24911da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK 24921da177e4SLinus Torvalds repeat_counter++; 24931da177e4SLinus Torvalds if ((repeat_counter % 10000) == 0) { 2494a063ae17SJeff Mahoney reiserfs_warning(tb->tb_sb, "reiserfs-8200", 249545b03d5eSJeff Mahoney "too many iterations waiting " 249645b03d5eSJeff Mahoney "for buffer to unlock " 24971da177e4SLinus Torvalds "(%b)", locked); 24981da177e4SLinus Torvalds 24991da177e4SLinus Torvalds /* Don't loop forever. Try to recover from possible error. */ 25001da177e4SLinus Torvalds 2501a063ae17SJeff Mahoney return (FILESYSTEM_CHANGED_TB(tb)) ? 2502bd4c625cSLinus Torvalds REPEAT_SEARCH : CARRY_ON; 25031da177e4SLinus Torvalds } 25041da177e4SLinus Torvalds #endif 2505278f6679SJeff Mahoney depth = reiserfs_write_unlock_nested(tb->tb_sb); 25061da177e4SLinus Torvalds __wait_on_buffer(locked); 2507278f6679SJeff Mahoney reiserfs_write_lock_nested(tb->tb_sb, depth); 2508a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) 25091da177e4SLinus Torvalds return REPEAT_SEARCH; 25101da177e4SLinus Torvalds } 25111da177e4SLinus Torvalds 25121da177e4SLinus Torvalds } while (locked); 25131da177e4SLinus Torvalds 25141da177e4SLinus Torvalds return CARRY_ON; 25151da177e4SLinus Torvalds } 25161da177e4SLinus Torvalds 2517098297b2SJeff Mahoney /* 2518098297b2SJeff Mahoney * Prepare for balancing, that is 25191da177e4SLinus Torvalds * get all necessary parents, and neighbors; 25201da177e4SLinus Torvalds * analyze what and where should be moved; 25211da177e4SLinus Torvalds * get sufficient number of new nodes; 25221da177e4SLinus Torvalds * Balancing will start only after all resources will be collected at a time. 25231da177e4SLinus Torvalds * 25241da177e4SLinus Torvalds * When ported to SMP kernels, only at the last moment after all needed nodes 25251da177e4SLinus Torvalds * are collected in cache, will the resources be locked using the usual 25261da177e4SLinus Torvalds * textbook ordered lock acquisition algorithms. Note that ensuring that 2527098297b2SJeff Mahoney * this code neither write locks what it does not need to write lock nor locks 2528098297b2SJeff Mahoney * out of order will be a pain in the butt that could have been avoided. 2529098297b2SJeff Mahoney * Grumble grumble. -Hans 25301da177e4SLinus Torvalds * 25311da177e4SLinus Torvalds * fix is meant in the sense of render unchanging 25321da177e4SLinus Torvalds * 2533098297b2SJeff Mahoney * Latency might be improved by first gathering a list of what buffers 2534098297b2SJeff Mahoney * are needed and then getting as many of them in parallel as possible? -Hans 25351da177e4SLinus Torvalds * 25361da177e4SLinus Torvalds * Parameters: 25371da177e4SLinus Torvalds * op_mode i - insert, d - delete, c - cut (truncate), p - paste (append) 25381da177e4SLinus Torvalds * tb tree_balance structure; 25391da177e4SLinus Torvalds * inum item number in S[h]; 25401da177e4SLinus Torvalds * pos_in_item - comment this if you can 2541a063ae17SJeff Mahoney * ins_ih item head of item being inserted 2542a063ae17SJeff Mahoney * data inserted item or data to be pasted 25431da177e4SLinus Torvalds * Returns: 1 - schedule occurred while the function worked; 25441da177e4SLinus Torvalds * 0 - schedule didn't occur while the function worked; 25451da177e4SLinus Torvalds * -1 - if no_disk_space 25461da177e4SLinus Torvalds */ 25471da177e4SLinus Torvalds 2548ee93961bSJeff Mahoney int fix_nodes(int op_mode, struct tree_balance *tb, 2549d68caa95SJeff Mahoney struct item_head *ins_ih, const void *data) 2550bd4c625cSLinus Torvalds { 2551ee93961bSJeff Mahoney int ret, h, item_num = PATH_LAST_POSITION(tb->tb_path); 2552ee93961bSJeff Mahoney int pos_in_item; 25531da177e4SLinus Torvalds 2554098297b2SJeff Mahoney /* 2555098297b2SJeff Mahoney * we set wait_tb_buffers_run when we have to restore any dirty 2556098297b2SJeff Mahoney * bits cleared during wait_tb_buffers_run 25571da177e4SLinus Torvalds */ 25581da177e4SLinus Torvalds int wait_tb_buffers_run = 0; 2559a063ae17SJeff Mahoney struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path); 25601da177e4SLinus Torvalds 2561a063ae17SJeff Mahoney ++REISERFS_SB(tb->tb_sb)->s_fix_nodes; 25621da177e4SLinus Torvalds 2563ee93961bSJeff Mahoney pos_in_item = tb->tb_path->pos_in_item; 25641da177e4SLinus Torvalds 2565a063ae17SJeff Mahoney tb->fs_gen = get_generation(tb->tb_sb); 25661da177e4SLinus Torvalds 2567098297b2SJeff Mahoney /* 2568098297b2SJeff Mahoney * we prepare and log the super here so it will already be in the 2569098297b2SJeff Mahoney * transaction when do_balance needs to change it. 2570098297b2SJeff Mahoney * This way do_balance won't have to schedule when trying to prepare 2571098297b2SJeff Mahoney * the super for logging 25721da177e4SLinus Torvalds */ 2573a063ae17SJeff Mahoney reiserfs_prepare_for_journal(tb->tb_sb, 2574a063ae17SJeff Mahoney SB_BUFFER_WITH_SB(tb->tb_sb), 1); 2575*09f1b80bSJeff Mahoney journal_mark_dirty(tb->transaction_handle, 2576a063ae17SJeff Mahoney SB_BUFFER_WITH_SB(tb->tb_sb)); 2577a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) 25781da177e4SLinus Torvalds return REPEAT_SEARCH; 25791da177e4SLinus Torvalds 25801da177e4SLinus Torvalds /* if it possible in indirect_to_direct conversion */ 2581a063ae17SJeff Mahoney if (buffer_locked(tbS0)) { 2582278f6679SJeff Mahoney int depth = reiserfs_write_unlock_nested(tb->tb_sb); 2583a063ae17SJeff Mahoney __wait_on_buffer(tbS0); 2584278f6679SJeff Mahoney reiserfs_write_lock_nested(tb->tb_sb, depth); 2585a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) 25861da177e4SLinus Torvalds return REPEAT_SEARCH; 25871da177e4SLinus Torvalds } 25881da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK 258908f14fc8SFrederic Weisbecker if (REISERFS_SB(tb->tb_sb)->cur_tb) { 25901da177e4SLinus Torvalds print_cur_tb("fix_nodes"); 2591a063ae17SJeff Mahoney reiserfs_panic(tb->tb_sb, "PAP-8305", 2592c3a9c210SJeff Mahoney "there is pending do_balance"); 25931da177e4SLinus Torvalds } 25941da177e4SLinus Torvalds 2595a063ae17SJeff Mahoney if (!buffer_uptodate(tbS0) || !B_IS_IN_TREE(tbS0)) 2596a063ae17SJeff Mahoney reiserfs_panic(tb->tb_sb, "PAP-8320", "S[0] (%b %z) is " 2597c3a9c210SJeff Mahoney "not uptodate at the beginning of fix_nodes " 2598c3a9c210SJeff Mahoney "or not in tree (mode %c)", 2599ee93961bSJeff Mahoney tbS0, tbS0, op_mode); 26001da177e4SLinus Torvalds 26011da177e4SLinus Torvalds /* Check parameters. */ 2602ee93961bSJeff Mahoney switch (op_mode) { 26031da177e4SLinus Torvalds case M_INSERT: 2604ee93961bSJeff Mahoney if (item_num <= 0 || item_num > B_NR_ITEMS(tbS0)) 2605a063ae17SJeff Mahoney reiserfs_panic(tb->tb_sb, "PAP-8330", "Incorrect " 2606c3a9c210SJeff Mahoney "item number %d (in S0 - %d) in case " 2607ee93961bSJeff Mahoney "of insert", item_num, 2608a063ae17SJeff Mahoney B_NR_ITEMS(tbS0)); 26091da177e4SLinus Torvalds break; 26101da177e4SLinus Torvalds case M_PASTE: 26111da177e4SLinus Torvalds case M_DELETE: 26121da177e4SLinus Torvalds case M_CUT: 2613ee93961bSJeff Mahoney if (item_num < 0 || item_num >= B_NR_ITEMS(tbS0)) { 2614a063ae17SJeff Mahoney print_block(tbS0, 0, -1, -1); 2615a063ae17SJeff Mahoney reiserfs_panic(tb->tb_sb, "PAP-8335", "Incorrect " 2616c3a9c210SJeff Mahoney "item number(%d); mode = %c " 2617c3a9c210SJeff Mahoney "insert_size = %d", 2618ee93961bSJeff Mahoney item_num, op_mode, 2619a063ae17SJeff Mahoney tb->insert_size[0]); 26201da177e4SLinus Torvalds } 26211da177e4SLinus Torvalds break; 26221da177e4SLinus Torvalds default: 2623a063ae17SJeff Mahoney reiserfs_panic(tb->tb_sb, "PAP-8340", "Incorrect mode " 2624c3a9c210SJeff Mahoney "of operation"); 26251da177e4SLinus Torvalds } 26261da177e4SLinus Torvalds #endif 26271da177e4SLinus Torvalds 2628a063ae17SJeff Mahoney if (get_mem_for_virtual_node(tb) == REPEAT_SEARCH) 2629098297b2SJeff Mahoney /* FIXME: maybe -ENOMEM when tb->vn_buf == 0? Now just repeat */ 26301da177e4SLinus Torvalds return REPEAT_SEARCH; 26311da177e4SLinus Torvalds 2632ee93961bSJeff Mahoney /* Starting from the leaf level; for all levels h of the tree. */ 2633ee93961bSJeff Mahoney for (h = 0; h < MAX_HEIGHT && tb->insert_size[h]; h++) { 2634ee93961bSJeff Mahoney ret = get_direct_parent(tb, h); 2635ee93961bSJeff Mahoney if (ret != CARRY_ON) 26361da177e4SLinus Torvalds goto repeat; 26371da177e4SLinus Torvalds 2638ee93961bSJeff Mahoney ret = check_balance(op_mode, tb, h, item_num, 2639ee93961bSJeff Mahoney pos_in_item, ins_ih, data); 2640ee93961bSJeff Mahoney if (ret != CARRY_ON) { 2641ee93961bSJeff Mahoney if (ret == NO_BALANCING_NEEDED) { 26421da177e4SLinus Torvalds /* No balancing for higher levels needed. */ 2643ee93961bSJeff Mahoney ret = get_neighbors(tb, h); 2644ee93961bSJeff Mahoney if (ret != CARRY_ON) 26451da177e4SLinus Torvalds goto repeat; 2646ee93961bSJeff Mahoney if (h != MAX_HEIGHT - 1) 2647ee93961bSJeff Mahoney tb->insert_size[h + 1] = 0; 2648098297b2SJeff Mahoney /* 2649098297b2SJeff Mahoney * ok, analysis and resource gathering 2650098297b2SJeff Mahoney * are complete 2651098297b2SJeff Mahoney */ 26521da177e4SLinus Torvalds break; 26531da177e4SLinus Torvalds } 26541da177e4SLinus Torvalds goto repeat; 26551da177e4SLinus Torvalds } 26561da177e4SLinus Torvalds 2657ee93961bSJeff Mahoney ret = get_neighbors(tb, h); 2658ee93961bSJeff Mahoney if (ret != CARRY_ON) 26591da177e4SLinus Torvalds goto repeat; 26601da177e4SLinus Torvalds 2661098297b2SJeff Mahoney /* 2662098297b2SJeff Mahoney * No disk space, or schedule occurred and analysis may be 2663098297b2SJeff Mahoney * invalid and needs to be redone. 2664098297b2SJeff Mahoney */ 2665ee93961bSJeff Mahoney ret = get_empty_nodes(tb, h); 2666ee93961bSJeff Mahoney if (ret != CARRY_ON) 2667a063ae17SJeff Mahoney goto repeat; 26681da177e4SLinus Torvalds 2669098297b2SJeff Mahoney /* 2670098297b2SJeff Mahoney * We have a positive insert size but no nodes exist on this 2671098297b2SJeff Mahoney * level, this means that we are creating a new root. 2672098297b2SJeff Mahoney */ 2673ee93961bSJeff Mahoney if (!PATH_H_PBUFFER(tb->tb_path, h)) { 26741da177e4SLinus Torvalds 2675ee93961bSJeff Mahoney RFALSE(tb->blknum[h] != 1, 26761da177e4SLinus Torvalds "PAP-8350: creating new empty root"); 26771da177e4SLinus Torvalds 2678ee93961bSJeff Mahoney if (h < MAX_HEIGHT - 1) 2679ee93961bSJeff Mahoney tb->insert_size[h + 1] = 0; 2680ee93961bSJeff Mahoney } else if (!PATH_H_PBUFFER(tb->tb_path, h + 1)) { 2681098297b2SJeff Mahoney /* 2682098297b2SJeff Mahoney * The tree needs to be grown, so this node S[h] 2683098297b2SJeff Mahoney * which is the root node is split into two nodes, 2684098297b2SJeff Mahoney * and a new node (S[h+1]) will be created to 2685098297b2SJeff Mahoney * become the root node. 2686098297b2SJeff Mahoney */ 2687ee93961bSJeff Mahoney if (tb->blknum[h] > 1) { 26881da177e4SLinus Torvalds 2689ee93961bSJeff Mahoney RFALSE(h == MAX_HEIGHT - 1, 26901da177e4SLinus Torvalds "PAP-8355: attempt to create too high of a tree"); 26911da177e4SLinus Torvalds 2692ee93961bSJeff Mahoney tb->insert_size[h + 1] = 2693bd4c625cSLinus Torvalds (DC_SIZE + 2694ee93961bSJeff Mahoney KEY_SIZE) * (tb->blknum[h] - 1) + 2695bd4c625cSLinus Torvalds DC_SIZE; 2696ee93961bSJeff Mahoney } else if (h < MAX_HEIGHT - 1) 2697ee93961bSJeff Mahoney tb->insert_size[h + 1] = 0; 2698bd4c625cSLinus Torvalds } else 2699ee93961bSJeff Mahoney tb->insert_size[h + 1] = 2700ee93961bSJeff Mahoney (DC_SIZE + KEY_SIZE) * (tb->blknum[h] - 1); 27011da177e4SLinus Torvalds } 27021da177e4SLinus Torvalds 2703ee93961bSJeff Mahoney ret = wait_tb_buffers_until_unlocked(tb); 2704ee93961bSJeff Mahoney if (ret == CARRY_ON) { 2705a063ae17SJeff Mahoney if (FILESYSTEM_CHANGED_TB(tb)) { 27061da177e4SLinus Torvalds wait_tb_buffers_run = 1; 2707ee93961bSJeff Mahoney ret = REPEAT_SEARCH; 27081da177e4SLinus Torvalds goto repeat; 27091da177e4SLinus Torvalds } else { 27101da177e4SLinus Torvalds return CARRY_ON; 27111da177e4SLinus Torvalds } 27121da177e4SLinus Torvalds } else { 27131da177e4SLinus Torvalds wait_tb_buffers_run = 1; 27141da177e4SLinus Torvalds goto repeat; 27151da177e4SLinus Torvalds } 27161da177e4SLinus Torvalds 27171da177e4SLinus Torvalds repeat: 2718098297b2SJeff Mahoney /* 2719098297b2SJeff Mahoney * fix_nodes was unable to perform its calculation due to 2720098297b2SJeff Mahoney * filesystem got changed under us, lack of free disk space or i/o 2721098297b2SJeff Mahoney * failure. If the first is the case - the search will be 2722098297b2SJeff Mahoney * repeated. For now - free all resources acquired so far except 2723098297b2SJeff Mahoney * for the new allocated nodes 2724098297b2SJeff Mahoney */ 27251da177e4SLinus Torvalds { 27261da177e4SLinus Torvalds int i; 27271da177e4SLinus Torvalds 27281da177e4SLinus Torvalds /* Release path buffers. */ 27291da177e4SLinus Torvalds if (wait_tb_buffers_run) { 2730a063ae17SJeff Mahoney pathrelse_and_restore(tb->tb_sb, tb->tb_path); 27311da177e4SLinus Torvalds } else { 2732a063ae17SJeff Mahoney pathrelse(tb->tb_path); 27331da177e4SLinus Torvalds } 27341da177e4SLinus Torvalds /* brelse all resources collected for balancing */ 27351da177e4SLinus Torvalds for (i = 0; i < MAX_HEIGHT; i++) { 27361da177e4SLinus Torvalds if (wait_tb_buffers_run) { 2737a063ae17SJeff Mahoney reiserfs_restore_prepared_buffer(tb->tb_sb, 2738a063ae17SJeff Mahoney tb->L[i]); 2739a063ae17SJeff Mahoney reiserfs_restore_prepared_buffer(tb->tb_sb, 2740a063ae17SJeff Mahoney tb->R[i]); 2741a063ae17SJeff Mahoney reiserfs_restore_prepared_buffer(tb->tb_sb, 2742a063ae17SJeff Mahoney tb->FL[i]); 2743a063ae17SJeff Mahoney reiserfs_restore_prepared_buffer(tb->tb_sb, 2744a063ae17SJeff Mahoney tb->FR[i]); 2745a063ae17SJeff Mahoney reiserfs_restore_prepared_buffer(tb->tb_sb, 2746a063ae17SJeff Mahoney tb-> 2747bd4c625cSLinus Torvalds CFL[i]); 2748a063ae17SJeff Mahoney reiserfs_restore_prepared_buffer(tb->tb_sb, 2749a063ae17SJeff Mahoney tb-> 2750bd4c625cSLinus Torvalds CFR[i]); 27511da177e4SLinus Torvalds } 27521da177e4SLinus Torvalds 2753a063ae17SJeff Mahoney brelse(tb->L[i]); 2754a063ae17SJeff Mahoney brelse(tb->R[i]); 2755a063ae17SJeff Mahoney brelse(tb->FL[i]); 2756a063ae17SJeff Mahoney brelse(tb->FR[i]); 2757a063ae17SJeff Mahoney brelse(tb->CFL[i]); 2758a063ae17SJeff Mahoney brelse(tb->CFR[i]); 27593cd6dbe6SJeff Mahoney 2760a063ae17SJeff Mahoney tb->L[i] = NULL; 2761a063ae17SJeff Mahoney tb->R[i] = NULL; 2762a063ae17SJeff Mahoney tb->FL[i] = NULL; 2763a063ae17SJeff Mahoney tb->FR[i] = NULL; 2764a063ae17SJeff Mahoney tb->CFL[i] = NULL; 2765a063ae17SJeff Mahoney tb->CFR[i] = NULL; 27661da177e4SLinus Torvalds } 27671da177e4SLinus Torvalds 27681da177e4SLinus Torvalds if (wait_tb_buffers_run) { 27691da177e4SLinus Torvalds for (i = 0; i < MAX_FEB_SIZE; i++) { 2770a063ae17SJeff Mahoney if (tb->FEB[i]) 2771bd4c625cSLinus Torvalds reiserfs_restore_prepared_buffer 2772a063ae17SJeff Mahoney (tb->tb_sb, tb->FEB[i]); 27731da177e4SLinus Torvalds } 27741da177e4SLinus Torvalds } 2775ee93961bSJeff Mahoney return ret; 27761da177e4SLinus Torvalds } 27771da177e4SLinus Torvalds 27781da177e4SLinus Torvalds } 27791da177e4SLinus Torvalds 27801da177e4SLinus Torvalds void unfix_nodes(struct tree_balance *tb) 27811da177e4SLinus Torvalds { 27821da177e4SLinus Torvalds int i; 27831da177e4SLinus Torvalds 27841da177e4SLinus Torvalds /* Release path buffers. */ 27851da177e4SLinus Torvalds pathrelse_and_restore(tb->tb_sb, tb->tb_path); 27861da177e4SLinus Torvalds 27871da177e4SLinus Torvalds /* brelse all resources collected for balancing */ 27881da177e4SLinus Torvalds for (i = 0; i < MAX_HEIGHT; i++) { 27891da177e4SLinus Torvalds reiserfs_restore_prepared_buffer(tb->tb_sb, tb->L[i]); 27901da177e4SLinus Torvalds reiserfs_restore_prepared_buffer(tb->tb_sb, tb->R[i]); 27911da177e4SLinus Torvalds reiserfs_restore_prepared_buffer(tb->tb_sb, tb->FL[i]); 27921da177e4SLinus Torvalds reiserfs_restore_prepared_buffer(tb->tb_sb, tb->FR[i]); 27931da177e4SLinus Torvalds reiserfs_restore_prepared_buffer(tb->tb_sb, tb->CFL[i]); 27941da177e4SLinus Torvalds reiserfs_restore_prepared_buffer(tb->tb_sb, tb->CFR[i]); 27951da177e4SLinus Torvalds 27961da177e4SLinus Torvalds brelse(tb->L[i]); 27971da177e4SLinus Torvalds brelse(tb->R[i]); 27981da177e4SLinus Torvalds brelse(tb->FL[i]); 27991da177e4SLinus Torvalds brelse(tb->FR[i]); 28001da177e4SLinus Torvalds brelse(tb->CFL[i]); 28011da177e4SLinus Torvalds brelse(tb->CFR[i]); 28021da177e4SLinus Torvalds } 28031da177e4SLinus Torvalds 28041da177e4SLinus Torvalds /* deal with list of allocated (used and unused) nodes */ 28051da177e4SLinus Torvalds for (i = 0; i < MAX_FEB_SIZE; i++) { 28061da177e4SLinus Torvalds if (tb->FEB[i]) { 28071da177e4SLinus Torvalds b_blocknr_t blocknr = tb->FEB[i]->b_blocknr; 2808098297b2SJeff Mahoney /* 2809098297b2SJeff Mahoney * de-allocated block which was not used by 2810098297b2SJeff Mahoney * balancing and bforget about buffer for it 2811098297b2SJeff Mahoney */ 28121da177e4SLinus Torvalds brelse(tb->FEB[i]); 2813bd4c625cSLinus Torvalds reiserfs_free_block(tb->transaction_handle, NULL, 2814bd4c625cSLinus Torvalds blocknr, 0); 28151da177e4SLinus Torvalds } 28161da177e4SLinus Torvalds if (tb->used[i]) { 28171da177e4SLinus Torvalds /* release used as new nodes including a new root */ 28181da177e4SLinus Torvalds brelse(tb->used[i]); 28191da177e4SLinus Torvalds } 28201da177e4SLinus Torvalds } 28211da177e4SLinus Torvalds 2822d739b42bSPekka Enberg kfree(tb->vn_buf); 28231da177e4SLinus Torvalds 28241da177e4SLinus Torvalds } 2825