blob: 381750a155f62d544ac6286896e314b43b5404ac [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
3 */
4
Linus Torvalds1da177e2005-04-16 15:20:36 -07005#include <asm/uaccess.h>
6#include <linux/string.h>
7#include <linux/time.h>
8#include <linux/reiserfs_fs.h>
9#include <linux/buffer_head.h>
10
11/* these are used in do_balance.c */
12
13/* leaf_move_items
14 leaf_shift_left
15 leaf_shift_right
16 leaf_delete_items
17 leaf_insert_into_buf
18 leaf_paste_in_buffer
19 leaf_cut_from_buffer
20 leaf_paste_entries
21 */
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023/* copy copy_count entries from source directory item to dest buffer (creating new item if needed) */
Linus Torvaldsbd4c6252005-07-12 20:21:28 -070024static void leaf_copy_dir_entries(struct buffer_info *dest_bi,
25 struct buffer_head *source, int last_first,
26 int item_num, int from, int copy_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -070027{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -070028 struct buffer_head *dest = dest_bi->bi_bh;
29 int item_num_in_dest; /* either the number of target item,
30 or if we must create a new item,
31 the number of the item we will
32 create it next to */
33 struct item_head *ih;
34 struct reiserfs_de_head *deh;
35 int copy_records_len; /* length of all records in item to be copied */
36 char *records;
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
Linus Torvaldsbd4c6252005-07-12 20:21:28 -070038 ih = B_N_PITEM_HEAD(source, item_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Linus Torvaldsbd4c6252005-07-12 20:21:28 -070040 RFALSE(!is_direntry_le_ih(ih), "vs-10000: item must be directory item");
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Linus Torvaldsbd4c6252005-07-12 20:21:28 -070042 /* length of all record to be copied and first byte of the last of them */
43 deh = B_I_DEH(source, ih);
44 if (copy_count) {
45 copy_records_len = (from ? deh_location(&(deh[from - 1])) :
46 ih_item_len(ih)) -
47 deh_location(&(deh[from + copy_count - 1]));
48 records =
49 source->b_data + ih_location(ih) +
50 deh_location(&(deh[from + copy_count - 1]));
51 } else {
52 copy_records_len = 0;
53 records = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Linus Torvaldsbd4c6252005-07-12 20:21:28 -070056 /* when copy last to first, dest buffer can contain 0 items */
57 item_num_in_dest =
58 (last_first ==
59 LAST_TO_FIRST) ? ((B_NR_ITEMS(dest)) ? 0 : -1) : (B_NR_ITEMS(dest)
60 - 1);
61
62 /* if there are no items in dest or the first/last item in dest is not item of the same directory */
63 if ((item_num_in_dest == -1) ||
64 (last_first == FIRST_TO_LAST && le_ih_k_offset(ih) == DOT_OFFSET) ||
65 (last_first == LAST_TO_FIRST
66 && comp_short_le_keys /*COMP_SHORT_KEYS */ (&ih->ih_key,
67 B_N_PKEY(dest,
68 item_num_in_dest))))
69 {
70 /* create new item in dest */
71 struct item_head new_ih;
72
73 /* form item header */
74 memcpy(&new_ih.ih_key, &ih->ih_key, KEY_SIZE);
75 put_ih_version(&new_ih, KEY_FORMAT_3_5);
76 /* calculate item len */
77 put_ih_item_len(&new_ih,
78 DEH_SIZE * copy_count + copy_records_len);
79 put_ih_entry_count(&new_ih, 0);
80
81 if (last_first == LAST_TO_FIRST) {
82 /* form key by the following way */
83 if (from < I_ENTRY_COUNT(ih)) {
84 set_le_ih_k_offset(&new_ih,
85 deh_offset(&(deh[from])));
86 /*memcpy (&new_ih.ih_key.k_offset, &deh[from].deh_offset, SHORT_KEY_SIZE); */
87 } else {
88 /* no entries will be copied to this item in this function */
89 set_le_ih_k_offset(&new_ih, U32_MAX);
90 /* this item is not yet valid, but we want I_IS_DIRECTORY_ITEM to return 1 for it, so we -1 */
91 }
92 set_le_key_k_type(KEY_FORMAT_3_5, &(new_ih.ih_key),
93 TYPE_DIRENTRY);
94 }
95
96 /* insert item into dest buffer */
97 leaf_insert_into_buf(dest_bi,
98 (last_first ==
99 LAST_TO_FIRST) ? 0 : B_NR_ITEMS(dest),
100 &new_ih, NULL, 0);
101 } else {
102 /* prepare space for entries */
103 leaf_paste_in_buffer(dest_bi,
104 (last_first ==
105 FIRST_TO_LAST) ? (B_NR_ITEMS(dest) -
106 1) : 0, MAX_US_INT,
107 DEH_SIZE * copy_count + copy_records_len,
108 records, 0);
109 }
110
111 item_num_in_dest =
112 (last_first == FIRST_TO_LAST) ? (B_NR_ITEMS(dest) - 1) : 0;
113
Jeff Mahoneyeba00302009-03-30 14:02:18 -0400114 leaf_paste_entries(dest_bi, item_num_in_dest,
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700115 (last_first ==
116 FIRST_TO_LAST) ? I_ENTRY_COUNT(B_N_PITEM_HEAD(dest,
117 item_num_in_dest))
118 : 0, copy_count, deh + from, records,
119 DEH_SIZE * copy_count + copy_records_len);
120}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
Jeff Mahoney0222e652009-03-30 14:02:44 -0400122/* Copy the first (if last_first == FIRST_TO_LAST) or last (last_first == LAST_TO_FIRST) item or
123 part of it or nothing (see the return 0 below) from SOURCE to the end
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 (if last_first) or beginning (!last_first) of the DEST */
125/* returns 1 if anything was copied, else 0 */
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700126static int leaf_copy_boundary_item(struct buffer_info *dest_bi,
127 struct buffer_head *src, int last_first,
128 int bytes_or_entries)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700130 struct buffer_head *dest = dest_bi->bi_bh;
131 int dest_nr_item, src_nr_item; /* number of items in the source and destination buffers */
132 struct item_head *ih;
133 struct item_head *dih;
134
135 dest_nr_item = B_NR_ITEMS(dest);
136
137 if (last_first == FIRST_TO_LAST) {
138 /* if ( DEST is empty or first item of SOURCE and last item of DEST are the items of different objects
139 or of different types ) then there is no need to treat this item differently from the other items
140 that we copy, so we return */
141 ih = B_N_PITEM_HEAD(src, 0);
142 dih = B_N_PITEM_HEAD(dest, dest_nr_item - 1);
143 if (!dest_nr_item
144 || (!op_is_left_mergeable(&(ih->ih_key), src->b_size)))
145 /* there is nothing to merge */
146 return 0;
147
148 RFALSE(!ih_item_len(ih),
149 "vs-10010: item can not have empty length");
150
151 if (is_direntry_le_ih(ih)) {
152 if (bytes_or_entries == -1)
153 /* copy all entries to dest */
154 bytes_or_entries = ih_entry_count(ih);
155 leaf_copy_dir_entries(dest_bi, src, FIRST_TO_LAST, 0, 0,
156 bytes_or_entries);
157 return 1;
158 }
159
160 /* copy part of the body of the first item of SOURCE to the end of the body of the last item of the DEST
161 part defined by 'bytes_or_entries'; if bytes_or_entries == -1 copy whole body; don't create new item header
162 */
163 if (bytes_or_entries == -1)
164 bytes_or_entries = ih_item_len(ih);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166#ifdef CONFIG_REISERFS_CHECK
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700167 else {
168 if (bytes_or_entries == ih_item_len(ih)
169 && is_indirect_le_ih(ih))
170 if (get_ih_free_space(ih))
Jeff Mahoneyc3a9c212009-03-30 14:02:25 -0400171 reiserfs_panic(sb_from_bi(dest_bi),
172 "vs-10020",
173 "last unformatted node "
174 "must be filled "
175 "entirely (%h)", ih);
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700179 /* merge first item (or its part) of src buffer with the last
180 item of dest buffer. Both are of the same file */
181 leaf_paste_in_buffer(dest_bi,
182 dest_nr_item - 1, ih_item_len(dih),
183 bytes_or_entries, B_I_PITEM(src, ih), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700185 if (is_indirect_le_ih(dih)) {
186 RFALSE(get_ih_free_space(dih),
187 "vs-10030: merge to left: last unformatted node of non-last indirect item %h must have zerto free space",
188 ih);
189 if (bytes_or_entries == ih_item_len(ih))
190 set_ih_free_space(dih, get_ih_free_space(ih));
191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700193 return 1;
194 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700196 /* copy boundary item to right (last_first == LAST_TO_FIRST) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700198 /* ( DEST is empty or last item of SOURCE and first item of DEST
199 are the items of different object or of different types )
200 */
201 src_nr_item = B_NR_ITEMS(src);
202 ih = B_N_PITEM_HEAD(src, src_nr_item - 1);
203 dih = B_N_PITEM_HEAD(dest, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700205 if (!dest_nr_item || !op_is_left_mergeable(&(dih->ih_key), src->b_size))
206 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700208 if (is_direntry_le_ih(ih)) {
209 if (bytes_or_entries == -1)
210 /* bytes_or_entries = entries number in last item body of SOURCE */
211 bytes_or_entries = ih_entry_count(ih);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700213 leaf_copy_dir_entries(dest_bi, src, LAST_TO_FIRST,
214 src_nr_item - 1,
215 ih_entry_count(ih) - bytes_or_entries,
216 bytes_or_entries);
217 return 1;
218 }
219
220 /* copy part of the body of the last item of SOURCE to the begin of the body of the first item of the DEST;
221 part defined by 'bytes_or_entries'; if byte_or_entriess == -1 copy whole body; change first item key of the DEST;
222 don't create new item header
223 */
224
225 RFALSE(is_indirect_le_ih(ih) && get_ih_free_space(ih),
226 "vs-10040: merge to right: last unformatted node of non-last indirect item must be filled entirely (%h)",
227 ih);
228
229 if (bytes_or_entries == -1) {
230 /* bytes_or_entries = length of last item body of SOURCE */
231 bytes_or_entries = ih_item_len(ih);
232
233 RFALSE(le_ih_k_offset(dih) !=
234 le_ih_k_offset(ih) + op_bytes_number(ih, src->b_size),
235 "vs-10050: items %h and %h do not match", ih, dih);
236
237 /* change first item key of the DEST */
238 set_le_ih_k_offset(dih, le_ih_k_offset(ih));
239
240 /* item becomes non-mergeable */
241 /* or mergeable if left item was */
242 set_le_ih_k_type(dih, le_ih_k_type(ih));
243 } else {
244 /* merge to right only part of item */
245 RFALSE(ih_item_len(ih) <= bytes_or_entries,
246 "vs-10060: no so much bytes %lu (needed %lu)",
247 (unsigned long)ih_item_len(ih),
248 (unsigned long)bytes_or_entries);
249
250 /* change first item key of the DEST */
251 if (is_direct_le_ih(dih)) {
252 RFALSE(le_ih_k_offset(dih) <=
253 (unsigned long)bytes_or_entries,
254 "vs-10070: dih %h, bytes_or_entries(%d)", dih,
255 bytes_or_entries);
256 set_le_ih_k_offset(dih,
257 le_ih_k_offset(dih) -
258 bytes_or_entries);
259 } else {
260 RFALSE(le_ih_k_offset(dih) <=
261 (bytes_or_entries / UNFM_P_SIZE) * dest->b_size,
262 "vs-10080: dih %h, bytes_or_entries(%d)",
263 dih,
264 (bytes_or_entries / UNFM_P_SIZE) * dest->b_size);
265 set_le_ih_k_offset(dih,
266 le_ih_k_offset(dih) -
267 ((bytes_or_entries / UNFM_P_SIZE) *
268 dest->b_size));
269 }
270 }
271
272 leaf_paste_in_buffer(dest_bi, 0, 0, bytes_or_entries,
273 B_I_PITEM(src,
274 ih) + ih_item_len(ih) - bytes_or_entries,
275 0);
276 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277}
278
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279/* copy cpy_mun items from buffer src to buffer dest
280 * last_first == FIRST_TO_LAST means, that we copy cpy_num items beginning from first-th item in src to tail of dest
281 * last_first == LAST_TO_FIRST means, that we copy cpy_num items beginning from first-th item in src to head of dest
282 */
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700283static void leaf_copy_items_entirely(struct buffer_info *dest_bi,
284 struct buffer_head *src, int last_first,
285 int first, int cpy_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700287 struct buffer_head *dest;
288 int nr, free_space;
289 int dest_before;
290 int last_loc, last_inserted_loc, location;
291 int i, j;
292 struct block_head *blkh;
293 struct item_head *ih;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700295 RFALSE(last_first != LAST_TO_FIRST && last_first != FIRST_TO_LAST,
296 "vs-10090: bad last_first parameter %d", last_first);
297 RFALSE(B_NR_ITEMS(src) - first < cpy_num,
298 "vs-10100: too few items in source %d, required %d from %d",
299 B_NR_ITEMS(src), cpy_num, first);
300 RFALSE(cpy_num < 0, "vs-10110: can not copy negative amount of items");
301 RFALSE(!dest_bi, "vs-10120: can not copy negative amount of items");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700303 dest = dest_bi->bi_bh;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700305 RFALSE(!dest, "vs-10130: can not copy negative amount of items");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700307 if (cpy_num == 0)
308 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700310 blkh = B_BLK_HEAD(dest);
311 nr = blkh_nr_item(blkh);
312 free_space = blkh_free_space(blkh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700314 /* we will insert items before 0-th or nr-th item in dest buffer. It depends of last_first parameter */
315 dest_before = (last_first == LAST_TO_FIRST) ? 0 : nr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700317 /* location of head of first new item */
318 ih = B_N_PITEM_HEAD(dest, dest_before);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700320 RFALSE(blkh_free_space(blkh) < cpy_num * IH_SIZE,
321 "vs-10140: not enough free space for headers %d (needed %d)",
322 B_FREE_SPACE(dest), cpy_num * IH_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700324 /* prepare space for headers */
325 memmove(ih + cpy_num, ih, (nr - dest_before) * IH_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700327 /* copy item headers */
328 memcpy(ih, B_N_PITEM_HEAD(src, first), cpy_num * IH_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700330 free_space -= (IH_SIZE * cpy_num);
331 set_blkh_free_space(blkh, free_space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700333 /* location of unmovable item */
334 j = location = (dest_before == 0) ? dest->b_size : ih_location(ih - 1);
335 for (i = dest_before; i < nr + cpy_num; i++) {
336 location -= ih_item_len(ih + i - dest_before);
337 put_ih_location(ih + i - dest_before, location);
338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700340 /* prepare space for items */
341 last_loc = ih_location(&(ih[nr + cpy_num - 1 - dest_before]));
342 last_inserted_loc = ih_location(&(ih[cpy_num - 1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700344 /* check free space */
345 RFALSE(free_space < j - last_inserted_loc,
346 "vs-10150: not enough free space for items %d (needed %d)",
347 free_space, j - last_inserted_loc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700349 memmove(dest->b_data + last_loc,
350 dest->b_data + last_loc + j - last_inserted_loc,
351 last_inserted_loc - last_loc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700353 /* copy items */
354 memcpy(dest->b_data + last_inserted_loc,
355 B_N_PITEM(src, (first + cpy_num - 1)), j - last_inserted_loc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700357 /* sizes, item number */
358 set_blkh_nr_item(blkh, nr + cpy_num);
359 set_blkh_free_space(blkh, free_space - (j - last_inserted_loc));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700361 do_balance_mark_leaf_dirty(dest_bi->tb, dest, 0);
362
363 if (dest_bi->bi_parent) {
364 struct disk_child *t_dc;
365 t_dc = B_N_CHILD(dest_bi->bi_parent, dest_bi->bi_position);
366 RFALSE(dc_block_number(t_dc) != dest->b_blocknr,
367 "vs-10160: block number in bh does not match to field in disk_child structure %lu and %lu",
368 (long unsigned)dest->b_blocknr,
369 (long unsigned)dc_block_number(t_dc));
370 put_dc_size(t_dc,
371 dc_size(t_dc) + (j - last_inserted_loc +
372 IH_SIZE * cpy_num));
373
374 do_balance_mark_internal_dirty(dest_bi->tb, dest_bi->bi_parent,
375 0);
376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377}
378
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379/* This function splits the (liquid) item into two items (useful when
380 shifting part of an item into another node.) */
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700381static void leaf_item_bottle(struct buffer_info *dest_bi,
382 struct buffer_head *src, int last_first,
383 int item_num, int cpy_bytes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700385 struct buffer_head *dest = dest_bi->bi_bh;
386 struct item_head *ih;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700388 RFALSE(cpy_bytes == -1,
389 "vs-10170: bytes == - 1 means: do not split item");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700391 if (last_first == FIRST_TO_LAST) {
392 /* if ( if item in position item_num in buffer SOURCE is directory item ) */
393 if (is_direntry_le_ih(ih = B_N_PITEM_HEAD(src, item_num)))
394 leaf_copy_dir_entries(dest_bi, src, FIRST_TO_LAST,
395 item_num, 0, cpy_bytes);
396 else {
397 struct item_head n_ih;
398
Jeff Mahoney0222e652009-03-30 14:02:44 -0400399 /* copy part of the body of the item number 'item_num' of SOURCE to the end of the DEST
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700400 part defined by 'cpy_bytes'; create new item header; change old item_header (????);
401 n_ih = new item_header;
402 */
403 memcpy(&n_ih, ih, IH_SIZE);
404 put_ih_item_len(&n_ih, cpy_bytes);
405 if (is_indirect_le_ih(ih)) {
406 RFALSE(cpy_bytes == ih_item_len(ih)
407 && get_ih_free_space(ih),
408 "vs-10180: when whole indirect item is bottle to left neighbor, it must have free_space==0 (not %lu)",
409 (long unsigned)get_ih_free_space(ih));
410 set_ih_free_space(&n_ih, 0);
411 }
412
413 RFALSE(op_is_left_mergeable(&(ih->ih_key), src->b_size),
414 "vs-10190: bad mergeability of item %h", ih);
415 n_ih.ih_version = ih->ih_version; /* JDM Endian safe, both le */
416 leaf_insert_into_buf(dest_bi, B_NR_ITEMS(dest), &n_ih,
417 B_N_PITEM(src, item_num), 0);
418 }
419 } else {
420 /* if ( if item in position item_num in buffer SOURCE is directory item ) */
421 if (is_direntry_le_ih(ih = B_N_PITEM_HEAD(src, item_num)))
422 leaf_copy_dir_entries(dest_bi, src, LAST_TO_FIRST,
423 item_num,
424 I_ENTRY_COUNT(ih) - cpy_bytes,
425 cpy_bytes);
426 else {
427 struct item_head n_ih;
428
Jeff Mahoney0222e652009-03-30 14:02:44 -0400429 /* copy part of the body of the item number 'item_num' of SOURCE to the begin of the DEST
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700430 part defined by 'cpy_bytes'; create new item header;
431 n_ih = new item_header;
432 */
433 memcpy(&n_ih, ih, SHORT_KEY_SIZE);
434
435 n_ih.ih_version = ih->ih_version; /* JDM Endian safe, both le */
436
437 if (is_direct_le_ih(ih)) {
438 set_le_ih_k_offset(&n_ih,
439 le_ih_k_offset(ih) +
440 ih_item_len(ih) - cpy_bytes);
441 set_le_ih_k_type(&n_ih, TYPE_DIRECT);
442 set_ih_free_space(&n_ih, MAX_US_INT);
443 } else {
444 /* indirect item */
445 RFALSE(!cpy_bytes && get_ih_free_space(ih),
446 "vs-10200: ih->ih_free_space must be 0 when indirect item will be appended");
447 set_le_ih_k_offset(&n_ih,
448 le_ih_k_offset(ih) +
449 (ih_item_len(ih) -
450 cpy_bytes) / UNFM_P_SIZE *
451 dest->b_size);
452 set_le_ih_k_type(&n_ih, TYPE_INDIRECT);
453 set_ih_free_space(&n_ih, get_ih_free_space(ih));
454 }
455
456 /* set item length */
457 put_ih_item_len(&n_ih, cpy_bytes);
458
459 n_ih.ih_version = ih->ih_version; /* JDM Endian safe, both le */
460
461 leaf_insert_into_buf(dest_bi, 0, &n_ih,
462 B_N_PITEM(src,
463 item_num) +
464 ih_item_len(ih) - cpy_bytes, 0);
465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467}
468
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469/* If cpy_bytes equals minus one than copy cpy_num whole items from SOURCE to DEST.
470 If cpy_bytes not equal to minus one than copy cpy_num-1 whole items from SOURCE to DEST.
471 From last item copy cpy_num bytes for regular item and cpy_num directory entries for
472 directory item. */
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700473static int leaf_copy_items(struct buffer_info *dest_bi, struct buffer_head *src,
474 int last_first, int cpy_num, int cpy_bytes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700476 struct buffer_head *dest;
477 int pos, i, src_nr_item, bytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700479 dest = dest_bi->bi_bh;
480 RFALSE(!dest || !src, "vs-10210: !dest || !src");
481 RFALSE(last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST,
482 "vs-10220:last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST");
483 RFALSE(B_NR_ITEMS(src) < cpy_num,
484 "vs-10230: No enough items: %d, req. %d", B_NR_ITEMS(src),
485 cpy_num);
486 RFALSE(cpy_num < 0, "vs-10240: cpy_num < 0 (%d)", cpy_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700488 if (cpy_num == 0)
489 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700491 if (last_first == FIRST_TO_LAST) {
492 /* copy items to left */
493 pos = 0;
494 if (cpy_num == 1)
495 bytes = cpy_bytes;
496 else
497 bytes = -1;
498
499 /* copy the first item or it part or nothing to the end of the DEST (i = leaf_copy_boundary_item(DEST,SOURCE,0,bytes)) */
500 i = leaf_copy_boundary_item(dest_bi, src, FIRST_TO_LAST, bytes);
501 cpy_num -= i;
502 if (cpy_num == 0)
503 return i;
504 pos += i;
505 if (cpy_bytes == -1)
506 /* copy first cpy_num items starting from position 'pos' of SOURCE to end of DEST */
507 leaf_copy_items_entirely(dest_bi, src, FIRST_TO_LAST,
508 pos, cpy_num);
509 else {
510 /* copy first cpy_num-1 items starting from position 'pos-1' of the SOURCE to the end of the DEST */
511 leaf_copy_items_entirely(dest_bi, src, FIRST_TO_LAST,
512 pos, cpy_num - 1);
513
514 /* copy part of the item which number is cpy_num+pos-1 to the end of the DEST */
515 leaf_item_bottle(dest_bi, src, FIRST_TO_LAST,
516 cpy_num + pos - 1, cpy_bytes);
517 }
518 } else {
519 /* copy items to right */
520 src_nr_item = B_NR_ITEMS(src);
521 if (cpy_num == 1)
522 bytes = cpy_bytes;
523 else
524 bytes = -1;
525
526 /* copy the last item or it part or nothing to the begin of the DEST (i = leaf_copy_boundary_item(DEST,SOURCE,1,bytes)); */
527 i = leaf_copy_boundary_item(dest_bi, src, LAST_TO_FIRST, bytes);
528
529 cpy_num -= i;
530 if (cpy_num == 0)
531 return i;
532
533 pos = src_nr_item - cpy_num - i;
534 if (cpy_bytes == -1) {
535 /* starting from position 'pos' copy last cpy_num items of SOURCE to begin of DEST */
536 leaf_copy_items_entirely(dest_bi, src, LAST_TO_FIRST,
537 pos, cpy_num);
538 } else {
539 /* copy last cpy_num-1 items starting from position 'pos+1' of the SOURCE to the begin of the DEST; */
540 leaf_copy_items_entirely(dest_bi, src, LAST_TO_FIRST,
541 pos + 1, cpy_num - 1);
542
543 /* copy part of the item which number is pos to the begin of the DEST */
544 leaf_item_bottle(dest_bi, src, LAST_TO_FIRST, pos,
545 cpy_bytes);
546 }
547 }
548 return i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549}
550
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551/* there are types of coping: from S[0] to L[0], from S[0] to R[0],
552 from R[0] to L[0]. for each of these we have to define parent and
553 positions of destination and source buffers */
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700554static void leaf_define_dest_src_infos(int shift_mode, struct tree_balance *tb,
555 struct buffer_info *dest_bi,
556 struct buffer_info *src_bi,
557 int *first_last,
558 struct buffer_head *Snew)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700560 memset(dest_bi, 0, sizeof(struct buffer_info));
561 memset(src_bi, 0, sizeof(struct buffer_info));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700563 /* define dest, src, dest parent, dest position */
564 switch (shift_mode) {
565 case LEAF_FROM_S_TO_L: /* it is used in leaf_shift_left */
566 src_bi->tb = tb;
567 src_bi->bi_bh = PATH_PLAST_BUFFER(tb->tb_path);
568 src_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
569 src_bi->bi_position = PATH_H_B_ITEM_ORDER(tb->tb_path, 0); /* src->b_item_order */
570 dest_bi->tb = tb;
571 dest_bi->bi_bh = tb->L[0];
572 dest_bi->bi_parent = tb->FL[0];
573 dest_bi->bi_position = get_left_neighbor_position(tb, 0);
574 *first_last = FIRST_TO_LAST;
575 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700577 case LEAF_FROM_S_TO_R: /* it is used in leaf_shift_right */
578 src_bi->tb = tb;
579 src_bi->bi_bh = PATH_PLAST_BUFFER(tb->tb_path);
580 src_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
581 src_bi->bi_position = PATH_H_B_ITEM_ORDER(tb->tb_path, 0);
582 dest_bi->tb = tb;
583 dest_bi->bi_bh = tb->R[0];
584 dest_bi->bi_parent = tb->FR[0];
585 dest_bi->bi_position = get_right_neighbor_position(tb, 0);
586 *first_last = LAST_TO_FIRST;
587 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700589 case LEAF_FROM_R_TO_L: /* it is used in balance_leaf_when_delete */
590 src_bi->tb = tb;
591 src_bi->bi_bh = tb->R[0];
592 src_bi->bi_parent = tb->FR[0];
593 src_bi->bi_position = get_right_neighbor_position(tb, 0);
594 dest_bi->tb = tb;
595 dest_bi->bi_bh = tb->L[0];
596 dest_bi->bi_parent = tb->FL[0];
597 dest_bi->bi_position = get_left_neighbor_position(tb, 0);
598 *first_last = FIRST_TO_LAST;
599 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700601 case LEAF_FROM_L_TO_R: /* it is used in balance_leaf_when_delete */
602 src_bi->tb = tb;
603 src_bi->bi_bh = tb->L[0];
604 src_bi->bi_parent = tb->FL[0];
605 src_bi->bi_position = get_left_neighbor_position(tb, 0);
606 dest_bi->tb = tb;
607 dest_bi->bi_bh = tb->R[0];
608 dest_bi->bi_parent = tb->FR[0];
609 dest_bi->bi_position = get_right_neighbor_position(tb, 0);
610 *first_last = LAST_TO_FIRST;
611 break;
612
613 case LEAF_FROM_S_TO_SNEW:
614 src_bi->tb = tb;
615 src_bi->bi_bh = PATH_PLAST_BUFFER(tb->tb_path);
616 src_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
617 src_bi->bi_position = PATH_H_B_ITEM_ORDER(tb->tb_path, 0);
618 dest_bi->tb = tb;
619 dest_bi->bi_bh = Snew;
620 dest_bi->bi_parent = NULL;
621 dest_bi->bi_position = 0;
622 *first_last = LAST_TO_FIRST;
623 break;
624
625 default:
Jeff Mahoneyc3a9c212009-03-30 14:02:25 -0400626 reiserfs_panic(sb_from_bi(src_bi), "vs-10250",
627 "shift type is unknown (%d)", shift_mode);
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700628 }
Al Viro9dce07f2008-03-29 03:07:28 +0000629 RFALSE(!src_bi->bi_bh || !dest_bi->bi_bh,
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700630 "vs-10260: mode==%d, source (%p) or dest (%p) buffer is initialized incorrectly",
631 shift_mode, src_bi->bi_bh, dest_bi->bi_bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632}
633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634/* copy mov_num items and mov_bytes of the (mov_num-1)th item to
635 neighbor. Delete them from source */
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700636int leaf_move_items(int shift_mode, struct tree_balance *tb, int mov_num,
637 int mov_bytes, struct buffer_head *Snew)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700639 int ret_value;
640 struct buffer_info dest_bi, src_bi;
641 int first_last;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700643 leaf_define_dest_src_infos(shift_mode, tb, &dest_bi, &src_bi,
644 &first_last, Snew);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700646 ret_value =
647 leaf_copy_items(&dest_bi, src_bi.bi_bh, first_last, mov_num,
648 mov_bytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700650 leaf_delete_items(&src_bi, first_last,
651 (first_last ==
652 FIRST_TO_LAST) ? 0 : (B_NR_ITEMS(src_bi.bi_bh) -
653 mov_num), mov_num, mov_bytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700655 return ret_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656}
657
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658/* Shift shift_num items (and shift_bytes of last shifted item if shift_bytes != -1)
659 from S[0] to L[0] and replace the delimiting key */
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700660int leaf_shift_left(struct tree_balance *tb, int shift_num, int shift_bytes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700662 struct buffer_head *S0 = PATH_PLAST_BUFFER(tb->tb_path);
663 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700665 /* move shift_num (and shift_bytes bytes) items from S[0] to left neighbor L[0] */
666 i = leaf_move_items(LEAF_FROM_S_TO_L, tb, shift_num, shift_bytes, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700668 if (shift_num) {
669 if (B_NR_ITEMS(S0) == 0) { /* number of items in S[0] == 0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700671 RFALSE(shift_bytes != -1,
672 "vs-10270: S0 is empty now, but shift_bytes != -1 (%d)",
673 shift_bytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674#ifdef CONFIG_REISERFS_CHECK
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700675 if (tb->tb_mode == M_PASTE || tb->tb_mode == M_INSERT) {
676 print_cur_tb("vs-10275");
Jeff Mahoneyc3a9c212009-03-30 14:02:25 -0400677 reiserfs_panic(tb->tb_sb, "vs-10275",
678 "balance condition corrupted "
679 "(%c)", tb->tb_mode);
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700680 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681#endif
682
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700683 if (PATH_H_POSITION(tb->tb_path, 1) == 0)
684 replace_key(tb, tb->CFL[0], tb->lkey[0],
685 PATH_H_PPARENT(tb->tb_path, 0), 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700687 } else {
688 /* replace lkey in CFL[0] by 0-th key from S[0]; */
689 replace_key(tb, tb->CFL[0], tb->lkey[0], S0, 0);
690
691 RFALSE((shift_bytes != -1 &&
692 !(is_direntry_le_ih(B_N_PITEM_HEAD(S0, 0))
693 && !I_ENTRY_COUNT(B_N_PITEM_HEAD(S0, 0)))) &&
694 (!op_is_left_mergeable
695 (B_N_PKEY(S0, 0), S0->b_size)),
696 "vs-10280: item must be mergeable");
697 }
698 }
699
700 return i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701}
702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703/* CLEANING STOPPED HERE */
704
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705/* Shift shift_num (shift_bytes) items from S[0] to the right neighbor, and replace the delimiting key */
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700706int leaf_shift_right(struct tree_balance *tb, int shift_num, int shift_bytes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700708 // struct buffer_head * S0 = PATH_PLAST_BUFFER (tb->tb_path);
709 int ret_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700711 /* move shift_num (and shift_bytes) items from S[0] to right neighbor R[0] */
712 ret_value =
713 leaf_move_items(LEAF_FROM_S_TO_R, tb, shift_num, shift_bytes, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700715 /* replace rkey in CFR[0] by the 0-th key from R[0] */
716 if (shift_num) {
717 replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700719 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700721 return ret_value;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722}
723
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700724static void leaf_delete_items_entirely(struct buffer_info *bi,
725 int first, int del_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726/* If del_bytes == -1, starting from position 'first' delete del_num items in whole in buffer CUR.
Jeff Mahoney0222e652009-03-30 14:02:44 -0400727 If not.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 If last_first == 0. Starting from position 'first' delete del_num-1 items in whole. Delete part of body of
729 the first item. Part defined by del_bytes. Don't delete first item header
730 If last_first == 1. Starting from position 'first+1' delete del_num-1 items in whole. Delete part of body of
731 the last item . Part defined by del_bytes. Don't delete last item header.
732*/
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700733void leaf_delete_items(struct buffer_info *cur_bi, int last_first,
734 int first, int del_num, int del_bytes)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700736 struct buffer_head *bh;
737 int item_amount = B_NR_ITEMS(bh = cur_bi->bi_bh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700739 RFALSE(!bh, "10155: bh is not defined");
740 RFALSE(del_num < 0, "10160: del_num can not be < 0. del_num==%d",
741 del_num);
742 RFALSE(first < 0
743 || first + del_num > item_amount,
744 "10165: invalid number of first item to be deleted (%d) or "
745 "no so much items (%d) to delete (only %d)", first,
746 first + del_num, item_amount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700748 if (del_num == 0)
749 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700751 if (first == 0 && del_num == item_amount && del_bytes == -1) {
752 make_empty_node(cur_bi);
753 do_balance_mark_leaf_dirty(cur_bi->tb, bh, 0);
754 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700757 if (del_bytes == -1)
758 /* delete del_num items beginning from item in position first */
759 leaf_delete_items_entirely(cur_bi, first, del_num);
760 else {
761 if (last_first == FIRST_TO_LAST) {
762 /* delete del_num-1 items beginning from item in position first */
763 leaf_delete_items_entirely(cur_bi, first, del_num - 1);
764
765 /* delete the part of the first item of the bh
766 do not delete item header
767 */
768 leaf_cut_from_buffer(cur_bi, 0, 0, del_bytes);
769 } else {
770 struct item_head *ih;
771 int len;
772
773 /* delete del_num-1 items beginning from item in position first+1 */
774 leaf_delete_items_entirely(cur_bi, first + 1,
775 del_num - 1);
776
777 if (is_direntry_le_ih
778 (ih = B_N_PITEM_HEAD(bh, B_NR_ITEMS(bh) - 1)))
779 /* the last item is directory */
780 /* len = numbers of directory entries in this item */
781 len = ih_entry_count(ih);
782 else
783 /* len = body len of item */
784 len = ih_item_len(ih);
785
Jeff Mahoney0222e652009-03-30 14:02:44 -0400786 /* delete the part of the last item of the bh
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700787 do not delete item header
788 */
789 leaf_cut_from_buffer(cur_bi, B_NR_ITEMS(bh) - 1,
790 len - del_bytes, del_bytes);
791 }
792 }
793}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795/* insert item into the leaf node in position before */
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700796void leaf_insert_into_buf(struct buffer_info *bi, int before,
797 struct item_head *inserted_item_ih,
798 const char *inserted_item_body, int zeros_number)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700800 struct buffer_head *bh = bi->bi_bh;
801 int nr, free_space;
802 struct block_head *blkh;
803 struct item_head *ih;
804 int i;
805 int last_loc, unmoved_loc;
806 char *to;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700808 blkh = B_BLK_HEAD(bh);
809 nr = blkh_nr_item(blkh);
810 free_space = blkh_free_space(blkh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700812 /* check free space */
813 RFALSE(free_space < ih_item_len(inserted_item_ih) + IH_SIZE,
814 "vs-10170: not enough free space in block %z, new item %h",
815 bh, inserted_item_ih);
816 RFALSE(zeros_number > ih_item_len(inserted_item_ih),
817 "vs-10172: zero number == %d, item length == %d",
818 zeros_number, ih_item_len(inserted_item_ih));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700820 /* get item new item must be inserted before */
821 ih = B_N_PITEM_HEAD(bh, before);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700823 /* prepare space for the body of new item */
824 last_loc = nr ? ih_location(&(ih[nr - before - 1])) : bh->b_size;
825 unmoved_loc = before ? ih_location(ih - 1) : bh->b_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700827 memmove(bh->b_data + last_loc - ih_item_len(inserted_item_ih),
828 bh->b_data + last_loc, unmoved_loc - last_loc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700830 to = bh->b_data + unmoved_loc - ih_item_len(inserted_item_ih);
831 memset(to, 0, zeros_number);
832 to += zeros_number;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700834 /* copy body to prepared space */
835 if (inserted_item_body)
836 memmove(to, inserted_item_body,
837 ih_item_len(inserted_item_ih) - zeros_number);
838 else
839 memset(to, '\0', ih_item_len(inserted_item_ih) - zeros_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700841 /* insert item header */
842 memmove(ih + 1, ih, IH_SIZE * (nr - before));
843 memmove(ih, inserted_item_ih, IH_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700845 /* change locations */
846 for (i = before; i < nr + 1; i++) {
847 unmoved_loc -= ih_item_len(&(ih[i - before]));
848 put_ih_location(&(ih[i - before]), unmoved_loc);
849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700851 /* sizes, free space, item number */
852 set_blkh_nr_item(blkh, blkh_nr_item(blkh) + 1);
853 set_blkh_free_space(blkh,
854 free_space - (IH_SIZE +
855 ih_item_len(inserted_item_ih)));
856 do_balance_mark_leaf_dirty(bi->tb, bh, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700858 if (bi->bi_parent) {
859 struct disk_child *t_dc;
860 t_dc = B_N_CHILD(bi->bi_parent, bi->bi_position);
861 put_dc_size(t_dc,
862 dc_size(t_dc) + (IH_SIZE +
863 ih_item_len(inserted_item_ih)));
864 do_balance_mark_internal_dirty(bi->tb, bi->bi_parent, 0);
865 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866}
867
Jeff Mahoney0222e652009-03-30 14:02:44 -0400868/* paste paste_size bytes to affected_item_num-th item.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 When item is a directory, this only prepare space for new entries */
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700870void leaf_paste_in_buffer(struct buffer_info *bi, int affected_item_num,
871 int pos_in_item, int paste_size,
872 const char *body, int zeros_number)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700874 struct buffer_head *bh = bi->bi_bh;
875 int nr, free_space;
876 struct block_head *blkh;
877 struct item_head *ih;
878 int i;
879 int last_loc, unmoved_loc;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700881 blkh = B_BLK_HEAD(bh);
882 nr = blkh_nr_item(blkh);
883 free_space = blkh_free_space(blkh);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700884
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700885 /* check free space */
886 RFALSE(free_space < paste_size,
887 "vs-10175: not enough free space: needed %d, available %d",
888 paste_size, free_space);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889
890#ifdef CONFIG_REISERFS_CHECK
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700891 if (zeros_number > paste_size) {
Jeff Mahoneyc3a9c212009-03-30 14:02:25 -0400892 struct super_block *sb = NULL;
893 if (bi && bi->tb)
894 sb = bi->tb->tb_sb;
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700895 print_cur_tb("10177");
Jeff Mahoneyc3a9c212009-03-30 14:02:25 -0400896 reiserfs_panic(sb, "vs-10177",
897 "zeros_number == %d, paste_size == %d",
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700898 zeros_number, paste_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 }
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700900#endif /* CONFIG_REISERFS_CHECK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700902 /* item to be appended */
903 ih = B_N_PITEM_HEAD(bh, affected_item_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700905 last_loc = ih_location(&(ih[nr - affected_item_num - 1]));
906 unmoved_loc = affected_item_num ? ih_location(ih - 1) : bh->b_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700908 /* prepare space */
909 memmove(bh->b_data + last_loc - paste_size, bh->b_data + last_loc,
910 unmoved_loc - last_loc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700912 /* change locations */
913 for (i = affected_item_num; i < nr; i++)
914 put_ih_location(&(ih[i - affected_item_num]),
915 ih_location(&(ih[i - affected_item_num])) -
916 paste_size);
917
918 if (body) {
919 if (!is_direntry_le_ih(ih)) {
920 if (!pos_in_item) {
921 /* shift data to right */
922 memmove(bh->b_data + ih_location(ih) +
923 paste_size,
924 bh->b_data + ih_location(ih),
925 ih_item_len(ih));
926 /* paste data in the head of item */
927 memset(bh->b_data + ih_location(ih), 0,
928 zeros_number);
929 memcpy(bh->b_data + ih_location(ih) +
930 zeros_number, body,
931 paste_size - zeros_number);
932 } else {
933 memset(bh->b_data + unmoved_loc - paste_size, 0,
934 zeros_number);
935 memcpy(bh->b_data + unmoved_loc - paste_size +
936 zeros_number, body,
937 paste_size - zeros_number);
938 }
939 }
940 } else
941 memset(bh->b_data + unmoved_loc - paste_size, '\0', paste_size);
942
943 put_ih_item_len(ih, ih_item_len(ih) + paste_size);
944
945 /* change free space */
946 set_blkh_free_space(blkh, free_space - paste_size);
947
948 do_balance_mark_leaf_dirty(bi->tb, bh, 0);
949
950 if (bi->bi_parent) {
951 struct disk_child *t_dc =
952 B_N_CHILD(bi->bi_parent, bi->bi_position);
953 put_dc_size(t_dc, dc_size(t_dc) + paste_size);
954 do_balance_mark_internal_dirty(bi->tb, bi->bi_parent, 0);
955 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956}
957
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958/* cuts DEL_COUNT entries beginning from FROM-th entry. Directory item
959 does not have free space, so it moves DEHs and remaining records as
960 necessary. Return value is size of removed part of directory item
961 in bytes. */
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700962static int leaf_cut_entries(struct buffer_head *bh,
963 struct item_head *ih, int from, int del_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700965 char *item;
966 struct reiserfs_de_head *deh;
967 int prev_record_offset; /* offset of record, that is (from-1)th */
968 char *prev_record; /* */
969 int cut_records_len; /* length of all removed records */
970 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700972 /* make sure, that item is directory and there are enough entries to
973 remove */
974 RFALSE(!is_direntry_le_ih(ih), "10180: item is not directory item");
975 RFALSE(I_ENTRY_COUNT(ih) < from + del_count,
976 "10185: item contains not enough entries: entry_cout = %d, from = %d, to delete = %d",
977 I_ENTRY_COUNT(ih), from, del_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700979 if (del_count == 0)
980 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700982 /* first byte of item */
983 item = bh->b_data + ih_location(ih);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700985 /* entry head array */
986 deh = B_I_DEH(bh, ih);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700988 /* first byte of remaining entries, those are BEFORE cut entries
989 (prev_record) and length of all removed records (cut_records_len) */
990 prev_record_offset =
991 (from ? deh_location(&(deh[from - 1])) : ih_item_len(ih));
992 cut_records_len = prev_record_offset /*from_record */ -
993 deh_location(&(deh[from + del_count - 1]));
994 prev_record = item + prev_record_offset;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995
Linus Torvaldsbd4c6252005-07-12 20:21:28 -0700996 /* adjust locations of remaining entries */
997 for (i = I_ENTRY_COUNT(ih) - 1; i > from + del_count - 1; i--)
998 put_deh_location(&(deh[i]),
999 deh_location(&deh[i]) -
1000 (DEH_SIZE * del_count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001002 for (i = 0; i < from; i++)
1003 put_deh_location(&(deh[i]),
1004 deh_location(&deh[i]) - (DEH_SIZE * del_count +
1005 cut_records_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001007 put_ih_entry_count(ih, ih_entry_count(ih) - del_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001009 /* shift entry head array and entries those are AFTER removed entries */
1010 memmove((char *)(deh + from),
1011 deh + from + del_count,
1012 prev_record - cut_records_len - (char *)(deh + from +
1013 del_count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001015 /* shift records, those are BEFORE removed entries */
1016 memmove(prev_record - cut_records_len - DEH_SIZE * del_count,
1017 prev_record, item + ih_item_len(ih) - prev_record);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001019 return DEH_SIZE * del_count + cut_records_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020}
1021
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022/* when cut item is part of regular file
1023 pos_in_item - first byte that must be cut
1024 cut_size - number of bytes to be cut beginning from pos_in_item
Jeff Mahoney0222e652009-03-30 14:02:44 -04001025
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026 when cut item is part of directory
1027 pos_in_item - number of first deleted entry
1028 cut_size - count of deleted entries
1029 */
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001030void leaf_cut_from_buffer(struct buffer_info *bi, int cut_item_num,
1031 int pos_in_item, int cut_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001033 int nr;
1034 struct buffer_head *bh = bi->bi_bh;
1035 struct block_head *blkh;
1036 struct item_head *ih;
1037 int last_loc, unmoved_loc;
1038 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001040 blkh = B_BLK_HEAD(bh);
1041 nr = blkh_nr_item(blkh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001043 /* item head of truncated item */
1044 ih = B_N_PITEM_HEAD(bh, cut_item_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001046 if (is_direntry_le_ih(ih)) {
1047 /* first cut entry () */
1048 cut_size = leaf_cut_entries(bh, ih, pos_in_item, cut_size);
1049 if (pos_in_item == 0) {
1050 /* change key */
1051 RFALSE(cut_item_num,
1052 "when 0-th enrty of item is cut, that item must be first in the node, not %d-th",
1053 cut_item_num);
1054 /* change item key by key of first entry in the item */
1055 set_le_ih_k_offset(ih, deh_offset(B_I_DEH(bh, ih)));
1056 /*memcpy (&ih->ih_key.k_offset, &(B_I_DEH (bh, ih)->deh_offset), SHORT_KEY_SIZE); */
1057 }
1058 } else {
1059 /* item is direct or indirect */
1060 RFALSE(is_statdata_le_ih(ih), "10195: item is stat data");
1061 RFALSE(pos_in_item && pos_in_item + cut_size != ih_item_len(ih),
1062 "10200: invalid offset (%lu) or trunc_size (%lu) or ih_item_len (%lu)",
1063 (long unsigned)pos_in_item, (long unsigned)cut_size,
1064 (long unsigned)ih_item_len(ih));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001066 /* shift item body to left if cut is from the head of item */
1067 if (pos_in_item == 0) {
1068 memmove(bh->b_data + ih_location(ih),
1069 bh->b_data + ih_location(ih) + cut_size,
1070 ih_item_len(ih) - cut_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001072 /* change key of item */
1073 if (is_direct_le_ih(ih))
1074 set_le_ih_k_offset(ih,
1075 le_ih_k_offset(ih) +
1076 cut_size);
1077 else {
1078 set_le_ih_k_offset(ih,
1079 le_ih_k_offset(ih) +
1080 (cut_size / UNFM_P_SIZE) *
1081 bh->b_size);
1082 RFALSE(ih_item_len(ih) == cut_size
1083 && get_ih_free_space(ih),
1084 "10205: invalid ih_free_space (%h)", ih);
1085 }
1086 }
1087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001089 /* location of the last item */
1090 last_loc = ih_location(&(ih[nr - cut_item_num - 1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001092 /* location of the item, which is remaining at the same place */
1093 unmoved_loc = cut_item_num ? ih_location(ih - 1) : bh->b_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001095 /* shift */
1096 memmove(bh->b_data + last_loc + cut_size, bh->b_data + last_loc,
1097 unmoved_loc - last_loc - cut_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001099 /* change item length */
1100 put_ih_item_len(ih, ih_item_len(ih) - cut_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001102 if (is_indirect_le_ih(ih)) {
1103 if (pos_in_item)
1104 set_ih_free_space(ih, 0);
1105 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001107 /* change locations */
1108 for (i = cut_item_num; i < nr; i++)
1109 put_ih_location(&(ih[i - cut_item_num]),
1110 ih_location(&ih[i - cut_item_num]) + cut_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001112 /* size, free space */
1113 set_blkh_free_space(blkh, blkh_free_space(blkh) + cut_size);
1114
1115 do_balance_mark_leaf_dirty(bi->tb, bh, 0);
1116
1117 if (bi->bi_parent) {
1118 struct disk_child *t_dc;
1119 t_dc = B_N_CHILD(bi->bi_parent, bi->bi_position);
1120 put_dc_size(t_dc, dc_size(t_dc) - cut_size);
1121 do_balance_mark_internal_dirty(bi->tb, bi->bi_parent, 0);
1122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123}
1124
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125/* delete del_num items from buffer starting from the first'th item */
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001126static void leaf_delete_items_entirely(struct buffer_info *bi,
1127 int first, int del_num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001129 struct buffer_head *bh = bi->bi_bh;
1130 int nr;
1131 int i, j;
1132 int last_loc, last_removed_loc;
1133 struct block_head *blkh;
1134 struct item_head *ih;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001136 RFALSE(bh == NULL, "10210: buffer is 0");
1137 RFALSE(del_num < 0, "10215: del_num less than 0 (%d)", del_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001139 if (del_num == 0)
1140 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001142 blkh = B_BLK_HEAD(bh);
1143 nr = blkh_nr_item(blkh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001145 RFALSE(first < 0 || first + del_num > nr,
1146 "10220: first=%d, number=%d, there is %d items", first, del_num,
1147 nr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001149 if (first == 0 && del_num == nr) {
1150 /* this does not work */
1151 make_empty_node(bi);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001153 do_balance_mark_leaf_dirty(bi->tb, bh, 0);
1154 return;
1155 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001157 ih = B_N_PITEM_HEAD(bh, first);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001159 /* location of unmovable item */
1160 j = (first == 0) ? bh->b_size : ih_location(ih - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001162 /* delete items */
1163 last_loc = ih_location(&(ih[nr - 1 - first]));
1164 last_removed_loc = ih_location(&(ih[del_num - 1]));
1165
1166 memmove(bh->b_data + last_loc + j - last_removed_loc,
1167 bh->b_data + last_loc, last_removed_loc - last_loc);
1168
1169 /* delete item headers */
1170 memmove(ih, ih + del_num, (nr - first - del_num) * IH_SIZE);
1171
1172 /* change item location */
1173 for (i = first; i < nr - del_num; i++)
1174 put_ih_location(&(ih[i - first]),
1175 ih_location(&(ih[i - first])) + (j -
1176 last_removed_loc));
1177
1178 /* sizes, item number */
1179 set_blkh_nr_item(blkh, blkh_nr_item(blkh) - del_num);
1180 set_blkh_free_space(blkh,
1181 blkh_free_space(blkh) + (j - last_removed_loc +
1182 IH_SIZE * del_num));
1183
1184 do_balance_mark_leaf_dirty(bi->tb, bh, 0);
1185
1186 if (bi->bi_parent) {
1187 struct disk_child *t_dc =
1188 B_N_CHILD(bi->bi_parent, bi->bi_position);
1189 put_dc_size(t_dc,
1190 dc_size(t_dc) - (j - last_removed_loc +
1191 IH_SIZE * del_num));
1192 do_balance_mark_internal_dirty(bi->tb, bi->bi_parent, 0);
1193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194}
1195
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196/* paste new_entry_count entries (new_dehs, records) into position before to item_num-th item */
Jeff Mahoneyeba00302009-03-30 14:02:18 -04001197void leaf_paste_entries(struct buffer_info *bi,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 int item_num,
1199 int before,
1200 int new_entry_count,
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001201 struct reiserfs_de_head *new_dehs,
1202 const char *records, int paste_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203{
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001204 struct item_head *ih;
1205 char *item;
1206 struct reiserfs_de_head *deh;
1207 char *insert_point;
1208 int i, old_entry_num;
Jeff Mahoneyeba00302009-03-30 14:02:18 -04001209 struct buffer_head *bh = bi->bi_bh;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001211 if (new_entry_count == 0)
1212 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001214 ih = B_N_PITEM_HEAD(bh, item_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001216 /* make sure, that item is directory, and there are enough records in it */
1217 RFALSE(!is_direntry_le_ih(ih), "10225: item is not directory item");
1218 RFALSE(I_ENTRY_COUNT(ih) < before,
1219 "10230: there are no entry we paste entries before. entry_count = %d, before = %d",
1220 I_ENTRY_COUNT(ih), before);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001222 /* first byte of dest item */
1223 item = bh->b_data + ih_location(ih);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001225 /* entry head array */
1226 deh = B_I_DEH(bh, ih);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001228 /* new records will be pasted at this point */
1229 insert_point =
1230 item +
1231 (before ? deh_location(&(deh[before - 1]))
1232 : (ih_item_len(ih) - paste_size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001234 /* adjust locations of records that will be AFTER new records */
1235 for (i = I_ENTRY_COUNT(ih) - 1; i >= before; i--)
1236 put_deh_location(&(deh[i]),
1237 deh_location(&(deh[i])) +
1238 (DEH_SIZE * new_entry_count));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001240 /* adjust locations of records that will be BEFORE new records */
1241 for (i = 0; i < before; i++)
1242 put_deh_location(&(deh[i]),
1243 deh_location(&(deh[i])) + paste_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001245 old_entry_num = I_ENTRY_COUNT(ih);
1246 put_ih_entry_count(ih, ih_entry_count(ih) + new_entry_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001248 /* prepare space for pasted records */
1249 memmove(insert_point + paste_size, insert_point,
1250 item + (ih_item_len(ih) - paste_size) - insert_point);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001252 /* copy new records */
1253 memcpy(insert_point + DEH_SIZE * new_entry_count, records,
1254 paste_size - DEH_SIZE * new_entry_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001256 /* prepare space for new entry heads */
1257 deh += before;
1258 memmove((char *)(deh + new_entry_count), deh,
1259 insert_point - (char *)deh);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001261 /* copy new entry heads */
1262 deh = (struct reiserfs_de_head *)((char *)deh);
1263 memcpy(deh, new_dehs, DEH_SIZE * new_entry_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001265 /* set locations of new records */
1266 for (i = 0; i < new_entry_count; i++) {
1267 put_deh_location(&(deh[i]),
1268 deh_location(&(deh[i])) +
1269 (-deh_location
1270 (&(new_dehs[new_entry_count - 1])) +
1271 insert_point + DEH_SIZE * new_entry_count -
1272 item));
1273 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001275 /* change item key if necessary (when we paste before 0-th entry */
1276 if (!before) {
1277 set_le_ih_k_offset(ih, deh_offset(new_dehs));
Jeff Mahoney0222e652009-03-30 14:02:44 -04001278/* memcpy (&ih->ih_key.k_offset,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 &new_dehs->deh_offset, SHORT_KEY_SIZE);*/
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001280 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281#ifdef CONFIG_REISERFS_CHECK
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001282 {
1283 int prev, next;
1284 /* check record locations */
1285 deh = B_I_DEH(bh, ih);
1286 for (i = 0; i < I_ENTRY_COUNT(ih); i++) {
1287 next =
1288 (i <
1289 I_ENTRY_COUNT(ih) -
1290 1) ? deh_location(&(deh[i + 1])) : 0;
1291 prev = (i != 0) ? deh_location(&(deh[i - 1])) : 0;
1292
1293 if (prev && prev <= deh_location(&(deh[i])))
Jeff Mahoney0030b642009-03-30 14:02:28 -04001294 reiserfs_error(sb_from_bi(bi), "vs-10240",
1295 "directory item (%h) "
1296 "corrupted (prev %a, "
1297 "cur(%d) %a)",
1298 ih, deh + i - 1, i, deh + i);
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001299 if (next && next >= deh_location(&(deh[i])))
Jeff Mahoney0030b642009-03-30 14:02:28 -04001300 reiserfs_error(sb_from_bi(bi), "vs-10250",
1301 "directory item (%h) "
1302 "corrupted (cur(%d) %a, "
1303 "next %a)",
1304 ih, i, deh + i, deh + i + 1);
Linus Torvaldsbd4c6252005-07-12 20:21:28 -07001305 }
1306 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307#endif
1308
1309}