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