xref: /linux/fs/reiserfs/lbalance.c (revision b746a1a2860f4a918f32d10dc569115d282aaf2f)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
31da177e4SLinus Torvalds  */
41da177e4SLinus Torvalds 
517093991SFabian Frederick #include <linux/uaccess.h>
61da177e4SLinus Torvalds #include <linux/string.h>
71da177e4SLinus Torvalds #include <linux/time.h>
8f466c6fdSAl Viro #include "reiserfs.h"
91da177e4SLinus Torvalds #include <linux/buffer_head.h>
101da177e4SLinus Torvalds 
11098297b2SJeff Mahoney /*
12098297b2SJeff Mahoney  * copy copy_count entries from source directory item to dest buffer
13098297b2SJeff Mahoney  * (creating new item if needed)
141da177e4SLinus Torvalds  */
leaf_copy_dir_entries(struct buffer_info * dest_bi,struct buffer_head * source,int last_first,int item_num,int from,int copy_count)15bd4c625cSLinus Torvalds static void leaf_copy_dir_entries(struct buffer_info *dest_bi,
16bd4c625cSLinus Torvalds 				  struct buffer_head *source, int last_first,
17bd4c625cSLinus Torvalds 				  int item_num, int from, int copy_count)
181da177e4SLinus Torvalds {
191da177e4SLinus Torvalds 	struct buffer_head *dest = dest_bi->bi_bh;
20098297b2SJeff Mahoney 	/*
21098297b2SJeff Mahoney 	 * either the number of target item, or if we must create a
22098297b2SJeff Mahoney 	 * new item, the number of the item we will create it next to
23098297b2SJeff Mahoney 	 */
24098297b2SJeff Mahoney 	int item_num_in_dest;
25098297b2SJeff Mahoney 
261da177e4SLinus Torvalds 	struct item_head *ih;
271da177e4SLinus Torvalds 	struct reiserfs_de_head *deh;
281da177e4SLinus Torvalds 	int copy_records_len;	/* length of all records in item to be copied */
291da177e4SLinus Torvalds 	char *records;
301da177e4SLinus Torvalds 
314cf5f7adSJeff Mahoney 	ih = item_head(source, item_num);
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds 	RFALSE(!is_direntry_le_ih(ih), "vs-10000: item must be directory item");
341da177e4SLinus Torvalds 
35098297b2SJeff Mahoney 	/*
36098297b2SJeff Mahoney 	 * length of all record to be copied and first byte of
37098297b2SJeff Mahoney 	 * the last of them
38098297b2SJeff Mahoney 	 */
391da177e4SLinus Torvalds 	deh = B_I_DEH(source, ih);
401da177e4SLinus Torvalds 	if (copy_count) {
41a228bf8fSJeff Mahoney 		copy_records_len = (from ? deh_location(&deh[from - 1]) :
42bd4c625cSLinus Torvalds 				    ih_item_len(ih)) -
43a228bf8fSJeff Mahoney 		    deh_location(&deh[from + copy_count - 1]);
44bd4c625cSLinus Torvalds 		records =
45bd4c625cSLinus Torvalds 		    source->b_data + ih_location(ih) +
46a228bf8fSJeff Mahoney 		    deh_location(&deh[from + copy_count - 1]);
471da177e4SLinus Torvalds 	} else {
481da177e4SLinus Torvalds 		copy_records_len = 0;
491da177e4SLinus Torvalds 		records = NULL;
501da177e4SLinus Torvalds 	}
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds 	/* when copy last to first, dest buffer can contain 0 items */
53bd4c625cSLinus Torvalds 	item_num_in_dest =
54bd4c625cSLinus Torvalds 	    (last_first ==
55bd4c625cSLinus Torvalds 	     LAST_TO_FIRST) ? ((B_NR_ITEMS(dest)) ? 0 : -1) : (B_NR_ITEMS(dest)
56bd4c625cSLinus Torvalds 							       - 1);
571da177e4SLinus Torvalds 
58098297b2SJeff Mahoney 	/*
59098297b2SJeff Mahoney 	 * if there are no items in dest or the first/last item in
60098297b2SJeff Mahoney 	 * dest is not item of the same directory
61098297b2SJeff Mahoney 	 */
621da177e4SLinus Torvalds 	if ((item_num_in_dest == -1) ||
631da177e4SLinus Torvalds 	    (last_first == FIRST_TO_LAST && le_ih_k_offset(ih) == DOT_OFFSET) ||
64bd4c625cSLinus Torvalds 	    (last_first == LAST_TO_FIRST
65bd4c625cSLinus Torvalds 	     && comp_short_le_keys /*COMP_SHORT_KEYS */ (&ih->ih_key,
664cf5f7adSJeff Mahoney 							 leaf_key(dest,
67bd4c625cSLinus Torvalds 								  item_num_in_dest))))
68bd4c625cSLinus Torvalds 	{
691da177e4SLinus Torvalds 		/* create new item in dest */
701da177e4SLinus Torvalds 		struct item_head new_ih;
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds 		/* form item header */
731da177e4SLinus Torvalds 		memcpy(&new_ih.ih_key, &ih->ih_key, KEY_SIZE);
741da177e4SLinus Torvalds 		put_ih_version(&new_ih, KEY_FORMAT_3_5);
751da177e4SLinus Torvalds 		/* calculate item len */
76bd4c625cSLinus Torvalds 		put_ih_item_len(&new_ih,
77bd4c625cSLinus Torvalds 				DEH_SIZE * copy_count + copy_records_len);
781da177e4SLinus Torvalds 		put_ih_entry_count(&new_ih, 0);
791da177e4SLinus Torvalds 
801da177e4SLinus Torvalds 		if (last_first == LAST_TO_FIRST) {
811da177e4SLinus Torvalds 			/* form key by the following way */
824cf5f7adSJeff Mahoney 			if (from < ih_entry_count(ih)) {
83bd4c625cSLinus Torvalds 				set_le_ih_k_offset(&new_ih,
84a228bf8fSJeff Mahoney 						   deh_offset(&deh[from]));
851da177e4SLinus Torvalds 			} else {
86098297b2SJeff Mahoney 				/*
87098297b2SJeff Mahoney 				 * no entries will be copied to this
88098297b2SJeff Mahoney 				 * item in this function
89098297b2SJeff Mahoney 				 */
901da177e4SLinus Torvalds 				set_le_ih_k_offset(&new_ih, U32_MAX);
91098297b2SJeff Mahoney 				/*
92098297b2SJeff Mahoney 				 * this item is not yet valid, but we
93098297b2SJeff Mahoney 				 * want I_IS_DIRECTORY_ITEM to return 1
94098297b2SJeff Mahoney 				 * for it, so we -1
95098297b2SJeff Mahoney 				 */
961da177e4SLinus Torvalds 			}
97a228bf8fSJeff Mahoney 			set_le_key_k_type(KEY_FORMAT_3_5, &new_ih.ih_key,
98bd4c625cSLinus Torvalds 					  TYPE_DIRENTRY);
991da177e4SLinus Torvalds 		}
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds 		/* insert item into dest buffer */
102bd4c625cSLinus Torvalds 		leaf_insert_into_buf(dest_bi,
103bd4c625cSLinus Torvalds 				     (last_first ==
104bd4c625cSLinus Torvalds 				      LAST_TO_FIRST) ? 0 : B_NR_ITEMS(dest),
105bd4c625cSLinus Torvalds 				     &new_ih, NULL, 0);
1061da177e4SLinus Torvalds 	} else {
1071da177e4SLinus Torvalds 		/* prepare space for entries */
108bd4c625cSLinus Torvalds 		leaf_paste_in_buffer(dest_bi,
109bd4c625cSLinus Torvalds 				     (last_first ==
110bd4c625cSLinus Torvalds 				      FIRST_TO_LAST) ? (B_NR_ITEMS(dest) -
111bd4c625cSLinus Torvalds 							1) : 0, MAX_US_INT,
112bd4c625cSLinus Torvalds 				     DEH_SIZE * copy_count + copy_records_len,
113bd4c625cSLinus Torvalds 				     records, 0);
1141da177e4SLinus Torvalds 	}
1151da177e4SLinus Torvalds 
116bd4c625cSLinus Torvalds 	item_num_in_dest =
117bd4c625cSLinus Torvalds 	    (last_first == FIRST_TO_LAST) ? (B_NR_ITEMS(dest) - 1) : 0;
1181da177e4SLinus Torvalds 
119eba00305SJeff Mahoney 	leaf_paste_entries(dest_bi, item_num_in_dest,
120bd4c625cSLinus Torvalds 			   (last_first ==
1214cf5f7adSJeff Mahoney 			    FIRST_TO_LAST) ? ih_entry_count(item_head(dest,
122bd4c625cSLinus Torvalds 									  item_num_in_dest))
123bd4c625cSLinus Torvalds 			   : 0, copy_count, deh + from, records,
124bd4c625cSLinus Torvalds 			   DEH_SIZE * copy_count + copy_records_len);
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds 
127098297b2SJeff Mahoney /*
128098297b2SJeff Mahoney  * Copy the first (if last_first == FIRST_TO_LAST) or last
129098297b2SJeff Mahoney  * (last_first == LAST_TO_FIRST) item or part of it or nothing
130098297b2SJeff Mahoney  * (see the return 0 below) from SOURCE to the end (if last_first)
131098297b2SJeff Mahoney  * or beginning (!last_first) of the DEST
132098297b2SJeff Mahoney  */
1331da177e4SLinus Torvalds /* returns 1 if anything was copied, else 0 */
leaf_copy_boundary_item(struct buffer_info * dest_bi,struct buffer_head * src,int last_first,int bytes_or_entries)134bd4c625cSLinus Torvalds static int leaf_copy_boundary_item(struct buffer_info *dest_bi,
135bd4c625cSLinus Torvalds 				   struct buffer_head *src, int last_first,
1361da177e4SLinus Torvalds 				   int bytes_or_entries)
1371da177e4SLinus Torvalds {
1381da177e4SLinus Torvalds 	struct buffer_head *dest = dest_bi->bi_bh;
139098297b2SJeff Mahoney 	/* number of items in the source and destination buffers */
140098297b2SJeff Mahoney 	int dest_nr_item, src_nr_item;
1411da177e4SLinus Torvalds 	struct item_head *ih;
1421da177e4SLinus Torvalds 	struct item_head *dih;
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	dest_nr_item = B_NR_ITEMS(dest);
1451da177e4SLinus Torvalds 
146098297b2SJeff Mahoney 	/*
147098297b2SJeff Mahoney 	 * if ( DEST is empty or first item of SOURCE and last item of
148098297b2SJeff Mahoney 	 * DEST are the items of different objects or of different types )
149098297b2SJeff Mahoney 	 * then there is no need to treat this item differently from the
150098297b2SJeff Mahoney 	 * other items that we copy, so we return
151098297b2SJeff Mahoney 	 */
1521da177e4SLinus Torvalds 	if (last_first == FIRST_TO_LAST) {
1534cf5f7adSJeff Mahoney 		ih = item_head(src, 0);
1544cf5f7adSJeff Mahoney 		dih = item_head(dest, dest_nr_item - 1);
155098297b2SJeff Mahoney 
156098297b2SJeff Mahoney 		/* there is nothing to merge */
157bd4c625cSLinus Torvalds 		if (!dest_nr_item
158a228bf8fSJeff Mahoney 		    || (!op_is_left_mergeable(&ih->ih_key, src->b_size)))
1591da177e4SLinus Torvalds 			return 0;
1601da177e4SLinus Torvalds 
161bd4c625cSLinus Torvalds 		RFALSE(!ih_item_len(ih),
162bd4c625cSLinus Torvalds 		       "vs-10010: item can not have empty length");
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds 		if (is_direntry_le_ih(ih)) {
1651da177e4SLinus Torvalds 			if (bytes_or_entries == -1)
1661da177e4SLinus Torvalds 				/* copy all entries to dest */
1671da177e4SLinus Torvalds 				bytes_or_entries = ih_entry_count(ih);
168bd4c625cSLinus Torvalds 			leaf_copy_dir_entries(dest_bi, src, FIRST_TO_LAST, 0, 0,
169bd4c625cSLinus Torvalds 					      bytes_or_entries);
1701da177e4SLinus Torvalds 			return 1;
1711da177e4SLinus Torvalds 		}
1721da177e4SLinus Torvalds 
173098297b2SJeff Mahoney 		/*
174098297b2SJeff Mahoney 		 * copy part of the body of the first item of SOURCE
175098297b2SJeff Mahoney 		 * to the end of the body of the last item of the DEST
176098297b2SJeff Mahoney 		 * part defined by 'bytes_or_entries'; if bytes_or_entries
177098297b2SJeff Mahoney 		 * == -1 copy whole body; don't create new item header
1781da177e4SLinus Torvalds 		 */
1791da177e4SLinus Torvalds 		if (bytes_or_entries == -1)
1801da177e4SLinus Torvalds 			bytes_or_entries = ih_item_len(ih);
1811da177e4SLinus Torvalds 
1821da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK
1831da177e4SLinus Torvalds 		else {
184bd4c625cSLinus Torvalds 			if (bytes_or_entries == ih_item_len(ih)
185bd4c625cSLinus Torvalds 			    && is_indirect_le_ih(ih))
1861da177e4SLinus Torvalds 				if (get_ih_free_space(ih))
187c3a9c210SJeff Mahoney 					reiserfs_panic(sb_from_bi(dest_bi),
188c3a9c210SJeff Mahoney 						       "vs-10020",
189c3a9c210SJeff Mahoney 						       "last unformatted node "
190c3a9c210SJeff Mahoney 						       "must be filled "
191c3a9c210SJeff Mahoney 						       "entirely (%h)", ih);
1921da177e4SLinus Torvalds 		}
1931da177e4SLinus Torvalds #endif
1941da177e4SLinus Torvalds 
195098297b2SJeff Mahoney 		/*
196098297b2SJeff Mahoney 		 * merge first item (or its part) of src buffer with the last
197098297b2SJeff Mahoney 		 * item of dest buffer. Both are of the same file
198098297b2SJeff Mahoney 		 */
1991da177e4SLinus Torvalds 		leaf_paste_in_buffer(dest_bi,
200bd4c625cSLinus Torvalds 				     dest_nr_item - 1, ih_item_len(dih),
2014cf5f7adSJeff Mahoney 				     bytes_or_entries, ih_item_body(src, ih), 0);
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds 		if (is_indirect_le_ih(dih)) {
2041da177e4SLinus Torvalds 			RFALSE(get_ih_free_space(dih),
2051da177e4SLinus Torvalds 			       "vs-10030: merge to left: last unformatted node of non-last indirect item %h must have zerto free space",
2061da177e4SLinus Torvalds 			       ih);
2071da177e4SLinus Torvalds 			if (bytes_or_entries == ih_item_len(ih))
2081da177e4SLinus Torvalds 				set_ih_free_space(dih, get_ih_free_space(ih));
2091da177e4SLinus Torvalds 		}
2101da177e4SLinus Torvalds 
2111da177e4SLinus Torvalds 		return 1;
2121da177e4SLinus Torvalds 	}
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds 	/* copy boundary item to right (last_first == LAST_TO_FIRST) */
2151da177e4SLinus Torvalds 
216098297b2SJeff Mahoney 	/*
217098297b2SJeff Mahoney 	 * (DEST is empty or last item of SOURCE and first item of DEST
218098297b2SJeff Mahoney 	 * are the items of different object or of different types)
2191da177e4SLinus Torvalds 	 */
2201da177e4SLinus Torvalds 	src_nr_item = B_NR_ITEMS(src);
2214cf5f7adSJeff Mahoney 	ih = item_head(src, src_nr_item - 1);
2224cf5f7adSJeff Mahoney 	dih = item_head(dest, 0);
2231da177e4SLinus Torvalds 
224a228bf8fSJeff Mahoney 	if (!dest_nr_item || !op_is_left_mergeable(&dih->ih_key, src->b_size))
2251da177e4SLinus Torvalds 		return 0;
2261da177e4SLinus Torvalds 
2271da177e4SLinus Torvalds 	if (is_direntry_le_ih(ih)) {
228098297b2SJeff Mahoney 		/*
229098297b2SJeff Mahoney 		 * bytes_or_entries = entries number in last
230098297b2SJeff Mahoney 		 * item body of SOURCE
231098297b2SJeff Mahoney 		 */
2321da177e4SLinus Torvalds 		if (bytes_or_entries == -1)
2331da177e4SLinus Torvalds 			bytes_or_entries = ih_entry_count(ih);
2341da177e4SLinus Torvalds 
235bd4c625cSLinus Torvalds 		leaf_copy_dir_entries(dest_bi, src, LAST_TO_FIRST,
236bd4c625cSLinus Torvalds 				      src_nr_item - 1,
237bd4c625cSLinus Torvalds 				      ih_entry_count(ih) - bytes_or_entries,
238bd4c625cSLinus Torvalds 				      bytes_or_entries);
2391da177e4SLinus Torvalds 		return 1;
2401da177e4SLinus Torvalds 	}
2411da177e4SLinus Torvalds 
242098297b2SJeff Mahoney 	/*
243098297b2SJeff Mahoney 	 * copy part of the body of the last item of SOURCE to the
244098297b2SJeff Mahoney 	 * begin of the body of the first item of the DEST; part defined
245098297b2SJeff Mahoney 	 * by 'bytes_or_entries'; if byte_or_entriess == -1 copy whole body;
246098297b2SJeff Mahoney 	 * change first item key of the DEST; don't create new item header
2471da177e4SLinus Torvalds 	 */
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds 	RFALSE(is_indirect_le_ih(ih) && get_ih_free_space(ih),
2501da177e4SLinus Torvalds 	       "vs-10040: merge to right: last unformatted node of non-last indirect item must be filled entirely (%h)",
2511da177e4SLinus Torvalds 	       ih);
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds 	if (bytes_or_entries == -1) {
2541da177e4SLinus Torvalds 		/* bytes_or_entries = length of last item body of SOURCE */
2551da177e4SLinus Torvalds 		bytes_or_entries = ih_item_len(ih);
2561da177e4SLinus Torvalds 
2571da177e4SLinus Torvalds 		RFALSE(le_ih_k_offset(dih) !=
2581da177e4SLinus Torvalds 		       le_ih_k_offset(ih) + op_bytes_number(ih, src->b_size),
2591da177e4SLinus Torvalds 		       "vs-10050: items %h and %h do not match", ih, dih);
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds 		/* change first item key of the DEST */
2621da177e4SLinus Torvalds 		set_le_ih_k_offset(dih, le_ih_k_offset(ih));
2631da177e4SLinus Torvalds 
2641da177e4SLinus Torvalds 		/* item becomes non-mergeable */
2651da177e4SLinus Torvalds 		/* or mergeable if left item was */
2661da177e4SLinus Torvalds 		set_le_ih_k_type(dih, le_ih_k_type(ih));
2671da177e4SLinus Torvalds 	} else {
2681da177e4SLinus Torvalds 		/* merge to right only part of item */
2691da177e4SLinus Torvalds 		RFALSE(ih_item_len(ih) <= bytes_or_entries,
2701da177e4SLinus Torvalds 		       "vs-10060: no so much bytes %lu (needed %lu)",
271bd4c625cSLinus Torvalds 		       (unsigned long)ih_item_len(ih),
272bd4c625cSLinus Torvalds 		       (unsigned long)bytes_or_entries);
2731da177e4SLinus Torvalds 
2741da177e4SLinus Torvalds 		/* change first item key of the DEST */
2751da177e4SLinus Torvalds 		if (is_direct_le_ih(dih)) {
276bd4c625cSLinus Torvalds 			RFALSE(le_ih_k_offset(dih) <=
277bd4c625cSLinus Torvalds 			       (unsigned long)bytes_or_entries,
278bd4c625cSLinus Torvalds 			       "vs-10070: dih %h, bytes_or_entries(%d)", dih,
279bd4c625cSLinus Torvalds 			       bytes_or_entries);
280bd4c625cSLinus Torvalds 			set_le_ih_k_offset(dih,
281bd4c625cSLinus Torvalds 					   le_ih_k_offset(dih) -
282bd4c625cSLinus Torvalds 					   bytes_or_entries);
2831da177e4SLinus Torvalds 		} else {
2841da177e4SLinus Torvalds 			RFALSE(le_ih_k_offset(dih) <=
2851da177e4SLinus Torvalds 			       (bytes_or_entries / UNFM_P_SIZE) * dest->b_size,
2861da177e4SLinus Torvalds 			       "vs-10080: dih %h, bytes_or_entries(%d)",
287bd4c625cSLinus Torvalds 			       dih,
288bd4c625cSLinus Torvalds 			       (bytes_or_entries / UNFM_P_SIZE) * dest->b_size);
289bd4c625cSLinus Torvalds 			set_le_ih_k_offset(dih,
290bd4c625cSLinus Torvalds 					   le_ih_k_offset(dih) -
291bd4c625cSLinus Torvalds 					   ((bytes_or_entries / UNFM_P_SIZE) *
292bd4c625cSLinus Torvalds 					    dest->b_size));
2931da177e4SLinus Torvalds 		}
2941da177e4SLinus Torvalds 	}
2951da177e4SLinus Torvalds 
296bd4c625cSLinus Torvalds 	leaf_paste_in_buffer(dest_bi, 0, 0, bytes_or_entries,
2974cf5f7adSJeff Mahoney 			     ih_item_body(src,
298bd4c625cSLinus Torvalds 				       ih) + ih_item_len(ih) - bytes_or_entries,
299bd4c625cSLinus Torvalds 			     0);
3001da177e4SLinus Torvalds 	return 1;
3011da177e4SLinus Torvalds }
3021da177e4SLinus Torvalds 
303098297b2SJeff Mahoney /*
304098297b2SJeff Mahoney  * copy cpy_mun items from buffer src to buffer dest
305098297b2SJeff Mahoney  * last_first == FIRST_TO_LAST means, that we copy cpy_num items beginning
306098297b2SJeff Mahoney  *                             from first-th item in src to tail of dest
307098297b2SJeff Mahoney  * last_first == LAST_TO_FIRST means, that we copy cpy_num items beginning
308098297b2SJeff Mahoney  *                             from first-th item in src to head of dest
3091da177e4SLinus Torvalds  */
leaf_copy_items_entirely(struct buffer_info * dest_bi,struct buffer_head * src,int last_first,int first,int cpy_num)310bd4c625cSLinus Torvalds static void leaf_copy_items_entirely(struct buffer_info *dest_bi,
311bd4c625cSLinus Torvalds 				     struct buffer_head *src, int last_first,
3121da177e4SLinus Torvalds 				     int first, int cpy_num)
3131da177e4SLinus Torvalds {
3141da177e4SLinus Torvalds 	struct buffer_head *dest;
3151da177e4SLinus Torvalds 	int nr, free_space;
3161da177e4SLinus Torvalds 	int dest_before;
3171da177e4SLinus Torvalds 	int last_loc, last_inserted_loc, location;
3181da177e4SLinus Torvalds 	int i, j;
3191da177e4SLinus Torvalds 	struct block_head *blkh;
3201da177e4SLinus Torvalds 	struct item_head *ih;
3211da177e4SLinus Torvalds 
3221da177e4SLinus Torvalds 	RFALSE(last_first != LAST_TO_FIRST && last_first != FIRST_TO_LAST,
3231da177e4SLinus Torvalds 	       "vs-10090: bad last_first parameter %d", last_first);
3241da177e4SLinus Torvalds 	RFALSE(B_NR_ITEMS(src) - first < cpy_num,
3251da177e4SLinus Torvalds 	       "vs-10100: too few items in source %d, required %d from %d",
3261da177e4SLinus Torvalds 	       B_NR_ITEMS(src), cpy_num, first);
3271da177e4SLinus Torvalds 	RFALSE(cpy_num < 0, "vs-10110: can not copy negative amount of items");
3281da177e4SLinus Torvalds 	RFALSE(!dest_bi, "vs-10120: can not copy negative amount of items");
3291da177e4SLinus Torvalds 
3301da177e4SLinus Torvalds 	dest = dest_bi->bi_bh;
3311da177e4SLinus Torvalds 
3321da177e4SLinus Torvalds 	RFALSE(!dest, "vs-10130: can not copy negative amount of items");
3331da177e4SLinus Torvalds 
3341da177e4SLinus Torvalds 	if (cpy_num == 0)
3351da177e4SLinus Torvalds 		return;
3361da177e4SLinus Torvalds 
3371da177e4SLinus Torvalds 	blkh = B_BLK_HEAD(dest);
3381da177e4SLinus Torvalds 	nr = blkh_nr_item(blkh);
3391da177e4SLinus Torvalds 	free_space = blkh_free_space(blkh);
3401da177e4SLinus Torvalds 
341098297b2SJeff Mahoney 	/*
342098297b2SJeff Mahoney 	 * we will insert items before 0-th or nr-th item in dest buffer.
343098297b2SJeff Mahoney 	 * It depends of last_first parameter
344098297b2SJeff Mahoney 	 */
3451da177e4SLinus Torvalds 	dest_before = (last_first == LAST_TO_FIRST) ? 0 : nr;
3461da177e4SLinus Torvalds 
3471da177e4SLinus Torvalds 	/* location of head of first new item */
3484cf5f7adSJeff Mahoney 	ih = item_head(dest, dest_before);
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds 	RFALSE(blkh_free_space(blkh) < cpy_num * IH_SIZE,
3511da177e4SLinus Torvalds 	       "vs-10140: not enough free space for headers %d (needed %d)",
3521da177e4SLinus Torvalds 	       B_FREE_SPACE(dest), cpy_num * IH_SIZE);
3531da177e4SLinus Torvalds 
3541da177e4SLinus Torvalds 	/* prepare space for headers */
3551da177e4SLinus Torvalds 	memmove(ih + cpy_num, ih, (nr - dest_before) * IH_SIZE);
3561da177e4SLinus Torvalds 
3571da177e4SLinus Torvalds 	/* copy item headers */
3584cf5f7adSJeff Mahoney 	memcpy(ih, item_head(src, first), cpy_num * IH_SIZE);
3591da177e4SLinus Torvalds 
3601da177e4SLinus Torvalds 	free_space -= (IH_SIZE * cpy_num);
3611da177e4SLinus Torvalds 	set_blkh_free_space(blkh, free_space);
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 	/* location of unmovable item */
3641da177e4SLinus Torvalds 	j = location = (dest_before == 0) ? dest->b_size : ih_location(ih - 1);
3651da177e4SLinus Torvalds 	for (i = dest_before; i < nr + cpy_num; i++) {
3661da177e4SLinus Torvalds 		location -= ih_item_len(ih + i - dest_before);
3671da177e4SLinus Torvalds 		put_ih_location(ih + i - dest_before, location);
3681da177e4SLinus Torvalds 	}
3691da177e4SLinus Torvalds 
3701da177e4SLinus Torvalds 	/* prepare space for items */
371a228bf8fSJeff Mahoney 	last_loc = ih_location(&ih[nr + cpy_num - 1 - dest_before]);
372a228bf8fSJeff Mahoney 	last_inserted_loc = ih_location(&ih[cpy_num - 1]);
3731da177e4SLinus Torvalds 
3741da177e4SLinus Torvalds 	/* check free space */
3751da177e4SLinus Torvalds 	RFALSE(free_space < j - last_inserted_loc,
3761da177e4SLinus Torvalds 	       "vs-10150: not enough free space for items %d (needed %d)",
3771da177e4SLinus Torvalds 	       free_space, j - last_inserted_loc);
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 	memmove(dest->b_data + last_loc,
3801da177e4SLinus Torvalds 		dest->b_data + last_loc + j - last_inserted_loc,
3811da177e4SLinus Torvalds 		last_inserted_loc - last_loc);
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 	/* copy items */
384bd4c625cSLinus Torvalds 	memcpy(dest->b_data + last_inserted_loc,
3854cf5f7adSJeff Mahoney 	       item_body(src, (first + cpy_num - 1)),
3864cf5f7adSJeff Mahoney 	       j - last_inserted_loc);
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 	/* sizes, item number */
3891da177e4SLinus Torvalds 	set_blkh_nr_item(blkh, nr + cpy_num);
3901da177e4SLinus Torvalds 	set_blkh_free_space(blkh, free_space - (j - last_inserted_loc));
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds 	do_balance_mark_leaf_dirty(dest_bi->tb, dest, 0);
3931da177e4SLinus Torvalds 
3941da177e4SLinus Torvalds 	if (dest_bi->bi_parent) {
3951da177e4SLinus Torvalds 		struct disk_child *t_dc;
3961da177e4SLinus Torvalds 		t_dc = B_N_CHILD(dest_bi->bi_parent, dest_bi->bi_position);
3971da177e4SLinus Torvalds 		RFALSE(dc_block_number(t_dc) != dest->b_blocknr,
3981da177e4SLinus Torvalds 		       "vs-10160: block number in bh does not match to field in disk_child structure %lu and %lu",
3991da177e4SLinus Torvalds 		       (long unsigned)dest->b_blocknr,
4001da177e4SLinus Torvalds 		       (long unsigned)dc_block_number(t_dc));
401bd4c625cSLinus Torvalds 		put_dc_size(t_dc,
402bd4c625cSLinus Torvalds 			    dc_size(t_dc) + (j - last_inserted_loc +
403bd4c625cSLinus Torvalds 					     IH_SIZE * cpy_num));
4041da177e4SLinus Torvalds 
405bd4c625cSLinus Torvalds 		do_balance_mark_internal_dirty(dest_bi->tb, dest_bi->bi_parent,
406bd4c625cSLinus Torvalds 					       0);
4071da177e4SLinus Torvalds 	}
4081da177e4SLinus Torvalds }
4091da177e4SLinus Torvalds 
410098297b2SJeff Mahoney /*
411098297b2SJeff Mahoney  * This function splits the (liquid) item into two items (useful when
412098297b2SJeff Mahoney  * shifting part of an item into another node.)
413098297b2SJeff Mahoney  */
leaf_item_bottle(struct buffer_info * dest_bi,struct buffer_head * src,int last_first,int item_num,int cpy_bytes)414bd4c625cSLinus Torvalds static void leaf_item_bottle(struct buffer_info *dest_bi,
415bd4c625cSLinus Torvalds 			     struct buffer_head *src, int last_first,
4161da177e4SLinus Torvalds 			     int item_num, int cpy_bytes)
4171da177e4SLinus Torvalds {
4181da177e4SLinus Torvalds 	struct buffer_head *dest = dest_bi->bi_bh;
4191da177e4SLinus Torvalds 	struct item_head *ih;
4201da177e4SLinus Torvalds 
421bd4c625cSLinus Torvalds 	RFALSE(cpy_bytes == -1,
422bd4c625cSLinus Torvalds 	       "vs-10170: bytes == - 1 means: do not split item");
4231da177e4SLinus Torvalds 
4241da177e4SLinus Torvalds 	if (last_first == FIRST_TO_LAST) {
425098297b2SJeff Mahoney 		/*
426098297b2SJeff Mahoney 		 * if ( if item in position item_num in buffer SOURCE
427098297b2SJeff Mahoney 		 * is directory item )
428098297b2SJeff Mahoney 		 */
4294cf5f7adSJeff Mahoney 		ih = item_head(src, item_num);
4301d965fe0SJeff Mahoney 		if (is_direntry_le_ih(ih))
431bd4c625cSLinus Torvalds 			leaf_copy_dir_entries(dest_bi, src, FIRST_TO_LAST,
432bd4c625cSLinus Torvalds 					      item_num, 0, cpy_bytes);
4331da177e4SLinus Torvalds 		else {
4341da177e4SLinus Torvalds 			struct item_head n_ih;
4351da177e4SLinus Torvalds 
436098297b2SJeff Mahoney 			/*
437098297b2SJeff Mahoney 			 * copy part of the body of the item number 'item_num'
438098297b2SJeff Mahoney 			 * of SOURCE to the end of the DEST part defined by
439098297b2SJeff Mahoney 			 * 'cpy_bytes'; create new item header; change old
440098297b2SJeff Mahoney 			 * item_header (????); n_ih = new item_header;
4411da177e4SLinus Torvalds 			 */
4421da177e4SLinus Torvalds 			memcpy(&n_ih, ih, IH_SIZE);
4431da177e4SLinus Torvalds 			put_ih_item_len(&n_ih, cpy_bytes);
4441da177e4SLinus Torvalds 			if (is_indirect_le_ih(ih)) {
445bd4c625cSLinus Torvalds 				RFALSE(cpy_bytes == ih_item_len(ih)
446bd4c625cSLinus Torvalds 				       && get_ih_free_space(ih),
4471da177e4SLinus Torvalds 				       "vs-10180: when whole indirect item is bottle to left neighbor, it must have free_space==0 (not %lu)",
4481da177e4SLinus Torvalds 				       (long unsigned)get_ih_free_space(ih));
4491da177e4SLinus Torvalds 				set_ih_free_space(&n_ih, 0);
4501da177e4SLinus Torvalds 			}
4511da177e4SLinus Torvalds 
452a228bf8fSJeff Mahoney 			RFALSE(op_is_left_mergeable(&ih->ih_key, src->b_size),
4531da177e4SLinus Torvalds 			       "vs-10190: bad mergeability of item %h", ih);
4541da177e4SLinus Torvalds 			n_ih.ih_version = ih->ih_version;	/* JDM Endian safe, both le */
455bd4c625cSLinus Torvalds 			leaf_insert_into_buf(dest_bi, B_NR_ITEMS(dest), &n_ih,
4564cf5f7adSJeff Mahoney 					     item_body(src, item_num), 0);
4571da177e4SLinus Torvalds 		}
4581da177e4SLinus Torvalds 	} else {
459098297b2SJeff Mahoney 		/*
460098297b2SJeff Mahoney 		 * if ( if item in position item_num in buffer
461098297b2SJeff Mahoney 		 * SOURCE is directory item )
462098297b2SJeff Mahoney 		 */
4634cf5f7adSJeff Mahoney 		ih = item_head(src, item_num);
4641d965fe0SJeff Mahoney 		if (is_direntry_le_ih(ih))
465bd4c625cSLinus Torvalds 			leaf_copy_dir_entries(dest_bi, src, LAST_TO_FIRST,
466bd4c625cSLinus Torvalds 					      item_num,
4674cf5f7adSJeff Mahoney 					      ih_entry_count(ih) - cpy_bytes,
468bd4c625cSLinus Torvalds 					      cpy_bytes);
4691da177e4SLinus Torvalds 		else {
4701da177e4SLinus Torvalds 			struct item_head n_ih;
4711da177e4SLinus Torvalds 
472098297b2SJeff Mahoney 			/*
473098297b2SJeff Mahoney 			 * copy part of the body of the item number 'item_num'
474098297b2SJeff Mahoney 			 * of SOURCE to the begin of the DEST part defined by
475098297b2SJeff Mahoney 			 * 'cpy_bytes'; create new item header;
476098297b2SJeff Mahoney 			 * n_ih = new item_header;
4771da177e4SLinus Torvalds 			 */
478ab494964SArnd Bergmann 			memcpy(&n_ih.ih_key, &ih->ih_key, KEY_SIZE);
4791da177e4SLinus Torvalds 
480098297b2SJeff Mahoney 			/* Endian safe, both le */
481098297b2SJeff Mahoney 			n_ih.ih_version = ih->ih_version;
4821da177e4SLinus Torvalds 
4831da177e4SLinus Torvalds 			if (is_direct_le_ih(ih)) {
484bd4c625cSLinus Torvalds 				set_le_ih_k_offset(&n_ih,
485bd4c625cSLinus Torvalds 						   le_ih_k_offset(ih) +
486bd4c625cSLinus Torvalds 						   ih_item_len(ih) - cpy_bytes);
4871da177e4SLinus Torvalds 				set_le_ih_k_type(&n_ih, TYPE_DIRECT);
4881da177e4SLinus Torvalds 				set_ih_free_space(&n_ih, MAX_US_INT);
4891da177e4SLinus Torvalds 			} else {
4901da177e4SLinus Torvalds 				/* indirect item */
4911da177e4SLinus Torvalds 				RFALSE(!cpy_bytes && get_ih_free_space(ih),
4921da177e4SLinus Torvalds 				       "vs-10200: ih->ih_free_space must be 0 when indirect item will be appended");
493bd4c625cSLinus Torvalds 				set_le_ih_k_offset(&n_ih,
494bd4c625cSLinus Torvalds 						   le_ih_k_offset(ih) +
495bd4c625cSLinus Torvalds 						   (ih_item_len(ih) -
496bd4c625cSLinus Torvalds 						    cpy_bytes) / UNFM_P_SIZE *
497bd4c625cSLinus Torvalds 						   dest->b_size);
4981da177e4SLinus Torvalds 				set_le_ih_k_type(&n_ih, TYPE_INDIRECT);
4991da177e4SLinus Torvalds 				set_ih_free_space(&n_ih, get_ih_free_space(ih));
5001da177e4SLinus Torvalds 			}
5011da177e4SLinus Torvalds 
5021da177e4SLinus Torvalds 			/* set item length */
5031da177e4SLinus Torvalds 			put_ih_item_len(&n_ih, cpy_bytes);
5041da177e4SLinus Torvalds 
505098297b2SJeff Mahoney 			/* Endian safe, both le */
506098297b2SJeff Mahoney 			n_ih.ih_version = ih->ih_version;
5071da177e4SLinus Torvalds 
508bd4c625cSLinus Torvalds 			leaf_insert_into_buf(dest_bi, 0, &n_ih,
5094cf5f7adSJeff Mahoney 					     item_body(src, item_num) +
510bd4c625cSLinus Torvalds 						ih_item_len(ih) - cpy_bytes, 0);
5111da177e4SLinus Torvalds 		}
5121da177e4SLinus Torvalds 	}
5131da177e4SLinus Torvalds }
5141da177e4SLinus Torvalds 
515098297b2SJeff Mahoney /*
516098297b2SJeff Mahoney  * If cpy_bytes equals minus one than copy cpy_num whole items from SOURCE
517098297b2SJeff Mahoney  * to DEST.  If cpy_bytes not equal to minus one than copy cpy_num-1 whole
518098297b2SJeff Mahoney  * items from SOURCE to DEST.  From last item copy cpy_num bytes for regular
519098297b2SJeff Mahoney  * item and cpy_num directory entries for directory item.
520098297b2SJeff Mahoney  */
leaf_copy_items(struct buffer_info * dest_bi,struct buffer_head * src,int last_first,int cpy_num,int cpy_bytes)521bd4c625cSLinus Torvalds static int leaf_copy_items(struct buffer_info *dest_bi, struct buffer_head *src,
522bd4c625cSLinus Torvalds 			   int last_first, int cpy_num, int cpy_bytes)
5231da177e4SLinus Torvalds {
5241da177e4SLinus Torvalds 	struct buffer_head *dest;
5251da177e4SLinus Torvalds 	int pos, i, src_nr_item, bytes;
5261da177e4SLinus Torvalds 
5271da177e4SLinus Torvalds 	dest = dest_bi->bi_bh;
5281da177e4SLinus Torvalds 	RFALSE(!dest || !src, "vs-10210: !dest || !src");
5291da177e4SLinus Torvalds 	RFALSE(last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST,
5301da177e4SLinus Torvalds 	       "vs-10220:last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST");
5311da177e4SLinus Torvalds 	RFALSE(B_NR_ITEMS(src) < cpy_num,
532bd4c625cSLinus Torvalds 	       "vs-10230: No enough items: %d, req. %d", B_NR_ITEMS(src),
533bd4c625cSLinus Torvalds 	       cpy_num);
5341da177e4SLinus Torvalds 	RFALSE(cpy_num < 0, "vs-10240: cpy_num < 0 (%d)", cpy_num);
5351da177e4SLinus Torvalds 
5361da177e4SLinus Torvalds 	if (cpy_num == 0)
5371da177e4SLinus Torvalds 		return 0;
5381da177e4SLinus Torvalds 
5391da177e4SLinus Torvalds 	if (last_first == FIRST_TO_LAST) {
5401da177e4SLinus Torvalds 		/* copy items to left */
5411da177e4SLinus Torvalds 		pos = 0;
5421da177e4SLinus Torvalds 		if (cpy_num == 1)
5431da177e4SLinus Torvalds 			bytes = cpy_bytes;
5441da177e4SLinus Torvalds 		else
5451da177e4SLinus Torvalds 			bytes = -1;
5461da177e4SLinus Torvalds 
547098297b2SJeff Mahoney 		/*
548098297b2SJeff Mahoney 		 * copy the first item or it part or nothing to the end of
549098297b2SJeff Mahoney 		 * the DEST (i = leaf_copy_boundary_item(DEST,SOURCE,0,bytes))
550098297b2SJeff Mahoney 		 */
5511da177e4SLinus Torvalds 		i = leaf_copy_boundary_item(dest_bi, src, FIRST_TO_LAST, bytes);
5521da177e4SLinus Torvalds 		cpy_num -= i;
5531da177e4SLinus Torvalds 		if (cpy_num == 0)
5541da177e4SLinus Torvalds 			return i;
5551da177e4SLinus Torvalds 		pos += i;
5561da177e4SLinus Torvalds 		if (cpy_bytes == -1)
557098297b2SJeff Mahoney 			/*
558098297b2SJeff Mahoney 			 * copy first cpy_num items starting from position
559098297b2SJeff Mahoney 			 * 'pos' of SOURCE to end of DEST
560098297b2SJeff Mahoney 			 */
561bd4c625cSLinus Torvalds 			leaf_copy_items_entirely(dest_bi, src, FIRST_TO_LAST,
562bd4c625cSLinus Torvalds 						 pos, cpy_num);
5631da177e4SLinus Torvalds 		else {
564098297b2SJeff Mahoney 			/*
565098297b2SJeff Mahoney 			 * copy first cpy_num-1 items starting from position
566098297b2SJeff Mahoney 			 * 'pos-1' of the SOURCE to the end of the DEST
567098297b2SJeff Mahoney 			 */
568bd4c625cSLinus Torvalds 			leaf_copy_items_entirely(dest_bi, src, FIRST_TO_LAST,
569bd4c625cSLinus Torvalds 						 pos, cpy_num - 1);
5701da177e4SLinus Torvalds 
571098297b2SJeff Mahoney 			/*
572098297b2SJeff Mahoney 			 * copy part of the item which number is
573098297b2SJeff Mahoney 			 * cpy_num+pos-1 to the end of the DEST
574098297b2SJeff Mahoney 			 */
575bd4c625cSLinus Torvalds 			leaf_item_bottle(dest_bi, src, FIRST_TO_LAST,
576bd4c625cSLinus Torvalds 					 cpy_num + pos - 1, cpy_bytes);
5771da177e4SLinus Torvalds 		}
5781da177e4SLinus Torvalds 	} else {
5791da177e4SLinus Torvalds 		/* copy items to right */
5801da177e4SLinus Torvalds 		src_nr_item = B_NR_ITEMS(src);
5811da177e4SLinus Torvalds 		if (cpy_num == 1)
5821da177e4SLinus Torvalds 			bytes = cpy_bytes;
5831da177e4SLinus Torvalds 		else
5841da177e4SLinus Torvalds 			bytes = -1;
5851da177e4SLinus Torvalds 
586098297b2SJeff Mahoney 		/*
587098297b2SJeff Mahoney 		 * copy the last item or it part or nothing to the
588098297b2SJeff Mahoney 		 * begin of the DEST
589098297b2SJeff Mahoney 		 * (i = leaf_copy_boundary_item(DEST,SOURCE,1,bytes));
590098297b2SJeff Mahoney 		 */
5911da177e4SLinus Torvalds 		i = leaf_copy_boundary_item(dest_bi, src, LAST_TO_FIRST, bytes);
5921da177e4SLinus Torvalds 
5931da177e4SLinus Torvalds 		cpy_num -= i;
5941da177e4SLinus Torvalds 		if (cpy_num == 0)
5951da177e4SLinus Torvalds 			return i;
5961da177e4SLinus Torvalds 
5971da177e4SLinus Torvalds 		pos = src_nr_item - cpy_num - i;
5981da177e4SLinus Torvalds 		if (cpy_bytes == -1) {
599098297b2SJeff Mahoney 			/*
600098297b2SJeff Mahoney 			 * starting from position 'pos' copy last cpy_num
601098297b2SJeff Mahoney 			 * items of SOURCE to begin of DEST
602098297b2SJeff Mahoney 			 */
603bd4c625cSLinus Torvalds 			leaf_copy_items_entirely(dest_bi, src, LAST_TO_FIRST,
604bd4c625cSLinus Torvalds 						 pos, cpy_num);
6051da177e4SLinus Torvalds 		} else {
606098297b2SJeff Mahoney 			/*
607098297b2SJeff Mahoney 			 * copy last cpy_num-1 items starting from position
608098297b2SJeff Mahoney 			 * 'pos+1' of the SOURCE to the begin of the DEST;
609098297b2SJeff Mahoney 			 */
610bd4c625cSLinus Torvalds 			leaf_copy_items_entirely(dest_bi, src, LAST_TO_FIRST,
611bd4c625cSLinus Torvalds 						 pos + 1, cpy_num - 1);
6121da177e4SLinus Torvalds 
613098297b2SJeff Mahoney 			/*
614098297b2SJeff Mahoney 			 * copy part of the item which number is pos to
615098297b2SJeff Mahoney 			 * the begin of the DEST
616098297b2SJeff Mahoney 			 */
617bd4c625cSLinus Torvalds 			leaf_item_bottle(dest_bi, src, LAST_TO_FIRST, pos,
618bd4c625cSLinus Torvalds 					 cpy_bytes);
6191da177e4SLinus Torvalds 		}
6201da177e4SLinus Torvalds 	}
6211da177e4SLinus Torvalds 	return i;
6221da177e4SLinus Torvalds }
6231da177e4SLinus Torvalds 
624098297b2SJeff Mahoney /*
625098297b2SJeff Mahoney  * there are types of coping: from S[0] to L[0], from S[0] to R[0],
626098297b2SJeff Mahoney  * from R[0] to L[0]. for each of these we have to define parent and
627098297b2SJeff Mahoney  * positions of destination and source buffers
628098297b2SJeff Mahoney  */
leaf_define_dest_src_infos(int shift_mode,struct tree_balance * tb,struct buffer_info * dest_bi,struct buffer_info * src_bi,int * first_last,struct buffer_head * Snew)629bd4c625cSLinus Torvalds static void leaf_define_dest_src_infos(int shift_mode, struct tree_balance *tb,
630bd4c625cSLinus Torvalds 				       struct buffer_info *dest_bi,
631bd4c625cSLinus Torvalds 				       struct buffer_info *src_bi,
632bd4c625cSLinus Torvalds 				       int *first_last,
6331da177e4SLinus Torvalds 				       struct buffer_head *Snew)
6341da177e4SLinus Torvalds {
6351da177e4SLinus Torvalds 	memset(dest_bi, 0, sizeof(struct buffer_info));
6361da177e4SLinus Torvalds 	memset(src_bi, 0, sizeof(struct buffer_info));
6371da177e4SLinus Torvalds 
6381da177e4SLinus Torvalds 	/* define dest, src, dest parent, dest position */
6391da177e4SLinus Torvalds 	switch (shift_mode) {
6401da177e4SLinus Torvalds 	case LEAF_FROM_S_TO_L:	/* it is used in leaf_shift_left */
6411da177e4SLinus Torvalds 		src_bi->tb = tb;
6421da177e4SLinus Torvalds 		src_bi->bi_bh = PATH_PLAST_BUFFER(tb->tb_path);
6431da177e4SLinus Torvalds 		src_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
644098297b2SJeff Mahoney 
645098297b2SJeff Mahoney 		/* src->b_item_order */
646098297b2SJeff Mahoney 		src_bi->bi_position = PATH_H_B_ITEM_ORDER(tb->tb_path, 0);
6471da177e4SLinus Torvalds 		dest_bi->tb = tb;
6481da177e4SLinus Torvalds 		dest_bi->bi_bh = tb->L[0];
6491da177e4SLinus Torvalds 		dest_bi->bi_parent = tb->FL[0];
6501da177e4SLinus Torvalds 		dest_bi->bi_position = get_left_neighbor_position(tb, 0);
6511da177e4SLinus Torvalds 		*first_last = FIRST_TO_LAST;
6521da177e4SLinus Torvalds 		break;
6531da177e4SLinus Torvalds 
6541da177e4SLinus Torvalds 	case LEAF_FROM_S_TO_R:	/* it is used in leaf_shift_right */
6551da177e4SLinus Torvalds 		src_bi->tb = tb;
6561da177e4SLinus Torvalds 		src_bi->bi_bh = PATH_PLAST_BUFFER(tb->tb_path);
6571da177e4SLinus Torvalds 		src_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
6581da177e4SLinus Torvalds 		src_bi->bi_position = PATH_H_B_ITEM_ORDER(tb->tb_path, 0);
6591da177e4SLinus Torvalds 		dest_bi->tb = tb;
6601da177e4SLinus Torvalds 		dest_bi->bi_bh = tb->R[0];
6611da177e4SLinus Torvalds 		dest_bi->bi_parent = tb->FR[0];
6621da177e4SLinus Torvalds 		dest_bi->bi_position = get_right_neighbor_position(tb, 0);
6631da177e4SLinus Torvalds 		*first_last = LAST_TO_FIRST;
6641da177e4SLinus Torvalds 		break;
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	case LEAF_FROM_R_TO_L:	/* it is used in balance_leaf_when_delete */
6671da177e4SLinus Torvalds 		src_bi->tb = tb;
6681da177e4SLinus Torvalds 		src_bi->bi_bh = tb->R[0];
6691da177e4SLinus Torvalds 		src_bi->bi_parent = tb->FR[0];
6701da177e4SLinus Torvalds 		src_bi->bi_position = get_right_neighbor_position(tb, 0);
6711da177e4SLinus Torvalds 		dest_bi->tb = tb;
6721da177e4SLinus Torvalds 		dest_bi->bi_bh = tb->L[0];
6731da177e4SLinus Torvalds 		dest_bi->bi_parent = tb->FL[0];
6741da177e4SLinus Torvalds 		dest_bi->bi_position = get_left_neighbor_position(tb, 0);
6751da177e4SLinus Torvalds 		*first_last = FIRST_TO_LAST;
6761da177e4SLinus Torvalds 		break;
6771da177e4SLinus Torvalds 
6781da177e4SLinus Torvalds 	case LEAF_FROM_L_TO_R:	/* it is used in balance_leaf_when_delete */
6791da177e4SLinus Torvalds 		src_bi->tb = tb;
6801da177e4SLinus Torvalds 		src_bi->bi_bh = tb->L[0];
6811da177e4SLinus Torvalds 		src_bi->bi_parent = tb->FL[0];
6821da177e4SLinus Torvalds 		src_bi->bi_position = get_left_neighbor_position(tb, 0);
6831da177e4SLinus Torvalds 		dest_bi->tb = tb;
6841da177e4SLinus Torvalds 		dest_bi->bi_bh = tb->R[0];
6851da177e4SLinus Torvalds 		dest_bi->bi_parent = tb->FR[0];
6861da177e4SLinus Torvalds 		dest_bi->bi_position = get_right_neighbor_position(tb, 0);
6871da177e4SLinus Torvalds 		*first_last = LAST_TO_FIRST;
6881da177e4SLinus Torvalds 		break;
6891da177e4SLinus Torvalds 
6901da177e4SLinus Torvalds 	case LEAF_FROM_S_TO_SNEW:
6911da177e4SLinus Torvalds 		src_bi->tb = tb;
6921da177e4SLinus Torvalds 		src_bi->bi_bh = PATH_PLAST_BUFFER(tb->tb_path);
6931da177e4SLinus Torvalds 		src_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
6941da177e4SLinus Torvalds 		src_bi->bi_position = PATH_H_B_ITEM_ORDER(tb->tb_path, 0);
6951da177e4SLinus Torvalds 		dest_bi->tb = tb;
6961da177e4SLinus Torvalds 		dest_bi->bi_bh = Snew;
6971da177e4SLinus Torvalds 		dest_bi->bi_parent = NULL;
6981da177e4SLinus Torvalds 		dest_bi->bi_position = 0;
6991da177e4SLinus Torvalds 		*first_last = LAST_TO_FIRST;
7001da177e4SLinus Torvalds 		break;
7011da177e4SLinus Torvalds 
7021da177e4SLinus Torvalds 	default:
703c3a9c210SJeff Mahoney 		reiserfs_panic(sb_from_bi(src_bi), "vs-10250",
704c3a9c210SJeff Mahoney 			       "shift type is unknown (%d)", shift_mode);
7051da177e4SLinus Torvalds 	}
7069dce07f1SAl Viro 	RFALSE(!src_bi->bi_bh || !dest_bi->bi_bh,
7071da177e4SLinus Torvalds 	       "vs-10260: mode==%d, source (%p) or dest (%p) buffer is initialized incorrectly",
7081da177e4SLinus Torvalds 	       shift_mode, src_bi->bi_bh, dest_bi->bi_bh);
7091da177e4SLinus Torvalds }
7101da177e4SLinus Torvalds 
711098297b2SJeff Mahoney /*
712098297b2SJeff Mahoney  * copy mov_num items and mov_bytes of the (mov_num-1)th item to
713098297b2SJeff Mahoney  * neighbor. Delete them from source
714098297b2SJeff Mahoney  */
leaf_move_items(int shift_mode,struct tree_balance * tb,int mov_num,int mov_bytes,struct buffer_head * Snew)715bd4c625cSLinus Torvalds int leaf_move_items(int shift_mode, struct tree_balance *tb, int mov_num,
716bd4c625cSLinus Torvalds 		    int mov_bytes, struct buffer_head *Snew)
7171da177e4SLinus Torvalds {
7181da177e4SLinus Torvalds 	int ret_value;
7191da177e4SLinus Torvalds 	struct buffer_info dest_bi, src_bi;
7201da177e4SLinus Torvalds 	int first_last;
7211da177e4SLinus Torvalds 
722bd4c625cSLinus Torvalds 	leaf_define_dest_src_infos(shift_mode, tb, &dest_bi, &src_bi,
723bd4c625cSLinus Torvalds 				   &first_last, Snew);
7241da177e4SLinus Torvalds 
725bd4c625cSLinus Torvalds 	ret_value =
726bd4c625cSLinus Torvalds 	    leaf_copy_items(&dest_bi, src_bi.bi_bh, first_last, mov_num,
727bd4c625cSLinus Torvalds 			    mov_bytes);
7281da177e4SLinus Torvalds 
729bd4c625cSLinus Torvalds 	leaf_delete_items(&src_bi, first_last,
730bd4c625cSLinus Torvalds 			  (first_last ==
731bd4c625cSLinus Torvalds 			   FIRST_TO_LAST) ? 0 : (B_NR_ITEMS(src_bi.bi_bh) -
732bd4c625cSLinus Torvalds 						 mov_num), mov_num, mov_bytes);
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 	return ret_value;
7351da177e4SLinus Torvalds }
7361da177e4SLinus Torvalds 
737098297b2SJeff Mahoney /*
738098297b2SJeff Mahoney  * Shift shift_num items (and shift_bytes of last shifted item if
739098297b2SJeff Mahoney  * shift_bytes != -1) from S[0] to L[0] and replace the delimiting key
740098297b2SJeff Mahoney  */
leaf_shift_left(struct tree_balance * tb,int shift_num,int shift_bytes)7411da177e4SLinus Torvalds int leaf_shift_left(struct tree_balance *tb, int shift_num, int shift_bytes)
7421da177e4SLinus Torvalds {
7431da177e4SLinus Torvalds 	struct buffer_head *S0 = PATH_PLAST_BUFFER(tb->tb_path);
7441da177e4SLinus Torvalds 	int i;
7451da177e4SLinus Torvalds 
746098297b2SJeff Mahoney 	/*
747098297b2SJeff Mahoney 	 * move shift_num (and shift_bytes bytes) items from S[0]
748098297b2SJeff Mahoney 	 * to left neighbor L[0]
749098297b2SJeff Mahoney 	 */
7501da177e4SLinus Torvalds 	i = leaf_move_items(LEAF_FROM_S_TO_L, tb, shift_num, shift_bytes, NULL);
7511da177e4SLinus Torvalds 
7521da177e4SLinus Torvalds 	if (shift_num) {
753098297b2SJeff Mahoney 		/* number of items in S[0] == 0 */
754098297b2SJeff Mahoney 		if (B_NR_ITEMS(S0) == 0) {
7551da177e4SLinus Torvalds 
7561da177e4SLinus Torvalds 			RFALSE(shift_bytes != -1,
7571da177e4SLinus Torvalds 			       "vs-10270: S0 is empty now, but shift_bytes != -1 (%d)",
7581da177e4SLinus Torvalds 			       shift_bytes);
7591da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK
7601da177e4SLinus Torvalds 			if (tb->tb_mode == M_PASTE || tb->tb_mode == M_INSERT) {
7611da177e4SLinus Torvalds 				print_cur_tb("vs-10275");
762c3a9c210SJeff Mahoney 				reiserfs_panic(tb->tb_sb, "vs-10275",
763c3a9c210SJeff Mahoney 					       "balance condition corrupted "
764c3a9c210SJeff Mahoney 					       "(%c)", tb->tb_mode);
7651da177e4SLinus Torvalds 			}
7661da177e4SLinus Torvalds #endif
7671da177e4SLinus Torvalds 
7681da177e4SLinus Torvalds 			if (PATH_H_POSITION(tb->tb_path, 1) == 0)
769bd4c625cSLinus Torvalds 				replace_key(tb, tb->CFL[0], tb->lkey[0],
770bd4c625cSLinus Torvalds 					    PATH_H_PPARENT(tb->tb_path, 0), 0);
7711da177e4SLinus Torvalds 
7721da177e4SLinus Torvalds 		} else {
7731da177e4SLinus Torvalds 			/* replace lkey in CFL[0] by 0-th key from S[0]; */
7741da177e4SLinus Torvalds 			replace_key(tb, tb->CFL[0], tb->lkey[0], S0, 0);
7751da177e4SLinus Torvalds 
7761da177e4SLinus Torvalds 			RFALSE((shift_bytes != -1 &&
7774cf5f7adSJeff Mahoney 				!(is_direntry_le_ih(item_head(S0, 0))
7784cf5f7adSJeff Mahoney 				  && !ih_entry_count(item_head(S0, 0)))) &&
779bd4c625cSLinus Torvalds 			       (!op_is_left_mergeable
7804cf5f7adSJeff Mahoney 				(leaf_key(S0, 0), S0->b_size)),
7811da177e4SLinus Torvalds 			       "vs-10280: item must be mergeable");
7821da177e4SLinus Torvalds 		}
7831da177e4SLinus Torvalds 	}
7841da177e4SLinus Torvalds 
7851da177e4SLinus Torvalds 	return i;
7861da177e4SLinus Torvalds }
7871da177e4SLinus Torvalds 
7881da177e4SLinus Torvalds /* CLEANING STOPPED HERE */
7891da177e4SLinus Torvalds 
790098297b2SJeff Mahoney /*
791098297b2SJeff Mahoney  * Shift shift_num (shift_bytes) items from S[0] to the right neighbor,
792098297b2SJeff Mahoney  * and replace the delimiting key
793098297b2SJeff Mahoney  */
leaf_shift_right(struct tree_balance * tb,int shift_num,int shift_bytes)794bd4c625cSLinus Torvalds int leaf_shift_right(struct tree_balance *tb, int shift_num, int shift_bytes)
7951da177e4SLinus Torvalds {
7961da177e4SLinus Torvalds 	int ret_value;
7971da177e4SLinus Torvalds 
798098297b2SJeff Mahoney 	/*
799098297b2SJeff Mahoney 	 * move shift_num (and shift_bytes) items from S[0] to
800098297b2SJeff Mahoney 	 * right neighbor R[0]
801098297b2SJeff Mahoney 	 */
802bd4c625cSLinus Torvalds 	ret_value =
803bd4c625cSLinus Torvalds 	    leaf_move_items(LEAF_FROM_S_TO_R, tb, shift_num, shift_bytes, NULL);
8041da177e4SLinus Torvalds 
8051da177e4SLinus Torvalds 	/* replace rkey in CFR[0] by the 0-th key from R[0] */
8061da177e4SLinus Torvalds 	if (shift_num) {
8071da177e4SLinus Torvalds 		replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
8081da177e4SLinus Torvalds 
8091da177e4SLinus Torvalds 	}
8101da177e4SLinus Torvalds 
8111da177e4SLinus Torvalds 	return ret_value;
8121da177e4SLinus Torvalds }
8131da177e4SLinus Torvalds 
8141da177e4SLinus Torvalds static void leaf_delete_items_entirely(struct buffer_info *bi,
8151da177e4SLinus Torvalds 				       int first, int del_num);
816098297b2SJeff Mahoney /*
817098297b2SJeff Mahoney  * If del_bytes == -1, starting from position 'first' delete del_num
818098297b2SJeff Mahoney  * items in whole in buffer CUR.
819098297b2SJeff Mahoney  *   If not.
820098297b2SJeff Mahoney  *   If last_first == 0. Starting from position 'first' delete del_num-1
821098297b2SJeff Mahoney  *   items in whole. Delete part of body of the first item. Part defined by
822098297b2SJeff Mahoney  *   del_bytes. Don't delete first item header
823098297b2SJeff Mahoney  *   If last_first == 1. Starting from position 'first+1' delete del_num-1
824098297b2SJeff Mahoney  *   items in whole. Delete part of body of the last item . Part defined by
825098297b2SJeff Mahoney  *   del_bytes. Don't delete last item header.
8261da177e4SLinus Torvalds */
leaf_delete_items(struct buffer_info * cur_bi,int last_first,int first,int del_num,int del_bytes)8271da177e4SLinus Torvalds void leaf_delete_items(struct buffer_info *cur_bi, int last_first,
8281da177e4SLinus Torvalds 		       int first, int del_num, int del_bytes)
8291da177e4SLinus Torvalds {
8301da177e4SLinus Torvalds 	struct buffer_head *bh;
8311da177e4SLinus Torvalds 	int item_amount = B_NR_ITEMS(bh = cur_bi->bi_bh);
8321da177e4SLinus Torvalds 
8331da177e4SLinus Torvalds 	RFALSE(!bh, "10155: bh is not defined");
834bd4c625cSLinus Torvalds 	RFALSE(del_num < 0, "10160: del_num can not be < 0. del_num==%d",
835bd4c625cSLinus Torvalds 	       del_num);
836bd4c625cSLinus Torvalds 	RFALSE(first < 0
837bd4c625cSLinus Torvalds 	       || first + del_num > item_amount,
8381da177e4SLinus Torvalds 	       "10165: invalid number of first item to be deleted (%d) or "
839bd4c625cSLinus Torvalds 	       "no so much items (%d) to delete (only %d)", first,
840bd4c625cSLinus Torvalds 	       first + del_num, item_amount);
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds 	if (del_num == 0)
8431da177e4SLinus Torvalds 		return;
8441da177e4SLinus Torvalds 
8451da177e4SLinus Torvalds 	if (first == 0 && del_num == item_amount && del_bytes == -1) {
8461da177e4SLinus Torvalds 		make_empty_node(cur_bi);
8471da177e4SLinus Torvalds 		do_balance_mark_leaf_dirty(cur_bi->tb, bh, 0);
8481da177e4SLinus Torvalds 		return;
8491da177e4SLinus Torvalds 	}
8501da177e4SLinus Torvalds 
8511da177e4SLinus Torvalds 	if (del_bytes == -1)
8521da177e4SLinus Torvalds 		/* delete del_num items beginning from item in position first */
8531da177e4SLinus Torvalds 		leaf_delete_items_entirely(cur_bi, first, del_num);
8541da177e4SLinus Torvalds 	else {
8551da177e4SLinus Torvalds 		if (last_first == FIRST_TO_LAST) {
856098297b2SJeff Mahoney 			/*
857098297b2SJeff Mahoney 			 * delete del_num-1 items beginning from
858098297b2SJeff Mahoney 			 * item in position first
859098297b2SJeff Mahoney 			 */
8601da177e4SLinus Torvalds 			leaf_delete_items_entirely(cur_bi, first, del_num - 1);
8611da177e4SLinus Torvalds 
862098297b2SJeff Mahoney 			/*
863098297b2SJeff Mahoney 			 * delete the part of the first item of the bh
864098297b2SJeff Mahoney 			 * do not delete item header
8651da177e4SLinus Torvalds 			 */
8661da177e4SLinus Torvalds 			leaf_cut_from_buffer(cur_bi, 0, 0, del_bytes);
8671da177e4SLinus Torvalds 		} else {
8681da177e4SLinus Torvalds 			struct item_head *ih;
8691da177e4SLinus Torvalds 			int len;
8701da177e4SLinus Torvalds 
871098297b2SJeff Mahoney 			/*
872098297b2SJeff Mahoney 			 * delete del_num-1 items beginning from
873098297b2SJeff Mahoney 			 * item in position first+1
874098297b2SJeff Mahoney 			 */
875bd4c625cSLinus Torvalds 			leaf_delete_items_entirely(cur_bi, first + 1,
876bd4c625cSLinus Torvalds 						   del_num - 1);
8771da177e4SLinus Torvalds 
8784cf5f7adSJeff Mahoney 			ih = item_head(bh, B_NR_ITEMS(bh) - 1);
8791d965fe0SJeff Mahoney 			if (is_direntry_le_ih(ih))
880bd4c625cSLinus Torvalds 				/* the last item is directory  */
881098297b2SJeff Mahoney 				/*
882098297b2SJeff Mahoney 				 * len = numbers of directory entries
883098297b2SJeff Mahoney 				 * in this item
884098297b2SJeff Mahoney 				 */
8851da177e4SLinus Torvalds 				len = ih_entry_count(ih);
8861da177e4SLinus Torvalds 			else
8871da177e4SLinus Torvalds 				/* len = body len of item */
8881da177e4SLinus Torvalds 				len = ih_item_len(ih);
8891da177e4SLinus Torvalds 
890098297b2SJeff Mahoney 			/*
891098297b2SJeff Mahoney 			 * delete the part of the last item of the bh
892098297b2SJeff Mahoney 			 * do not delete item header
8931da177e4SLinus Torvalds 			 */
894bd4c625cSLinus Torvalds 			leaf_cut_from_buffer(cur_bi, B_NR_ITEMS(bh) - 1,
895bd4c625cSLinus Torvalds 					     len - del_bytes, del_bytes);
8961da177e4SLinus Torvalds 		}
8971da177e4SLinus Torvalds 	}
8981da177e4SLinus Torvalds }
8991da177e4SLinus Torvalds 
9001da177e4SLinus Torvalds /* insert item into the leaf node in position before */
leaf_insert_into_buf(struct buffer_info * bi,int before,struct item_head * const inserted_item_ih,const char * const inserted_item_body,int zeros_number)9011da177e4SLinus Torvalds void leaf_insert_into_buf(struct buffer_info *bi, int before,
90227d0e5bcSJeff Mahoney 			  struct item_head * const inserted_item_ih,
90327d0e5bcSJeff Mahoney 			  const char * const inserted_item_body,
90427d0e5bcSJeff Mahoney 			  int zeros_number)
9051da177e4SLinus Torvalds {
9061da177e4SLinus Torvalds 	struct buffer_head *bh = bi->bi_bh;
9071da177e4SLinus Torvalds 	int nr, free_space;
9081da177e4SLinus Torvalds 	struct block_head *blkh;
9091da177e4SLinus Torvalds 	struct item_head *ih;
9101da177e4SLinus Torvalds 	int i;
9111da177e4SLinus Torvalds 	int last_loc, unmoved_loc;
9121da177e4SLinus Torvalds 	char *to;
9131da177e4SLinus Torvalds 
9141da177e4SLinus Torvalds 	blkh = B_BLK_HEAD(bh);
9151da177e4SLinus Torvalds 	nr = blkh_nr_item(blkh);
9161da177e4SLinus Torvalds 	free_space = blkh_free_space(blkh);
9171da177e4SLinus Torvalds 
9181da177e4SLinus Torvalds 	/* check free space */
9191da177e4SLinus Torvalds 	RFALSE(free_space < ih_item_len(inserted_item_ih) + IH_SIZE,
9201da177e4SLinus Torvalds 	       "vs-10170: not enough free space in block %z, new item %h",
9211da177e4SLinus Torvalds 	       bh, inserted_item_ih);
9221da177e4SLinus Torvalds 	RFALSE(zeros_number > ih_item_len(inserted_item_ih),
9231da177e4SLinus Torvalds 	       "vs-10172: zero number == %d, item length == %d",
9241da177e4SLinus Torvalds 	       zeros_number, ih_item_len(inserted_item_ih));
9251da177e4SLinus Torvalds 
9261da177e4SLinus Torvalds 	/* get item new item must be inserted before */
9274cf5f7adSJeff Mahoney 	ih = item_head(bh, before);
9281da177e4SLinus Torvalds 
9291da177e4SLinus Torvalds 	/* prepare space for the body of new item */
930a228bf8fSJeff Mahoney 	last_loc = nr ? ih_location(&ih[nr - before - 1]) : bh->b_size;
9311da177e4SLinus Torvalds 	unmoved_loc = before ? ih_location(ih - 1) : bh->b_size;
9321da177e4SLinus Torvalds 
9331da177e4SLinus Torvalds 	memmove(bh->b_data + last_loc - ih_item_len(inserted_item_ih),
9341da177e4SLinus Torvalds 		bh->b_data + last_loc, unmoved_loc - last_loc);
9351da177e4SLinus Torvalds 
9361da177e4SLinus Torvalds 	to = bh->b_data + unmoved_loc - ih_item_len(inserted_item_ih);
9371da177e4SLinus Torvalds 	memset(to, 0, zeros_number);
9381da177e4SLinus Torvalds 	to += zeros_number;
9391da177e4SLinus Torvalds 
9401da177e4SLinus Torvalds 	/* copy body to prepared space */
9411da177e4SLinus Torvalds 	if (inserted_item_body)
942bd4c625cSLinus Torvalds 		memmove(to, inserted_item_body,
943bd4c625cSLinus Torvalds 			ih_item_len(inserted_item_ih) - zeros_number);
9441da177e4SLinus Torvalds 	else
9451da177e4SLinus Torvalds 		memset(to, '\0', ih_item_len(inserted_item_ih) - zeros_number);
9461da177e4SLinus Torvalds 
9471da177e4SLinus Torvalds 	/* insert item header */
9481da177e4SLinus Torvalds 	memmove(ih + 1, ih, IH_SIZE * (nr - before));
9491da177e4SLinus Torvalds 	memmove(ih, inserted_item_ih, IH_SIZE);
9501da177e4SLinus Torvalds 
9511da177e4SLinus Torvalds 	/* change locations */
952bd4c625cSLinus Torvalds 	for (i = before; i < nr + 1; i++) {
953a228bf8fSJeff Mahoney 		unmoved_loc -= ih_item_len(&ih[i - before]);
954a228bf8fSJeff Mahoney 		put_ih_location(&ih[i - before], unmoved_loc);
9551da177e4SLinus Torvalds 	}
9561da177e4SLinus Torvalds 
9571da177e4SLinus Torvalds 	/* sizes, free space, item number */
9581da177e4SLinus Torvalds 	set_blkh_nr_item(blkh, blkh_nr_item(blkh) + 1);
9591da177e4SLinus Torvalds 	set_blkh_free_space(blkh,
960bd4c625cSLinus Torvalds 			    free_space - (IH_SIZE +
961bd4c625cSLinus Torvalds 					  ih_item_len(inserted_item_ih)));
9621da177e4SLinus Torvalds 	do_balance_mark_leaf_dirty(bi->tb, bh, 1);
9631da177e4SLinus Torvalds 
9641da177e4SLinus Torvalds 	if (bi->bi_parent) {
9651da177e4SLinus Torvalds 		struct disk_child *t_dc;
9661da177e4SLinus Torvalds 		t_dc = B_N_CHILD(bi->bi_parent, bi->bi_position);
967bd4c625cSLinus Torvalds 		put_dc_size(t_dc,
968bd4c625cSLinus Torvalds 			    dc_size(t_dc) + (IH_SIZE +
969bd4c625cSLinus Torvalds 					     ih_item_len(inserted_item_ih)));
9701da177e4SLinus Torvalds 		do_balance_mark_internal_dirty(bi->tb, bi->bi_parent, 0);
9711da177e4SLinus Torvalds 	}
9721da177e4SLinus Torvalds }
9731da177e4SLinus Torvalds 
974098297b2SJeff Mahoney /*
975098297b2SJeff Mahoney  * paste paste_size bytes to affected_item_num-th item.
976098297b2SJeff Mahoney  * When item is a directory, this only prepare space for new entries
977098297b2SJeff Mahoney  */
leaf_paste_in_buffer(struct buffer_info * bi,int affected_item_num,int pos_in_item,int paste_size,const char * body,int zeros_number)9781da177e4SLinus Torvalds void leaf_paste_in_buffer(struct buffer_info *bi, int affected_item_num,
9791da177e4SLinus Torvalds 			  int pos_in_item, int paste_size,
980bd4c625cSLinus Torvalds 			  const char *body, int zeros_number)
9811da177e4SLinus Torvalds {
9821da177e4SLinus Torvalds 	struct buffer_head *bh = bi->bi_bh;
9831da177e4SLinus Torvalds 	int nr, free_space;
9841da177e4SLinus Torvalds 	struct block_head *blkh;
9851da177e4SLinus Torvalds 	struct item_head *ih;
9861da177e4SLinus Torvalds 	int i;
9871da177e4SLinus Torvalds 	int last_loc, unmoved_loc;
9881da177e4SLinus Torvalds 
9891da177e4SLinus Torvalds 	blkh = B_BLK_HEAD(bh);
9901da177e4SLinus Torvalds 	nr = blkh_nr_item(blkh);
9911da177e4SLinus Torvalds 	free_space = blkh_free_space(blkh);
9921da177e4SLinus Torvalds 
9931da177e4SLinus Torvalds 	/* check free space */
9941da177e4SLinus Torvalds 	RFALSE(free_space < paste_size,
9951da177e4SLinus Torvalds 	       "vs-10175: not enough free space: needed %d, available %d",
9961da177e4SLinus Torvalds 	       paste_size, free_space);
9971da177e4SLinus Torvalds 
9981da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK
9991da177e4SLinus Torvalds 	if (zeros_number > paste_size) {
1000c3a9c210SJeff Mahoney 		struct super_block *sb = NULL;
1001c3a9c210SJeff Mahoney 		if (bi && bi->tb)
1002c3a9c210SJeff Mahoney 			sb = bi->tb->tb_sb;
10031da177e4SLinus Torvalds 		print_cur_tb("10177");
1004c3a9c210SJeff Mahoney 		reiserfs_panic(sb, "vs-10177",
1005c3a9c210SJeff Mahoney 			       "zeros_number == %d, paste_size == %d",
10061da177e4SLinus Torvalds 			       zeros_number, paste_size);
10071da177e4SLinus Torvalds 	}
10081da177e4SLinus Torvalds #endif				/* CONFIG_REISERFS_CHECK */
10091da177e4SLinus Torvalds 
10101da177e4SLinus Torvalds 	/* item to be appended */
10114cf5f7adSJeff Mahoney 	ih = item_head(bh, affected_item_num);
10121da177e4SLinus Torvalds 
1013a228bf8fSJeff Mahoney 	last_loc = ih_location(&ih[nr - affected_item_num - 1]);
10141da177e4SLinus Torvalds 	unmoved_loc = affected_item_num ? ih_location(ih - 1) : bh->b_size;
10151da177e4SLinus Torvalds 
10161da177e4SLinus Torvalds 	/* prepare space */
10171da177e4SLinus Torvalds 	memmove(bh->b_data + last_loc - paste_size, bh->b_data + last_loc,
10181da177e4SLinus Torvalds 		unmoved_loc - last_loc);
10191da177e4SLinus Torvalds 
10201da177e4SLinus Torvalds 	/* change locations */
10211da177e4SLinus Torvalds 	for (i = affected_item_num; i < nr; i++)
1022a228bf8fSJeff Mahoney 		put_ih_location(&ih[i - affected_item_num],
1023a228bf8fSJeff Mahoney 				ih_location(&ih[i - affected_item_num]) -
1024bd4c625cSLinus Torvalds 				paste_size);
10251da177e4SLinus Torvalds 
10261da177e4SLinus Torvalds 	if (body) {
10271da177e4SLinus Torvalds 		if (!is_direntry_le_ih(ih)) {
10281da177e4SLinus Torvalds 			if (!pos_in_item) {
10291da177e4SLinus Torvalds 				/* shift data to right */
1030bd4c625cSLinus Torvalds 				memmove(bh->b_data + ih_location(ih) +
1031bd4c625cSLinus Torvalds 					paste_size,
1032bd4c625cSLinus Torvalds 					bh->b_data + ih_location(ih),
1033bd4c625cSLinus Torvalds 					ih_item_len(ih));
10341da177e4SLinus Torvalds 				/* paste data in the head of item */
1035bd4c625cSLinus Torvalds 				memset(bh->b_data + ih_location(ih), 0,
1036bd4c625cSLinus Torvalds 				       zeros_number);
1037bd4c625cSLinus Torvalds 				memcpy(bh->b_data + ih_location(ih) +
1038bd4c625cSLinus Torvalds 				       zeros_number, body,
1039bd4c625cSLinus Torvalds 				       paste_size - zeros_number);
10401da177e4SLinus Torvalds 			} else {
1041bd4c625cSLinus Torvalds 				memset(bh->b_data + unmoved_loc - paste_size, 0,
1042bd4c625cSLinus Torvalds 				       zeros_number);
1043bd4c625cSLinus Torvalds 				memcpy(bh->b_data + unmoved_loc - paste_size +
1044bd4c625cSLinus Torvalds 				       zeros_number, body,
1045bd4c625cSLinus Torvalds 				       paste_size - zeros_number);
10461da177e4SLinus Torvalds 			}
10471da177e4SLinus Torvalds 		}
1048bd4c625cSLinus Torvalds 	} else
10491da177e4SLinus Torvalds 		memset(bh->b_data + unmoved_loc - paste_size, '\0', paste_size);
10501da177e4SLinus Torvalds 
10511da177e4SLinus Torvalds 	put_ih_item_len(ih, ih_item_len(ih) + paste_size);
10521da177e4SLinus Torvalds 
10531da177e4SLinus Torvalds 	/* change free space */
10541da177e4SLinus Torvalds 	set_blkh_free_space(blkh, free_space - paste_size);
10551da177e4SLinus Torvalds 
10561da177e4SLinus Torvalds 	do_balance_mark_leaf_dirty(bi->tb, bh, 0);
10571da177e4SLinus Torvalds 
10581da177e4SLinus Torvalds 	if (bi->bi_parent) {
1059bd4c625cSLinus Torvalds 		struct disk_child *t_dc =
1060bd4c625cSLinus Torvalds 		    B_N_CHILD(bi->bi_parent, bi->bi_position);
10611da177e4SLinus Torvalds 		put_dc_size(t_dc, dc_size(t_dc) + paste_size);
10621da177e4SLinus Torvalds 		do_balance_mark_internal_dirty(bi->tb, bi->bi_parent, 0);
10631da177e4SLinus Torvalds 	}
10641da177e4SLinus Torvalds }
10651da177e4SLinus Torvalds 
1066098297b2SJeff Mahoney /*
1067098297b2SJeff Mahoney  * cuts DEL_COUNT entries beginning from FROM-th entry. Directory item
1068098297b2SJeff Mahoney  * does not have free space, so it moves DEHs and remaining records as
1069098297b2SJeff Mahoney  * necessary. Return value is size of removed part of directory item
1070098297b2SJeff Mahoney  * in bytes.
1071098297b2SJeff Mahoney  */
leaf_cut_entries(struct buffer_head * bh,struct item_head * ih,int from,int del_count)1072bd4c625cSLinus Torvalds static int leaf_cut_entries(struct buffer_head *bh,
1073bd4c625cSLinus Torvalds 			    struct item_head *ih, int from, int del_count)
10741da177e4SLinus Torvalds {
10751da177e4SLinus Torvalds 	char *item;
10761da177e4SLinus Torvalds 	struct reiserfs_de_head *deh;
10771da177e4SLinus Torvalds 	int prev_record_offset;	/* offset of record, that is (from-1)th */
10781da177e4SLinus Torvalds 	char *prev_record;	/* */
10791da177e4SLinus Torvalds 	int cut_records_len;	/* length of all removed records */
10801da177e4SLinus Torvalds 	int i;
10811da177e4SLinus Torvalds 
1082098297b2SJeff Mahoney 	/*
1083098297b2SJeff Mahoney 	 * make sure that item is directory and there are enough entries to
1084098297b2SJeff Mahoney 	 * remove
1085098297b2SJeff Mahoney 	 */
10861da177e4SLinus Torvalds 	RFALSE(!is_direntry_le_ih(ih), "10180: item is not directory item");
10874cf5f7adSJeff Mahoney 	RFALSE(ih_entry_count(ih) < from + del_count,
10888112b983SMasanari Iida 	       "10185: item contains not enough entries: entry_count = %d, from = %d, to delete = %d",
10894cf5f7adSJeff Mahoney 	       ih_entry_count(ih), from, del_count);
10901da177e4SLinus Torvalds 
10911da177e4SLinus Torvalds 	if (del_count == 0)
10921da177e4SLinus Torvalds 		return 0;
10931da177e4SLinus Torvalds 
10941da177e4SLinus Torvalds 	/* first byte of item */
10951da177e4SLinus Torvalds 	item = bh->b_data + ih_location(ih);
10961da177e4SLinus Torvalds 
10971da177e4SLinus Torvalds 	/* entry head array */
10981da177e4SLinus Torvalds 	deh = B_I_DEH(bh, ih);
10991da177e4SLinus Torvalds 
1100098297b2SJeff Mahoney 	/*
1101098297b2SJeff Mahoney 	 * first byte of remaining entries, those are BEFORE cut entries
1102098297b2SJeff Mahoney 	 * (prev_record) and length of all removed records (cut_records_len)
1103098297b2SJeff Mahoney 	 */
1104bd4c625cSLinus Torvalds 	prev_record_offset =
1105a228bf8fSJeff Mahoney 	    (from ? deh_location(&deh[from - 1]) : ih_item_len(ih));
11061da177e4SLinus Torvalds 	cut_records_len = prev_record_offset /*from_record */  -
1107a228bf8fSJeff Mahoney 	    deh_location(&deh[from + del_count - 1]);
11081da177e4SLinus Torvalds 	prev_record = item + prev_record_offset;
11091da177e4SLinus Torvalds 
11101da177e4SLinus Torvalds 	/* adjust locations of remaining entries */
11114cf5f7adSJeff Mahoney 	for (i = ih_entry_count(ih) - 1; i > from + del_count - 1; i--)
1112a228bf8fSJeff Mahoney 		put_deh_location(&deh[i],
1113bd4c625cSLinus Torvalds 				 deh_location(&deh[i]) -
1114bd4c625cSLinus Torvalds 				 (DEH_SIZE * del_count));
11151da177e4SLinus Torvalds 
11161da177e4SLinus Torvalds 	for (i = 0; i < from; i++)
1117a228bf8fSJeff Mahoney 		put_deh_location(&deh[i],
1118bd4c625cSLinus Torvalds 				 deh_location(&deh[i]) - (DEH_SIZE * del_count +
1119bd4c625cSLinus Torvalds 							  cut_records_len));
11201da177e4SLinus Torvalds 
11211da177e4SLinus Torvalds 	put_ih_entry_count(ih, ih_entry_count(ih) - del_count);
11221da177e4SLinus Torvalds 
11231da177e4SLinus Torvalds 	/* shift entry head array and entries those are AFTER removed entries */
11241da177e4SLinus Torvalds 	memmove((char *)(deh + from),
11251da177e4SLinus Torvalds 		deh + from + del_count,
1126bd4c625cSLinus Torvalds 		prev_record - cut_records_len - (char *)(deh + from +
1127bd4c625cSLinus Torvalds 							 del_count));
11281da177e4SLinus Torvalds 
11291da177e4SLinus Torvalds 	/* shift records, those are BEFORE removed entries */
11301da177e4SLinus Torvalds 	memmove(prev_record - cut_records_len - DEH_SIZE * del_count,
11311da177e4SLinus Torvalds 		prev_record, item + ih_item_len(ih) - prev_record);
11321da177e4SLinus Torvalds 
11331da177e4SLinus Torvalds 	return DEH_SIZE * del_count + cut_records_len;
11341da177e4SLinus Torvalds }
11351da177e4SLinus Torvalds 
1136098297b2SJeff Mahoney /*
1137098297b2SJeff Mahoney  * when cut item is part of regular file
1138098297b2SJeff Mahoney  *      pos_in_item - first byte that must be cut
1139098297b2SJeff Mahoney  *      cut_size - number of bytes to be cut beginning from pos_in_item
1140098297b2SJeff Mahoney  *
1141098297b2SJeff Mahoney  * when cut item is part of directory
1142098297b2SJeff Mahoney  *      pos_in_item - number of first deleted entry
1143098297b2SJeff Mahoney  *      cut_size - count of deleted entries
11441da177e4SLinus Torvalds  */
leaf_cut_from_buffer(struct buffer_info * bi,int cut_item_num,int pos_in_item,int cut_size)11451da177e4SLinus Torvalds void leaf_cut_from_buffer(struct buffer_info *bi, int cut_item_num,
11461da177e4SLinus Torvalds 			  int pos_in_item, int cut_size)
11471da177e4SLinus Torvalds {
11481da177e4SLinus Torvalds 	int nr;
11491da177e4SLinus Torvalds 	struct buffer_head *bh = bi->bi_bh;
11501da177e4SLinus Torvalds 	struct block_head *blkh;
11511da177e4SLinus Torvalds 	struct item_head *ih;
11521da177e4SLinus Torvalds 	int last_loc, unmoved_loc;
11531da177e4SLinus Torvalds 	int i;
11541da177e4SLinus Torvalds 
11551da177e4SLinus Torvalds 	blkh = B_BLK_HEAD(bh);
11561da177e4SLinus Torvalds 	nr = blkh_nr_item(blkh);
11571da177e4SLinus Torvalds 
11581da177e4SLinus Torvalds 	/* item head of truncated item */
11594cf5f7adSJeff Mahoney 	ih = item_head(bh, cut_item_num);
11601da177e4SLinus Torvalds 
11611da177e4SLinus Torvalds 	if (is_direntry_le_ih(ih)) {
11621da177e4SLinus Torvalds 		/* first cut entry () */
11631da177e4SLinus Torvalds 		cut_size = leaf_cut_entries(bh, ih, pos_in_item, cut_size);
11641da177e4SLinus Torvalds 		if (pos_in_item == 0) {
11651da177e4SLinus Torvalds 			/* change key */
11661da177e4SLinus Torvalds 			RFALSE(cut_item_num,
1167bd4c625cSLinus Torvalds 			       "when 0-th enrty of item is cut, that item must be first in the node, not %d-th",
1168bd4c625cSLinus Torvalds 			       cut_item_num);
11691da177e4SLinus Torvalds 			/* change item key by key of first entry in the item */
11701da177e4SLinus Torvalds 			set_le_ih_k_offset(ih, deh_offset(B_I_DEH(bh, ih)));
11711da177e4SLinus Torvalds 		}
11721da177e4SLinus Torvalds 	} else {
11731da177e4SLinus Torvalds 		/* item is direct or indirect */
11741da177e4SLinus Torvalds 		RFALSE(is_statdata_le_ih(ih), "10195: item is stat data");
11751da177e4SLinus Torvalds 		RFALSE(pos_in_item && pos_in_item + cut_size != ih_item_len(ih),
11761da177e4SLinus Torvalds 		       "10200: invalid offset (%lu) or trunc_size (%lu) or ih_item_len (%lu)",
11771da177e4SLinus Torvalds 		       (long unsigned)pos_in_item, (long unsigned)cut_size,
11781da177e4SLinus Torvalds 		       (long unsigned)ih_item_len(ih));
11791da177e4SLinus Torvalds 
11801da177e4SLinus Torvalds 		/* shift item body to left if cut is from the head of item */
11811da177e4SLinus Torvalds 		if (pos_in_item == 0) {
11821da177e4SLinus Torvalds 			memmove(bh->b_data + ih_location(ih),
11831da177e4SLinus Torvalds 				bh->b_data + ih_location(ih) + cut_size,
11841da177e4SLinus Torvalds 				ih_item_len(ih) - cut_size);
11851da177e4SLinus Torvalds 
11861da177e4SLinus Torvalds 			/* change key of item */
11871da177e4SLinus Torvalds 			if (is_direct_le_ih(ih))
1188bd4c625cSLinus Torvalds 				set_le_ih_k_offset(ih,
1189bd4c625cSLinus Torvalds 						   le_ih_k_offset(ih) +
1190bd4c625cSLinus Torvalds 						   cut_size);
11911da177e4SLinus Torvalds 			else {
1192bd4c625cSLinus Torvalds 				set_le_ih_k_offset(ih,
1193bd4c625cSLinus Torvalds 						   le_ih_k_offset(ih) +
1194bd4c625cSLinus Torvalds 						   (cut_size / UNFM_P_SIZE) *
1195bd4c625cSLinus Torvalds 						   bh->b_size);
1196bd4c625cSLinus Torvalds 				RFALSE(ih_item_len(ih) == cut_size
1197bd4c625cSLinus Torvalds 				       && get_ih_free_space(ih),
11981da177e4SLinus Torvalds 				       "10205: invalid ih_free_space (%h)", ih);
11991da177e4SLinus Torvalds 			}
12001da177e4SLinus Torvalds 		}
12011da177e4SLinus Torvalds 	}
12021da177e4SLinus Torvalds 
12031da177e4SLinus Torvalds 	/* location of the last item */
1204a228bf8fSJeff Mahoney 	last_loc = ih_location(&ih[nr - cut_item_num - 1]);
12051da177e4SLinus Torvalds 
12061da177e4SLinus Torvalds 	/* location of the item, which is remaining at the same place */
12071da177e4SLinus Torvalds 	unmoved_loc = cut_item_num ? ih_location(ih - 1) : bh->b_size;
12081da177e4SLinus Torvalds 
12091da177e4SLinus Torvalds 	/* shift */
12101da177e4SLinus Torvalds 	memmove(bh->b_data + last_loc + cut_size, bh->b_data + last_loc,
12111da177e4SLinus Torvalds 		unmoved_loc - last_loc - cut_size);
12121da177e4SLinus Torvalds 
12131da177e4SLinus Torvalds 	/* change item length */
12141da177e4SLinus Torvalds 	put_ih_item_len(ih, ih_item_len(ih) - cut_size);
12151da177e4SLinus Torvalds 
12161da177e4SLinus Torvalds 	if (is_indirect_le_ih(ih)) {
12171da177e4SLinus Torvalds 		if (pos_in_item)
12181da177e4SLinus Torvalds 			set_ih_free_space(ih, 0);
12191da177e4SLinus Torvalds 	}
12201da177e4SLinus Torvalds 
12211da177e4SLinus Torvalds 	/* change locations */
12221da177e4SLinus Torvalds 	for (i = cut_item_num; i < nr; i++)
1223a228bf8fSJeff Mahoney 		put_ih_location(&ih[i - cut_item_num],
1224bd4c625cSLinus Torvalds 				ih_location(&ih[i - cut_item_num]) + cut_size);
12251da177e4SLinus Torvalds 
12261da177e4SLinus Torvalds 	/* size, free space */
12271da177e4SLinus Torvalds 	set_blkh_free_space(blkh, blkh_free_space(blkh) + cut_size);
12281da177e4SLinus Torvalds 
12291da177e4SLinus Torvalds 	do_balance_mark_leaf_dirty(bi->tb, bh, 0);
12301da177e4SLinus Torvalds 
12311da177e4SLinus Torvalds 	if (bi->bi_parent) {
12321da177e4SLinus Torvalds 		struct disk_child *t_dc;
12331da177e4SLinus Torvalds 		t_dc = B_N_CHILD(bi->bi_parent, bi->bi_position);
12341da177e4SLinus Torvalds 		put_dc_size(t_dc, dc_size(t_dc) - cut_size);
12351da177e4SLinus Torvalds 		do_balance_mark_internal_dirty(bi->tb, bi->bi_parent, 0);
12361da177e4SLinus Torvalds 	}
12371da177e4SLinus Torvalds }
12381da177e4SLinus Torvalds 
12391da177e4SLinus Torvalds /* delete del_num items from buffer starting from the first'th item */
leaf_delete_items_entirely(struct buffer_info * bi,int first,int del_num)12401da177e4SLinus Torvalds static void leaf_delete_items_entirely(struct buffer_info *bi,
12411da177e4SLinus Torvalds 				       int first, int del_num)
12421da177e4SLinus Torvalds {
12431da177e4SLinus Torvalds 	struct buffer_head *bh = bi->bi_bh;
12441da177e4SLinus Torvalds 	int nr;
12451da177e4SLinus Torvalds 	int i, j;
12461da177e4SLinus Torvalds 	int last_loc, last_removed_loc;
12471da177e4SLinus Torvalds 	struct block_head *blkh;
12481da177e4SLinus Torvalds 	struct item_head *ih;
12491da177e4SLinus Torvalds 
12501da177e4SLinus Torvalds 	RFALSE(bh == NULL, "10210: buffer is 0");
12511da177e4SLinus Torvalds 	RFALSE(del_num < 0, "10215: del_num less than 0 (%d)", del_num);
12521da177e4SLinus Torvalds 
12531da177e4SLinus Torvalds 	if (del_num == 0)
12541da177e4SLinus Torvalds 		return;
12551da177e4SLinus Torvalds 
12561da177e4SLinus Torvalds 	blkh = B_BLK_HEAD(bh);
12571da177e4SLinus Torvalds 	nr = blkh_nr_item(blkh);
12581da177e4SLinus Torvalds 
12591da177e4SLinus Torvalds 	RFALSE(first < 0 || first + del_num > nr,
1260bd4c625cSLinus Torvalds 	       "10220: first=%d, number=%d, there is %d items", first, del_num,
1261bd4c625cSLinus Torvalds 	       nr);
12621da177e4SLinus Torvalds 
12631da177e4SLinus Torvalds 	if (first == 0 && del_num == nr) {
12641da177e4SLinus Torvalds 		/* this does not work */
12651da177e4SLinus Torvalds 		make_empty_node(bi);
12661da177e4SLinus Torvalds 
12671da177e4SLinus Torvalds 		do_balance_mark_leaf_dirty(bi->tb, bh, 0);
12681da177e4SLinus Torvalds 		return;
12691da177e4SLinus Torvalds 	}
12701da177e4SLinus Torvalds 
12714cf5f7adSJeff Mahoney 	ih = item_head(bh, first);
12721da177e4SLinus Torvalds 
12731da177e4SLinus Torvalds 	/* location of unmovable item */
12741da177e4SLinus Torvalds 	j = (first == 0) ? bh->b_size : ih_location(ih - 1);
12751da177e4SLinus Torvalds 
12761da177e4SLinus Torvalds 	/* delete items */
1277a228bf8fSJeff Mahoney 	last_loc = ih_location(&ih[nr - 1 - first]);
1278a228bf8fSJeff Mahoney 	last_removed_loc = ih_location(&ih[del_num - 1]);
12791da177e4SLinus Torvalds 
12801da177e4SLinus Torvalds 	memmove(bh->b_data + last_loc + j - last_removed_loc,
12811da177e4SLinus Torvalds 		bh->b_data + last_loc, last_removed_loc - last_loc);
12821da177e4SLinus Torvalds 
12831da177e4SLinus Torvalds 	/* delete item headers */
12841da177e4SLinus Torvalds 	memmove(ih, ih + del_num, (nr - first - del_num) * IH_SIZE);
12851da177e4SLinus Torvalds 
12861da177e4SLinus Torvalds 	/* change item location */
12871da177e4SLinus Torvalds 	for (i = first; i < nr - del_num; i++)
1288a228bf8fSJeff Mahoney 		put_ih_location(&ih[i - first],
1289a228bf8fSJeff Mahoney 				ih_location(&ih[i - first]) + (j -
1290bd4c625cSLinus Torvalds 								 last_removed_loc));
12911da177e4SLinus Torvalds 
12921da177e4SLinus Torvalds 	/* sizes, item number */
12931da177e4SLinus Torvalds 	set_blkh_nr_item(blkh, blkh_nr_item(blkh) - del_num);
1294bd4c625cSLinus Torvalds 	set_blkh_free_space(blkh,
1295bd4c625cSLinus Torvalds 			    blkh_free_space(blkh) + (j - last_removed_loc +
1296bd4c625cSLinus Torvalds 						     IH_SIZE * del_num));
12971da177e4SLinus Torvalds 
12981da177e4SLinus Torvalds 	do_balance_mark_leaf_dirty(bi->tb, bh, 0);
12991da177e4SLinus Torvalds 
13001da177e4SLinus Torvalds 	if (bi->bi_parent) {
1301bd4c625cSLinus Torvalds 		struct disk_child *t_dc =
1302bd4c625cSLinus Torvalds 		    B_N_CHILD(bi->bi_parent, bi->bi_position);
1303bd4c625cSLinus Torvalds 		put_dc_size(t_dc,
1304bd4c625cSLinus Torvalds 			    dc_size(t_dc) - (j - last_removed_loc +
1305bd4c625cSLinus Torvalds 					     IH_SIZE * del_num));
13061da177e4SLinus Torvalds 		do_balance_mark_internal_dirty(bi->tb, bi->bi_parent, 0);
13071da177e4SLinus Torvalds 	}
13081da177e4SLinus Torvalds }
13091da177e4SLinus Torvalds 
1310098297b2SJeff Mahoney /*
1311098297b2SJeff Mahoney  * paste new_entry_count entries (new_dehs, records) into position
1312098297b2SJeff Mahoney  * before to item_num-th item
1313098297b2SJeff Mahoney  */
leaf_paste_entries(struct buffer_info * bi,int item_num,int before,int new_entry_count,struct reiserfs_de_head * new_dehs,const char * records,int paste_size)1314eba00305SJeff Mahoney void leaf_paste_entries(struct buffer_info *bi,
13151da177e4SLinus Torvalds 			int item_num,
13161da177e4SLinus Torvalds 			int before,
13171da177e4SLinus Torvalds 			int new_entry_count,
13181da177e4SLinus Torvalds 			struct reiserfs_de_head *new_dehs,
1319bd4c625cSLinus Torvalds 			const char *records, int paste_size)
13201da177e4SLinus Torvalds {
13211da177e4SLinus Torvalds 	struct item_head *ih;
13221da177e4SLinus Torvalds 	char *item;
13231da177e4SLinus Torvalds 	struct reiserfs_de_head *deh;
13241da177e4SLinus Torvalds 	char *insert_point;
1325*d4a1a857Szhengbin 	int i;
1326eba00305SJeff Mahoney 	struct buffer_head *bh = bi->bi_bh;
13271da177e4SLinus Torvalds 
13281da177e4SLinus Torvalds 	if (new_entry_count == 0)
13291da177e4SLinus Torvalds 		return;
13301da177e4SLinus Torvalds 
13314cf5f7adSJeff Mahoney 	ih = item_head(bh, item_num);
13321da177e4SLinus Torvalds 
1333098297b2SJeff Mahoney 	/*
1334098297b2SJeff Mahoney 	 * make sure, that item is directory, and there are enough
1335098297b2SJeff Mahoney 	 * records in it
1336098297b2SJeff Mahoney 	 */
13371da177e4SLinus Torvalds 	RFALSE(!is_direntry_le_ih(ih), "10225: item is not directory item");
13384cf5f7adSJeff Mahoney 	RFALSE(ih_entry_count(ih) < before,
13391da177e4SLinus Torvalds 	       "10230: there are no entry we paste entries before. entry_count = %d, before = %d",
13404cf5f7adSJeff Mahoney 	       ih_entry_count(ih), before);
13411da177e4SLinus Torvalds 
13421da177e4SLinus Torvalds 	/* first byte of dest item */
13431da177e4SLinus Torvalds 	item = bh->b_data + ih_location(ih);
13441da177e4SLinus Torvalds 
13451da177e4SLinus Torvalds 	/* entry head array */
13461da177e4SLinus Torvalds 	deh = B_I_DEH(bh, ih);
13471da177e4SLinus Torvalds 
13481da177e4SLinus Torvalds 	/* new records will be pasted at this point */
1349bd4c625cSLinus Torvalds 	insert_point =
1350bd4c625cSLinus Torvalds 	    item +
1351a228bf8fSJeff Mahoney 	    (before ? deh_location(&deh[before - 1])
1352bd4c625cSLinus Torvalds 	     : (ih_item_len(ih) - paste_size));
13531da177e4SLinus Torvalds 
13541da177e4SLinus Torvalds 	/* adjust locations of records that will be AFTER new records */
13554cf5f7adSJeff Mahoney 	for (i = ih_entry_count(ih) - 1; i >= before; i--)
1356a228bf8fSJeff Mahoney 		put_deh_location(&deh[i],
1357a228bf8fSJeff Mahoney 				 deh_location(&deh[i]) +
1358bd4c625cSLinus Torvalds 				 (DEH_SIZE * new_entry_count));
13591da177e4SLinus Torvalds 
13601da177e4SLinus Torvalds 	/* adjust locations of records that will be BEFORE new records */
13611da177e4SLinus Torvalds 	for (i = 0; i < before; i++)
1362a228bf8fSJeff Mahoney 		put_deh_location(&deh[i],
1363a228bf8fSJeff Mahoney 				 deh_location(&deh[i]) + paste_size);
13641da177e4SLinus Torvalds 
13651da177e4SLinus Torvalds 	put_ih_entry_count(ih, ih_entry_count(ih) + new_entry_count);
13661da177e4SLinus Torvalds 
13671da177e4SLinus Torvalds 	/* prepare space for pasted records */
1368bd4c625cSLinus Torvalds 	memmove(insert_point + paste_size, insert_point,
1369bd4c625cSLinus Torvalds 		item + (ih_item_len(ih) - paste_size) - insert_point);
13701da177e4SLinus Torvalds 
13711da177e4SLinus Torvalds 	/* copy new records */
13721da177e4SLinus Torvalds 	memcpy(insert_point + DEH_SIZE * new_entry_count, records,
13731da177e4SLinus Torvalds 	       paste_size - DEH_SIZE * new_entry_count);
13741da177e4SLinus Torvalds 
13751da177e4SLinus Torvalds 	/* prepare space for new entry heads */
13761da177e4SLinus Torvalds 	deh += before;
1377bd4c625cSLinus Torvalds 	memmove((char *)(deh + new_entry_count), deh,
1378bd4c625cSLinus Torvalds 		insert_point - (char *)deh);
13791da177e4SLinus Torvalds 
13801da177e4SLinus Torvalds 	/* copy new entry heads */
13811da177e4SLinus Torvalds 	deh = (struct reiserfs_de_head *)((char *)deh);
13821da177e4SLinus Torvalds 	memcpy(deh, new_dehs, DEH_SIZE * new_entry_count);
13831da177e4SLinus Torvalds 
13841da177e4SLinus Torvalds 	/* set locations of new records */
1385bd4c625cSLinus Torvalds 	for (i = 0; i < new_entry_count; i++) {
1386a228bf8fSJeff Mahoney 		put_deh_location(&deh[i],
1387a228bf8fSJeff Mahoney 				 deh_location(&deh[i]) +
1388bd4c625cSLinus Torvalds 				 (-deh_location
1389a228bf8fSJeff Mahoney 				  (&new_dehs[new_entry_count - 1]) +
1390bd4c625cSLinus Torvalds 				  insert_point + DEH_SIZE * new_entry_count -
1391bd4c625cSLinus Torvalds 				  item));
13921da177e4SLinus Torvalds 	}
13931da177e4SLinus Torvalds 
13941da177e4SLinus Torvalds 	/* change item key if necessary (when we paste before 0-th entry */
1395bd4c625cSLinus Torvalds 	if (!before) {
13961da177e4SLinus Torvalds 		set_le_ih_k_offset(ih, deh_offset(new_dehs));
13971da177e4SLinus Torvalds 	}
13981da177e4SLinus Torvalds #ifdef CONFIG_REISERFS_CHECK
13991da177e4SLinus Torvalds 	{
14001da177e4SLinus Torvalds 		int prev, next;
14011da177e4SLinus Torvalds 		/* check record locations */
14021da177e4SLinus Torvalds 		deh = B_I_DEH(bh, ih);
14034cf5f7adSJeff Mahoney 		for (i = 0; i < ih_entry_count(ih); i++) {
1404bd4c625cSLinus Torvalds 			next =
1405bd4c625cSLinus Torvalds 			    (i <
14064cf5f7adSJeff Mahoney 			     ih_entry_count(ih) -
1407a228bf8fSJeff Mahoney 			     1) ? deh_location(&deh[i + 1]) : 0;
1408a228bf8fSJeff Mahoney 			prev = (i != 0) ? deh_location(&deh[i - 1]) : 0;
14091da177e4SLinus Torvalds 
1410a228bf8fSJeff Mahoney 			if (prev && prev <= deh_location(&deh[i]))
14110030b645SJeff Mahoney 				reiserfs_error(sb_from_bi(bi), "vs-10240",
141245b03d5eSJeff Mahoney 					       "directory item (%h) "
141345b03d5eSJeff Mahoney 					       "corrupted (prev %a, "
141445b03d5eSJeff Mahoney 					       "cur(%d) %a)",
14151da177e4SLinus Torvalds 					       ih, deh + i - 1, i, deh + i);
1416a228bf8fSJeff Mahoney 			if (next && next >= deh_location(&deh[i]))
14170030b645SJeff Mahoney 				reiserfs_error(sb_from_bi(bi), "vs-10250",
141845b03d5eSJeff Mahoney 					       "directory item (%h) "
141945b03d5eSJeff Mahoney 					       "corrupted (cur(%d) %a, "
142045b03d5eSJeff Mahoney 					       "next %a)",
14211da177e4SLinus Torvalds 					       ih, i, deh + i, deh + i + 1);
14221da177e4SLinus Torvalds 		}
14231da177e4SLinus Torvalds 	}
14241da177e4SLinus Torvalds #endif
14251da177e4SLinus Torvalds 
14261da177e4SLinus Torvalds }
1427