]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/xfs_dir2_block.c
xfsprogs debian changes
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_dir2_block.c
CommitLineData
2bd0ea18 1/*
da23017d
NS
2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
5000d01d 4 *
da23017d
NS
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
2bd0ea18 7 * published by the Free Software Foundation.
5000d01d 8 *
da23017d
NS
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
5000d01d 13 *
da23017d
NS
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2bd0ea18
NS
17 */
18
19/*
20 * xfs_dir2_block.c
21 * XFS V2 directory implementation, single-block form.
22 * See xfs_dir2_block.h for the format.
23 */
24
25#include <xfs.h>
26
27/*
28 * Add an entry to a block directory.
29 */
30int /* error */
31xfs_dir2_block_addname(
32 xfs_da_args_t *args) /* directory op arguments */
33{
34 xfs_dir2_data_free_t *bf; /* bestfree table in block */
35 xfs_dir2_block_t *block; /* directory block structure */
36 xfs_dir2_leaf_entry_t *blp; /* block leaf entries */
37 xfs_dabuf_t *bp; /* buffer for block */
38 xfs_dir2_block_tail_t *btp; /* block tail */
39 int compact; /* need to compact leaf ents */
40 xfs_dir2_data_entry_t *dep; /* block data entry */
41 xfs_inode_t *dp; /* directory inode */
42 xfs_dir2_data_unused_t *dup; /* block unused entry */
43 int error; /* error return value */
0e266570 44 xfs_dir2_data_unused_t *enddup=NULL; /* unused at end of data */
2bd0ea18
NS
45 xfs_dahash_t hash; /* hash value of found entry */
46 int high; /* high index for binary srch */
47 int highstale; /* high stale index */
0e266570
NS
48 int lfloghigh=0; /* last final leaf to log */
49 int lfloglow=0; /* first final leaf to log */
2bd0ea18
NS
50 int len; /* length of the new entry */
51 int low; /* low index for binary srch */
52 int lowstale; /* low stale index */
0e266570 53 int mid=0; /* midpoint for binary srch */
2bd0ea18
NS
54 xfs_mount_t *mp; /* filesystem mount point */
55 int needlog; /* need to log header */
56 int needscan; /* need to rescan freespace */
57 xfs_dir2_data_off_t *tagp; /* pointer to tag value */
58 xfs_trans_t *tp; /* transaction structure */
59
60 xfs_dir2_trace_args("block_addname", args);
61 dp = args->dp;
62 tp = args->trans;
63 mp = dp->i_mount;
64 /*
65 * Read the (one and only) directory block into dabuf bp.
66 */
0e266570
NS
67 if ((error =
68 xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) {
2bd0ea18
NS
69 return error;
70 }
71 ASSERT(bp != NULL);
72 block = bp->data;
73 /*
74 * Check the magic number, corrupted if wrong.
75 */
4ca431fc
NS
76 if (unlikely(INT_GET(block->hdr.magic, ARCH_CONVERT)
77 != XFS_DIR2_BLOCK_MAGIC)) {
78 XFS_CORRUPTION_ERROR("xfs_dir2_block_addname",
79 XFS_ERRLEVEL_LOW, mp, block);
2bd0ea18
NS
80 xfs_da_brelse(tp, bp);
81 return XFS_ERROR(EFSCORRUPTED);
82 }
83 len = XFS_DIR2_DATA_ENTSIZE(args->namelen);
84 /*
85 * Set up pointers to parts of the block.
86 */
87 bf = block->hdr.bestfree;
88 btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
46eca962 89 blp = XFS_DIR2_BLOCK_LEAF_P(btp);
2bd0ea18
NS
90 /*
91 * No stale entries? Need space for entry and new leaf.
92 */
46eca962 93 if (!btp->stale) {
2bd0ea18
NS
94 /*
95 * Tag just before the first leaf entry.
96 */
97 tagp = (xfs_dir2_data_off_t *)blp - 1;
98 /*
99 * Data object just before the first leaf entry.
100 */
101 enddup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT));
102 /*
103 * If it's not free then can't do this add without cleaning up:
104 * the space before the first leaf entry needs to be free so it
105 * can be expanded to hold the pointer to the new entry.
106 */
107 if (INT_GET(enddup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG)
108 dup = enddup = NULL;
109 /*
110 * Check out the biggest freespace and see if it's the same one.
111 */
112 else {
113 dup = (xfs_dir2_data_unused_t *)
114 ((char *)block + INT_GET(bf[0].offset, ARCH_CONVERT));
115 if (dup == enddup) {
116 /*
117 * It is the biggest freespace, is it too small
118 * to hold the new leaf too?
119 */
120 if (INT_GET(dup->length, ARCH_CONVERT) < len + (uint)sizeof(*blp)) {
2bd0ea18
NS
121 /*
122 * Yes, we use the second-largest
123 * entry instead if it works.
124 */
125 if (INT_GET(bf[1].length, ARCH_CONVERT) >= len)
126 dup = (xfs_dir2_data_unused_t *)
127 ((char *)block +
128 INT_GET(bf[1].offset, ARCH_CONVERT));
129 else
130 dup = NULL;
131 }
132 } else {
133 /*
134 * Not the same free entry,
135 * just check its length.
136 */
137 if (INT_GET(dup->length, ARCH_CONVERT) < len) {
2bd0ea18
NS
138 dup = NULL;
139 }
140 }
141 }
142 compact = 0;
143 }
144 /*
145 * If there are stale entries we'll use one for the leaf.
146 * Is the biggest entry enough to avoid compaction?
147 */
148 else if (INT_GET(bf[0].length, ARCH_CONVERT) >= len) {
149 dup = (xfs_dir2_data_unused_t *)
150 ((char *)block + INT_GET(bf[0].offset, ARCH_CONVERT));
151 compact = 0;
152 }
153 /*
154 * Will need to compact to make this work.
155 */
156 else {
2bd0ea18
NS
157 /*
158 * Tag just before the first leaf entry.
159 */
160 tagp = (xfs_dir2_data_off_t *)blp - 1;
161 /*
162 * Data object just before the first leaf entry.
163 */
164 dup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT));
165 /*
166 * If it's not free then the data will go where the
167 * leaf data starts now, if it works at all.
168 */
169 if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
170 if (INT_GET(dup->length, ARCH_CONVERT) + (INT_GET(btp->stale, ARCH_CONVERT) - 1) *
171 (uint)sizeof(*blp) < len)
172 dup = NULL;
173 } else if ((INT_GET(btp->stale, ARCH_CONVERT) - 1) * (uint)sizeof(*blp) < len)
174 dup = NULL;
175 else
176 dup = (xfs_dir2_data_unused_t *)blp;
177 compact = 1;
178 }
179 /*
180 * If this isn't a real add, we're done with the buffer.
181 */
182 if (args->justcheck)
183 xfs_da_brelse(tp, bp);
184 /*
185 * If we don't have space for the new entry & leaf ...
186 */
187 if (!dup) {
2bd0ea18
NS
188 /*
189 * Not trying to actually do anything, or don't have
190 * a space reservation: return no-space.
191 */
192 if (args->justcheck || args->total == 0)
193 return XFS_ERROR(ENOSPC);
194 /*
195 * Convert to the next larger format.
196 * Then add the new entry in that format.
197 */
198 error = xfs_dir2_block_to_leaf(args, bp);
199 xfs_da_buf_done(bp);
200 if (error)
201 return error;
202 return xfs_dir2_leaf_addname(args);
203 }
204 /*
205 * Just checking, and it would work, so say so.
206 */
207 if (args->justcheck)
208 return 0;
209 needlog = needscan = 0;
210 /*
211 * If need to compact the leaf entries, do it now.
212 * Leave the highest-numbered stale entry stale.
213 * XXX should be the one closest to mid but mid is not yet computed.
214 */
215 if (compact) {
2bd0ea18
NS
216 int fromidx; /* source leaf index */
217 int toidx; /* target leaf index */
218
219 for (fromidx = toidx = INT_GET(btp->count, ARCH_CONVERT) - 1,
220 highstale = lfloghigh = -1;
221 fromidx >= 0;
222 fromidx--) {
223 if (INT_GET(blp[fromidx].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) {
224 if (highstale == -1)
225 highstale = toidx;
226 else {
227 if (lfloghigh == -1)
228 lfloghigh = toidx;
229 continue;
230 }
231 }
232 if (fromidx < toidx)
233 blp[toidx] = blp[fromidx];
234 toidx--;
235 }
236 lfloglow = toidx + 1 - (INT_GET(btp->stale, ARCH_CONVERT) - 1);
237 lfloghigh -= INT_GET(btp->stale, ARCH_CONVERT) - 1;
238 INT_MOD(btp->count, ARCH_CONVERT, -(INT_GET(btp->stale, ARCH_CONVERT) - 1));
239 xfs_dir2_data_make_free(tp, bp,
240 (xfs_dir2_data_aoff_t)((char *)blp - (char *)block),
241 (xfs_dir2_data_aoff_t)((INT_GET(btp->stale, ARCH_CONVERT) - 1) * sizeof(*blp)),
242 &needlog, &needscan);
243 blp += INT_GET(btp->stale, ARCH_CONVERT) - 1;
244 INT_SET(btp->stale, ARCH_CONVERT, 1);
245 /*
246 * If we now need to rebuild the bestfree map, do so.
247 * This needs to happen before the next call to use_free.
248 */
249 if (needscan) {
250 xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block,
251 &needlog, NULL);
252 needscan = 0;
253 }
254 }
255 /*
256 * Set leaf logging boundaries to impossible state.
257 * For the no-stale case they're set explicitly.
258 */
259 else if (INT_GET(btp->stale, ARCH_CONVERT)) {
260 lfloglow = INT_GET(btp->count, ARCH_CONVERT);
261 lfloghigh = -1;
262 }
263 /*
264 * Find the slot that's first lower than our hash value, -1 if none.
265 */
266 for (low = 0, high = INT_GET(btp->count, ARCH_CONVERT) - 1; low <= high; ) {
267 mid = (low + high) >> 1;
268 if ((hash = INT_GET(blp[mid].hashval, ARCH_CONVERT)) == args->hashval)
269 break;
270 if (hash < args->hashval)
271 low = mid + 1;
272 else
273 high = mid - 1;
274 }
275 while (mid >= 0 && INT_GET(blp[mid].hashval, ARCH_CONVERT) >= args->hashval) {
2bd0ea18
NS
276 mid--;
277 }
278 /*
279 * No stale entries, will use enddup space to hold new leaf.
280 */
46eca962 281 if (!btp->stale) {
2bd0ea18
NS
282 /*
283 * Mark the space needed for the new leaf entry, now in use.
284 */
285 xfs_dir2_data_use_free(tp, bp, enddup,
286 (xfs_dir2_data_aoff_t)
287 ((char *)enddup - (char *)block + INT_GET(enddup->length, ARCH_CONVERT) -
288 sizeof(*blp)),
289 (xfs_dir2_data_aoff_t)sizeof(*blp),
290 &needlog, &needscan);
291 /*
292 * Update the tail (entry count).
293 */
294 INT_MOD(btp->count, ARCH_CONVERT, +1);
295 /*
296 * If we now need to rebuild the bestfree map, do so.
297 * This needs to happen before the next call to use_free.
298 */
299 if (needscan) {
300 xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block,
301 &needlog, NULL);
302 needscan = 0;
303 }
304 /*
305 * Adjust pointer to the first leaf entry, we're about to move
306 * the table up one to open up space for the new leaf entry.
307 * Then adjust our index to match.
308 */
309 blp--;
310 mid++;
311 if (mid)
32181a02 312 memmove(blp, &blp[1], mid * sizeof(*blp));
2bd0ea18
NS
313 lfloglow = 0;
314 lfloghigh = mid;
315 }
316 /*
317 * Use a stale leaf for our new entry.
318 */
319 else {
320 for (lowstale = mid;
321 lowstale >= 0 &&
322 INT_GET(blp[lowstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR;
323 lowstale--)
324 continue;
325 for (highstale = mid + 1;
326 highstale < INT_GET(btp->count, ARCH_CONVERT) &&
327 INT_GET(blp[highstale].address, ARCH_CONVERT) != XFS_DIR2_NULL_DATAPTR &&
328 (lowstale < 0 || mid - lowstale > highstale - mid);
329 highstale++)
330 continue;
331 /*
332 * Move entries toward the low-numbered stale entry.
333 */
334 if (lowstale >= 0 &&
335 (highstale == INT_GET(btp->count, ARCH_CONVERT) ||
336 mid - lowstale <= highstale - mid)) {
337 if (mid - lowstale)
32181a02 338 memmove(&blp[lowstale], &blp[lowstale + 1],
2bd0ea18
NS
339 (mid - lowstale) * sizeof(*blp));
340 lfloglow = MIN(lowstale, lfloglow);
341 lfloghigh = MAX(mid, lfloghigh);
342 }
343 /*
344 * Move entries toward the high-numbered stale entry.
345 */
346 else {
347 ASSERT(highstale < INT_GET(btp->count, ARCH_CONVERT));
348 mid++;
349 if (highstale - mid)
32181a02 350 memmove(&blp[mid + 1], &blp[mid],
2bd0ea18
NS
351 (highstale - mid) * sizeof(*blp));
352 lfloglow = MIN(mid, lfloglow);
353 lfloghigh = MAX(highstale, lfloghigh);
354 }
355 INT_MOD(btp->stale, ARCH_CONVERT, -1);
356 }
357 /*
358 * Point to the new data entry.
359 */
360 dep = (xfs_dir2_data_entry_t *)dup;
361 /*
362 * Fill in the leaf entry.
363 */
364 INT_SET(blp[mid].hashval, ARCH_CONVERT, args->hashval);
365 INT_SET(blp[mid].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block));
366 xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh);
367 /*
368 * Mark space for the data entry used.
369 */
370 xfs_dir2_data_use_free(tp, bp, dup,
371 (xfs_dir2_data_aoff_t)((char *)dup - (char *)block),
372 (xfs_dir2_data_aoff_t)len, &needlog, &needscan);
373 /*
374 * Create the new data entry.
375 */
376 INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
377 dep->namelen = args->namelen;
32181a02 378 memcpy(dep->name, args->name, args->namelen);
2bd0ea18
NS
379 tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
380 INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
381 /*
382 * Clean up the bestfree array and log the header, tail, and entry.
383 */
384 if (needscan)
385 xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
386 NULL);
387 if (needlog)
388 xfs_dir2_data_log_header(tp, bp);
389 xfs_dir2_block_log_tail(tp, bp);
390 xfs_dir2_data_log_entry(tp, bp, dep);
391 xfs_dir2_data_check(dp, bp);
392 xfs_da_buf_done(bp);
393 return 0;
394}
395
396/*
397 * Log leaf entries from the block.
398 */
399STATIC void
400xfs_dir2_block_log_leaf(
401 xfs_trans_t *tp, /* transaction structure */
402 xfs_dabuf_t *bp, /* block buffer */
403 int first, /* index of first logged leaf */
404 int last) /* index of last logged leaf */
405{
406 xfs_dir2_block_t *block; /* directory block structure */
407 xfs_dir2_leaf_entry_t *blp; /* block leaf entries */
408 xfs_dir2_block_tail_t *btp; /* block tail */
409 xfs_mount_t *mp; /* filesystem mount point */
410
411 mp = tp->t_mountp;
412 block = bp->data;
413 btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
46eca962 414 blp = XFS_DIR2_BLOCK_LEAF_P(btp);
2bd0ea18
NS
415 xfs_da_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)block),
416 (uint)((char *)&blp[last + 1] - (char *)block - 1));
417}
418
419/*
420 * Log the block tail.
421 */
422STATIC void
423xfs_dir2_block_log_tail(
424 xfs_trans_t *tp, /* transaction structure */
425 xfs_dabuf_t *bp) /* block buffer */
426{
427 xfs_dir2_block_t *block; /* directory block structure */
428 xfs_dir2_block_tail_t *btp; /* block tail */
429 xfs_mount_t *mp; /* filesystem mount point */
430
431 mp = tp->t_mountp;
432 block = bp->data;
433 btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
434 xfs_da_log_buf(tp, bp, (uint)((char *)btp - (char *)block),
435 (uint)((char *)(btp + 1) - (char *)block - 1));
436}
437
438/*
439 * Look up an entry in the block. This is the external routine,
440 * xfs_dir2_block_lookup_int does the real work.
441 */
442int /* error */
443xfs_dir2_block_lookup(
444 xfs_da_args_t *args) /* dir lookup arguments */
445{
446 xfs_dir2_block_t *block; /* block structure */
447 xfs_dir2_leaf_entry_t *blp; /* block leaf entries */
448 xfs_dabuf_t *bp; /* block buffer */
449 xfs_dir2_block_tail_t *btp; /* block tail */
450 xfs_dir2_data_entry_t *dep; /* block data entry */
451 xfs_inode_t *dp; /* incore inode */
452 int ent; /* entry index */
453 int error; /* error return value */
454 xfs_mount_t *mp; /* filesystem mount point */
455
456 xfs_dir2_trace_args("block_lookup", args);
457 /*
458 * Get the buffer, look up the entry.
459 * If not found (ENOENT) then return, have no buffer.
460 */
0e266570 461 if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent)))
2bd0ea18
NS
462 return error;
463 dp = args->dp;
464 mp = dp->i_mount;
465 block = bp->data;
466 xfs_dir2_data_check(dp, bp);
467 btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
46eca962 468 blp = XFS_DIR2_BLOCK_LEAF_P(btp);
2bd0ea18
NS
469 /*
470 * Get the offset from the leaf entry, to point to the data.
471 */
472 dep = (xfs_dir2_data_entry_t *)
473 ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT)));
474 /*
475 * Fill in inode number, release the block.
476 */
477 args->inumber = INT_GET(dep->inumber, ARCH_CONVERT);
478 xfs_da_brelse(args->trans, bp);
479 return XFS_ERROR(EEXIST);
480}
481
482/*
483 * Internal block lookup routine.
484 */
485STATIC int /* error */
486xfs_dir2_block_lookup_int(
487 xfs_da_args_t *args, /* dir lookup arguments */
488 xfs_dabuf_t **bpp, /* returned block buffer */
489 int *entno) /* returned entry number */
490{
491 xfs_dir2_dataptr_t addr; /* data entry address */
492 xfs_dir2_block_t *block; /* block structure */
493 xfs_dir2_leaf_entry_t *blp; /* block leaf entries */
494 xfs_dabuf_t *bp; /* block buffer */
495 xfs_dir2_block_tail_t *btp; /* block tail */
496 xfs_dir2_data_entry_t *dep; /* block data entry */
497 xfs_inode_t *dp; /* incore inode */
498 int error; /* error return value */
499 xfs_dahash_t hash; /* found hash value */
500 int high; /* binary search high index */
501 int low; /* binary search low index */
502 int mid; /* binary search current idx */
503 xfs_mount_t *mp; /* filesystem mount point */
504 xfs_trans_t *tp; /* transaction pointer */
505
506 dp = args->dp;
507 tp = args->trans;
508 mp = dp->i_mount;
509 /*
510 * Read the buffer, return error if we can't get it.
511 */
0e266570
NS
512 if ((error =
513 xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &bp, XFS_DATA_FORK))) {
2bd0ea18
NS
514 return error;
515 }
516 ASSERT(bp != NULL);
517 block = bp->data;
518 xfs_dir2_data_check(dp, bp);
519 btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
46eca962 520 blp = XFS_DIR2_BLOCK_LEAF_P(btp);
2bd0ea18
NS
521 /*
522 * Loop doing a binary search for our hash value.
523 * Find our entry, ENOENT if it's not there.
524 */
525 for (low = 0, high = INT_GET(btp->count, ARCH_CONVERT) - 1; ; ) {
526 ASSERT(low <= high);
527 mid = (low + high) >> 1;
528 if ((hash = INT_GET(blp[mid].hashval, ARCH_CONVERT)) == args->hashval)
529 break;
530 if (hash < args->hashval)
531 low = mid + 1;
532 else
533 high = mid - 1;
534 if (low > high) {
535 ASSERT(args->oknoent);
536 xfs_da_brelse(tp, bp);
537 return XFS_ERROR(ENOENT);
538 }
539 }
540 /*
541 * Back up to the first one with the right hash value.
542 */
543 while (mid > 0 && INT_GET(blp[mid - 1].hashval, ARCH_CONVERT) == args->hashval) {
2bd0ea18
NS
544 mid--;
545 }
546 /*
547 * Now loop forward through all the entries with the
548 * right hash value looking for our name.
549 */
550 do {
551 if ((addr = INT_GET(blp[mid].address, ARCH_CONVERT)) == XFS_DIR2_NULL_DATAPTR)
552 continue;
553 /*
554 * Get pointer to the entry from the leaf.
555 */
556 dep = (xfs_dir2_data_entry_t *)
557 ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, addr));
558 /*
559 * Compare, if it's right give back buffer & entry number.
560 */
561 if (dep->namelen == args->namelen &&
562 dep->name[0] == args->name[0] &&
32181a02 563 memcmp(dep->name, args->name, args->namelen) == 0) {
2bd0ea18
NS
564 *bpp = bp;
565 *entno = mid;
566 return 0;
567 }
568 } while (++mid < INT_GET(btp->count, ARCH_CONVERT) && INT_GET(blp[mid].hashval, ARCH_CONVERT) == hash);
569 /*
570 * No match, release the buffer and return ENOENT.
571 */
572 ASSERT(args->oknoent);
573 xfs_da_brelse(tp, bp);
574 return XFS_ERROR(ENOENT);
575}
576
577/*
578 * Remove an entry from a block format directory.
579 * If that makes the block small enough to fit in shortform, transform it.
580 */
581int /* error */
582xfs_dir2_block_removename(
583 xfs_da_args_t *args) /* directory operation args */
584{
585 xfs_dir2_block_t *block; /* block structure */
586 xfs_dir2_leaf_entry_t *blp; /* block leaf pointer */
587 xfs_dabuf_t *bp; /* block buffer */
588 xfs_dir2_block_tail_t *btp; /* block tail */
589 xfs_dir2_data_entry_t *dep; /* block data entry */
590 xfs_inode_t *dp; /* incore inode */
591 int ent; /* block leaf entry index */
592 int error; /* error return value */
593 xfs_mount_t *mp; /* filesystem mount point */
594 int needlog; /* need to log block header */
595 int needscan; /* need to fixup bestfree */
596 xfs_dir2_sf_hdr_t sfh; /* shortform header */
597 int size; /* shortform size */
598 xfs_trans_t *tp; /* transaction pointer */
599
600 xfs_dir2_trace_args("block_removename", args);
601 /*
602 * Look up the entry in the block. Gets the buffer and entry index.
603 * It will always be there, the vnodeops level does a lookup first.
604 */
0e266570 605 if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) {
2bd0ea18
NS
606 return error;
607 }
608 dp = args->dp;
609 tp = args->trans;
610 mp = dp->i_mount;
611 block = bp->data;
612 btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
46eca962 613 blp = XFS_DIR2_BLOCK_LEAF_P(btp);
2bd0ea18
NS
614 /*
615 * Point to the data entry using the leaf entry.
616 */
617 dep = (xfs_dir2_data_entry_t *)
618 ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT)));
619 /*
620 * Mark the data entry's space free.
621 */
622 needlog = needscan = 0;
623 xfs_dir2_data_make_free(tp, bp,
624 (xfs_dir2_data_aoff_t)((char *)dep - (char *)block),
625 XFS_DIR2_DATA_ENTSIZE(dep->namelen), &needlog, &needscan);
626 /*
627 * Fix up the block tail.
628 */
629 INT_MOD(btp->stale, ARCH_CONVERT, +1);
630 xfs_dir2_block_log_tail(tp, bp);
631 /*
632 * Remove the leaf entry by marking it stale.
633 */
634 INT_SET(blp[ent].address, ARCH_CONVERT, XFS_DIR2_NULL_DATAPTR);
635 xfs_dir2_block_log_leaf(tp, bp, ent, ent);
636 /*
637 * Fix up bestfree, log the header if necessary.
638 */
639 if (needscan)
640 xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
641 NULL);
642 if (needlog)
643 xfs_dir2_data_log_header(tp, bp);
644 xfs_dir2_data_check(dp, bp);
645 /*
646 * See if the size as a shortform is good enough.
647 */
648 if ((size = xfs_dir2_block_sfsize(dp, block, &sfh)) >
649 XFS_IFORK_DSIZE(dp)) {
650 xfs_da_buf_done(bp);
651 return 0;
652 }
653 /*
654 * If it works, do the conversion.
655 */
656 return xfs_dir2_block_to_sf(args, bp, size, &sfh);
657}
658
659/*
660 * Replace an entry in a V2 block directory.
661 * Change the inode number to the new value.
662 */
663int /* error */
664xfs_dir2_block_replace(
665 xfs_da_args_t *args) /* directory operation args */
666{
667 xfs_dir2_block_t *block; /* block structure */
668 xfs_dir2_leaf_entry_t *blp; /* block leaf entries */
669 xfs_dabuf_t *bp; /* block buffer */
670 xfs_dir2_block_tail_t *btp; /* block tail */
671 xfs_dir2_data_entry_t *dep; /* block data entry */
672 xfs_inode_t *dp; /* incore inode */
673 int ent; /* leaf entry index */
674 int error; /* error return value */
675 xfs_mount_t *mp; /* filesystem mount point */
676
677 xfs_dir2_trace_args("block_replace", args);
678 /*
679 * Lookup the entry in the directory. Get buffer and entry index.
680 * This will always succeed since the caller has already done a lookup.
681 */
0e266570 682 if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) {
2bd0ea18
NS
683 return error;
684 }
685 dp = args->dp;
686 mp = dp->i_mount;
687 block = bp->data;
688 btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
46eca962 689 blp = XFS_DIR2_BLOCK_LEAF_P(btp);
2bd0ea18
NS
690 /*
691 * Point to the data entry we need to change.
692 */
693 dep = (xfs_dir2_data_entry_t *)
694 ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, INT_GET(blp[ent].address, ARCH_CONVERT)));
695 ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) != args->inumber);
696 /*
697 * Change the inode number to the new value.
698 */
699 INT_SET(dep->inumber, ARCH_CONVERT, args->inumber);
700 xfs_dir2_data_log_entry(args->trans, bp, dep);
701 xfs_dir2_data_check(dp, bp);
702 xfs_da_buf_done(bp);
703 return 0;
704}
705
706/*
707 * Qsort comparison routine for the block leaf entries.
708 */
709static int /* sort order */
710xfs_dir2_block_sort(
711 const void *a, /* first leaf entry */
712 const void *b) /* second leaf entry */
713{
714 const xfs_dir2_leaf_entry_t *la; /* first leaf entry */
715 const xfs_dir2_leaf_entry_t *lb; /* second leaf entry */
716
717 la = a;
718 lb = b;
719 return INT_GET(la->hashval, ARCH_CONVERT) < INT_GET(lb->hashval, ARCH_CONVERT) ? -1 :
720 (INT_GET(la->hashval, ARCH_CONVERT) > INT_GET(lb->hashval, ARCH_CONVERT) ? 1 : 0);
721}
722
723/*
724 * Convert a V2 leaf directory to a V2 block directory if possible.
725 */
726int /* error */
727xfs_dir2_leaf_to_block(
728 xfs_da_args_t *args, /* operation arguments */
729 xfs_dabuf_t *lbp, /* leaf buffer */
730 xfs_dabuf_t *dbp) /* data buffer */
731{
732 xfs_dir2_data_off_t *bestsp; /* leaf bests table */
733 xfs_dir2_block_t *block; /* block structure */
734 xfs_dir2_block_tail_t *btp; /* block tail */
735 xfs_inode_t *dp; /* incore directory inode */
736 xfs_dir2_data_unused_t *dup; /* unused data entry */
737 int error; /* error return value */
738 int from; /* leaf from index */
739 xfs_dir2_leaf_t *leaf; /* leaf structure */
740 xfs_dir2_leaf_entry_t *lep; /* leaf entry */
741 xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */
742 xfs_mount_t *mp; /* file system mount point */
743 int needlog; /* need to log data header */
744 int needscan; /* need to scan for bestfree */
745 xfs_dir2_sf_hdr_t sfh; /* shortform header */
746 int size; /* bytes used */
747 xfs_dir2_data_off_t *tagp; /* end of entry (tag) */
748 int to; /* block/leaf to index */
749 xfs_trans_t *tp; /* transaction pointer */
750
751 xfs_dir2_trace_args_bb("leaf_to_block", args, lbp, dbp);
752 dp = args->dp;
753 tp = args->trans;
754 mp = dp->i_mount;
755 leaf = lbp->data;
756 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAF1_MAGIC);
757 ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
758 /*
759 * If there are data blocks other than the first one, take this
760 * opportunity to remove trailing empty data blocks that may have
761 * been left behind during no-space-reservation operations.
762 * These will show up in the leaf bests table.
763 */
764 while (dp->i_d.di_size > mp->m_dirblksize) {
46eca962 765 bestsp = XFS_DIR2_LEAF_BESTS_P(ltp);
2bd0ea18
NS
766 if (INT_GET(bestsp[INT_GET(ltp->bestcount, ARCH_CONVERT) - 1], ARCH_CONVERT) ==
767 mp->m_dirblksize - (uint)sizeof(block->hdr)) {
0e266570 768 if ((error =
2bd0ea18 769 xfs_dir2_leaf_trim_data(args, lbp,
0e266570 770 (xfs_dir2_db_t)(INT_GET(ltp->bestcount, ARCH_CONVERT) - 1))))
2bd0ea18
NS
771 goto out;
772 } else {
773 error = 0;
774 goto out;
775 }
776 }
777 /*
778 * Read the data block if we don't already have it, give up if it fails.
779 */
780 if (dbp == NULL &&
781 (error = xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &dbp,
782 XFS_DATA_FORK))) {
2bd0ea18
NS
783 goto out;
784 }
785 block = dbp->data;
786 ASSERT(INT_GET(block->hdr.magic, ARCH_CONVERT) == XFS_DIR2_DATA_MAGIC);
787 /*
788 * Size of the "leaf" area in the block.
789 */
790 size = (uint)sizeof(block->tail) +
791 (uint)sizeof(*lep) * (INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT));
792 /*
793 * Look at the last data entry.
794 */
795 tagp = (xfs_dir2_data_off_t *)((char *)block + mp->m_dirblksize) - 1;
796 dup = (xfs_dir2_data_unused_t *)((char *)block + INT_GET(*tagp, ARCH_CONVERT));
797 /*
798 * If it's not free or is too short we can't do it.
799 */
800 if (INT_GET(dup->freetag, ARCH_CONVERT) != XFS_DIR2_DATA_FREE_TAG || INT_GET(dup->length, ARCH_CONVERT) < size) {
801 error = 0;
802 goto out;
803 }
804 /*
805 * Start converting it to block form.
806 */
807 INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_BLOCK_MAGIC);
808 needlog = 1;
809 needscan = 0;
810 /*
811 * Use up the space at the end of the block (blp/btp).
812 */
813 xfs_dir2_data_use_free(tp, dbp, dup, mp->m_dirblksize - size, size,
814 &needlog, &needscan);
815 /*
816 * Initialize the block tail.
817 */
818 btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
819 INT_SET(btp->count, ARCH_CONVERT, INT_GET(leaf->hdr.count, ARCH_CONVERT) - INT_GET(leaf->hdr.stale, ARCH_CONVERT));
46eca962 820 btp->stale = 0;
2bd0ea18
NS
821 xfs_dir2_block_log_tail(tp, dbp);
822 /*
823 * Initialize the block leaf area. We compact out stale entries.
824 */
46eca962 825 lep = XFS_DIR2_BLOCK_LEAF_P(btp);
2bd0ea18
NS
826 for (from = to = 0; from < INT_GET(leaf->hdr.count, ARCH_CONVERT); from++) {
827 if (INT_GET(leaf->ents[from].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR)
828 continue;
829 lep[to++] = leaf->ents[from];
830 }
831 ASSERT(to == INT_GET(btp->count, ARCH_CONVERT));
832 xfs_dir2_block_log_leaf(tp, dbp, 0, INT_GET(btp->count, ARCH_CONVERT) - 1);
833 /*
834 * Scan the bestfree if we need it and log the data block header.
835 */
836 if (needscan)
837 xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog,
838 NULL);
839 if (needlog)
840 xfs_dir2_data_log_header(tp, dbp);
841 /*
842 * Pitch the old leaf block.
843 */
844 error = xfs_da_shrink_inode(args, mp->m_dirleafblk, lbp);
845 lbp = NULL;
846 if (error) {
2bd0ea18
NS
847 goto out;
848 }
849 /*
850 * Now see if the resulting block can be shrunken to shortform.
851 */
852 if ((size = xfs_dir2_block_sfsize(dp, block, &sfh)) >
853 XFS_IFORK_DSIZE(dp)) {
854 error = 0;
855 goto out;
856 }
857 return xfs_dir2_block_to_sf(args, dbp, size, &sfh);
858out:
859 if (lbp)
860 xfs_da_buf_done(lbp);
861 if (dbp)
862 xfs_da_buf_done(dbp);
863 return error;
864}
865
866/*
867 * Convert the shortform directory to block form.
868 */
869int /* error */
870xfs_dir2_sf_to_block(
871 xfs_da_args_t *args) /* operation arguments */
872{
873 xfs_dir2_db_t blkno; /* dir-relative block # (0) */
874 xfs_dir2_block_t *block; /* block structure */
875 xfs_dir2_leaf_entry_t *blp; /* block leaf entries */
876 xfs_dabuf_t *bp; /* block buffer */
877 xfs_dir2_block_tail_t *btp; /* block tail pointer */
d663096d
SL
878 char *buf; /* sf buffer */
879 int buf_len;
2bd0ea18
NS
880 xfs_dir2_data_entry_t *dep; /* data entry pointer */
881 xfs_inode_t *dp; /* incore directory inode */
882 int dummy; /* trash */
883 xfs_dir2_data_unused_t *dup; /* unused entry pointer */
884 int endoffset; /* end of data objects */
885 int error; /* error return value */
886 int i; /* index */
887 xfs_mount_t *mp; /* filesystem mount point */
888 int needlog; /* need to log block header */
889 int needscan; /* need to scan block freespc */
890 int newoffset; /* offset from current entry */
891 int offset; /* target block offset */
892 xfs_dir2_sf_entry_t *sfep; /* sf entry pointer */
893 xfs_dir2_sf_t *sfp; /* shortform structure */
894 xfs_dir2_data_off_t *tagp; /* end of data entry */
895 xfs_trans_t *tp; /* transaction pointer */
896
897 xfs_dir2_trace_args("sf_to_block", args);
898 dp = args->dp;
899 tp = args->trans;
900 mp = dp->i_mount;
901 ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
902 /*
903 * Bomb out if the shortform directory is way too short.
904 */
905 if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
2bd0ea18
NS
906 ASSERT(XFS_FORCED_SHUTDOWN(mp));
907 return XFS_ERROR(EIO);
908 }
909 ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
910 ASSERT(dp->i_df.if_u1.if_data != NULL);
911 sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
912 ASSERT(dp->i_d.di_size >= XFS_DIR2_SF_HDR_SIZE(sfp->hdr.i8count));
913 /*
914 * Copy the directory into the stack buffer.
915 * Then pitch the incore inode data so we can make extents.
916 */
d663096d
SL
917
918 buf_len = dp->i_df.if_bytes;
919 buf = kmem_alloc(dp->i_df.if_bytes, KM_SLEEP);
920
32181a02 921 memcpy(buf, sfp, dp->i_df.if_bytes);
2bd0ea18
NS
922 xfs_idata_realloc(dp, -dp->i_df.if_bytes, XFS_DATA_FORK);
923 dp->i_d.di_size = 0;
924 xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
925 /*
926 * Reset pointer - old sfp is gone.
927 */
928 sfp = (xfs_dir2_sf_t *)buf;
929 /*
930 * Add block 0 to the inode.
931 */
932 error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno);
933 if (error) {
d663096d 934 kmem_free(buf, buf_len);
2bd0ea18
NS
935 return error;
936 }
937 /*
938 * Initialize the data block.
939 */
940 error = xfs_dir2_data_init(args, blkno, &bp);
941 if (error) {
d663096d 942 kmem_free(buf, buf_len);
2bd0ea18
NS
943 return error;
944 }
945 block = bp->data;
946 INT_SET(block->hdr.magic, ARCH_CONVERT, XFS_DIR2_BLOCK_MAGIC);
947 /*
948 * Compute size of block "tail" area.
949 */
950 i = (uint)sizeof(*btp) +
951 (INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t);
952 /*
953 * The whole thing is initialized to free by the init routine.
954 * Say we're using the leaf and tail area.
955 */
956 dup = (xfs_dir2_data_unused_t *)block->u;
957 needlog = needscan = 0;
958 xfs_dir2_data_use_free(tp, bp, dup, mp->m_dirblksize - i, i, &needlog,
959 &needscan);
960 ASSERT(needscan == 0);
961 /*
962 * Fill in the tail.
963 */
964 btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
965 INT_SET(btp->count, ARCH_CONVERT, INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2); /* ., .. */
46eca962
NS
966 btp->stale = 0;
967 blp = XFS_DIR2_BLOCK_LEAF_P(btp);
2bd0ea18
NS
968 endoffset = (uint)((char *)blp - (char *)block);
969 /*
970 * Remove the freespace, we'll manage it.
971 */
972 xfs_dir2_data_use_free(tp, bp, dup,
973 (xfs_dir2_data_aoff_t)((char *)dup - (char *)block),
974 INT_GET(dup->length, ARCH_CONVERT), &needlog, &needscan);
975 /*
976 * Create entry for .
977 */
978 dep = (xfs_dir2_data_entry_t *)
979 ((char *)block + XFS_DIR2_DATA_DOT_OFFSET);
980 INT_SET(dep->inumber, ARCH_CONVERT, dp->i_ino);
981 dep->namelen = 1;
982 dep->name[0] = '.';
983 tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
984 INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
985 xfs_dir2_data_log_entry(tp, bp, dep);
986 INT_SET(blp[0].hashval, ARCH_CONVERT, xfs_dir_hash_dot);
987 INT_SET(blp[0].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block));
988 /*
989 * Create entry for ..
990 */
991 dep = (xfs_dir2_data_entry_t *)
992 ((char *)block + XFS_DIR2_DATA_DOTDOT_OFFSET);
46eca962 993 INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent));
2bd0ea18
NS
994 dep->namelen = 2;
995 dep->name[0] = dep->name[1] = '.';
996 tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
997 INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
998 xfs_dir2_data_log_entry(tp, bp, dep);
999 INT_SET(blp[1].hashval, ARCH_CONVERT, xfs_dir_hash_dotdot);
1000 INT_SET(blp[1].address, ARCH_CONVERT, XFS_DIR2_BYTE_TO_DATAPTR(mp, (char *)dep - (char *)block));
1001 offset = XFS_DIR2_DATA_FIRST_OFFSET;
1002 /*
1003 * Loop over existing entries, stuff them in.
1004 */
1005 if ((i = 0) == INT_GET(sfp->hdr.count, ARCH_CONVERT))
1006 sfep = NULL;
1007 else
1008 sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
1009 /*
1010 * Need to preserve the existing offset values in the sf directory.
1011 * Insert holes (unused entries) where necessary.
1012 */
1013 while (offset < endoffset) {
1014 /*
1015 * sfep is null when we reach the end of the list.
1016 */
1017 if (sfep == NULL)
1018 newoffset = endoffset;
1019 else
46eca962 1020 newoffset = XFS_DIR2_SF_GET_OFFSET(sfep);
2bd0ea18
NS
1021 /*
1022 * There should be a hole here, make one.
1023 */
1024 if (offset < newoffset) {
1025 dup = (xfs_dir2_data_unused_t *)
1026 ((char *)block + offset);
1027 INT_SET(dup->freetag, ARCH_CONVERT, XFS_DIR2_DATA_FREE_TAG);
1028 INT_SET(dup->length, ARCH_CONVERT, newoffset - offset);
46eca962 1029 INT_SET(*XFS_DIR2_DATA_UNUSED_TAG_P(dup), ARCH_CONVERT,
2bd0ea18
NS
1030 (xfs_dir2_data_off_t)
1031 ((char *)dup - (char *)block));
1032 xfs_dir2_data_log_unused(tp, bp, dup);
1033 (void)xfs_dir2_data_freeinsert((xfs_dir2_data_t *)block,
1034 dup, &dummy);
1035 offset += INT_GET(dup->length, ARCH_CONVERT);
1036 continue;
1037 }
1038 /*
1039 * Copy a real entry.
1040 */
1041 dep = (xfs_dir2_data_entry_t *)((char *)block + newoffset);
46eca962
NS
1042 INT_SET(dep->inumber, ARCH_CONVERT, XFS_DIR2_SF_GET_INUMBER(sfp,
1043 XFS_DIR2_SF_INUMBERP(sfep)));
2bd0ea18 1044 dep->namelen = sfep->namelen;
32181a02 1045 memcpy(dep->name, sfep->name, dep->namelen);
2bd0ea18
NS
1046 tagp = XFS_DIR2_DATA_ENTRY_TAG_P(dep);
1047 INT_SET(*tagp, ARCH_CONVERT, (xfs_dir2_data_off_t)((char *)dep - (char *)block));
1048 xfs_dir2_data_log_entry(tp, bp, dep);
51ca7008
BN
1049 blp[2 + i].hashval = cpu_to_be32(mp->m_dirnameops->hashname(
1050 sfep->name, sfep->namelen));
1051 blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
2bd0ea18
NS
1052 (char *)dep - (char *)block));
1053 offset = (int)((char *)(tagp + 1) - (char *)block);
1054 if (++i == INT_GET(sfp->hdr.count, ARCH_CONVERT))
1055 sfep = NULL;
1056 else
1057 sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
1058 }
d663096d
SL
1059 /* Done with the temporary buffer */
1060 kmem_free(buf, buf_len);
2bd0ea18
NS
1061 /*
1062 * Sort the leaf entries by hash value.
1063 */
6239071d 1064 xfs_sort(blp, INT_GET(btp->count, ARCH_CONVERT), sizeof(*blp), xfs_dir2_block_sort);
5000d01d 1065 /*
2bd0ea18
NS
1066 * Log the leaf entry area and tail.
1067 * Already logged the header in data_init, ignore needlog.
1068 */
1069 ASSERT(needscan == 0);
1070 xfs_dir2_block_log_leaf(tp, bp, 0, INT_GET(btp->count, ARCH_CONVERT) - 1);
1071 xfs_dir2_block_log_tail(tp, bp);
1072 xfs_dir2_data_check(dp, bp);
1073 xfs_da_buf_done(bp);
1074 return 0;
1075}