]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/dir2.c
Minor fix up in xfs_db man page
[thirdparty/xfsprogs-dev.git] / repair / dir2.c
CommitLineData
2bd0ea18 1/*
da23017d
NS
2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
dfc130f3 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.
dfc130f3 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.
dfc130f3 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#include <libxfs.h>
20#include "avl.h"
21#include "globals.h"
22#include "incore.h"
23#include "err_protos.h"
24#include "dinode.h"
25#include "dir.h"
26#include "dir2.h"
27#include "bmap.h"
cb5b3ef4 28#include "prefetch.h"
2556c98b 29#include "progress.h"
2bd0ea18
NS
30
31/*
32 * Tag bad directory entries with this.
dfc130f3 33 * We can't tag them with -1 since that will look like a
2bd0ea18
NS
34 * data_unused_t instead of a data_entry_t.
35 */
36#define BADFSINO ((xfs_ino_t)0xfeffffffffffffffULL)
37
38/*
39 * Known bad inode list. These are seen when the leaf and node
40 * block linkages are incorrect.
41 */
42typedef struct dir2_bad {
43 xfs_ino_t ino;
44 struct dir2_bad *next;
45} dir2_bad_t;
46dir2_bad_t *dir2_bad_list;
47
48void
49dir2_add_badlist(
50 xfs_ino_t ino)
51{
52 dir2_bad_t *l;
53
54 if ((l = malloc(sizeof(dir2_bad_t))) == NULL) {
507f4e33
NS
55 do_error(
56 _("malloc failed (%u bytes) dir2_add_badlist:ino %llu\n"),
2bd0ea18
NS
57 sizeof(dir2_bad_t), ino);
58 exit(1);
59 }
60 l->next = dir2_bad_list;
61 dir2_bad_list = l;
62 l->ino = ino;
63}
64
65int
66dir2_is_badino(
67 xfs_ino_t ino)
68{
69 dir2_bad_t *l;
70
71 for (l = dir2_bad_list; l; l = l->next)
72 if (l->ino == ino)
73 return 1;
74 return 0;
75}
76
77/*
78 * Multibuffer handling.
79 * V2 directory blocks can be noncontiguous, needing multiple buffers.
80 */
81xfs_dabuf_t *
82da_read_buf(
83 xfs_mount_t *mp,
84 int nex,
85 bmap_ext_t *bmp)
86{
87 xfs_buf_t *bp;
1e77098c 88 xfs_buf_t *bparray[4];
2bd0ea18
NS
89 xfs_buf_t **bplist;
90 xfs_dabuf_t *dabuf;
f8bc5a6f 91 int i;
2bd0ea18
NS
92 int off;
93
f8bc5a6f 94 if (nex > (sizeof(bparray)/sizeof(xfs_buf_t *))) {
1e77098c
MV
95 bplist = calloc(nex, sizeof(*bplist));
96 if (bplist == NULL) {
97 do_error(_("couldn't malloc dir2 buffer list\n"));
98 exit(1);
99 }
100 }
101 else {
102 /* common case avoids calloc/free */
103 bplist = bparray;
2bd0ea18 104 }
f8bc5a6f 105 for (i = 0; i < nex; i++) {
2556c98b 106#ifdef XR_PF_TRACE
f8bc5a6f
BN
107 pftrace("about to read off %llu (len = %d)",
108 (long long)XFS_FSB_TO_DADDR(mp, bmp[i].startblock),
109 XFS_FSB_TO_BB(mp, bmp[i].blockcount));
2556c98b 110#endif
f8bc5a6f
BN
111 bplist[i] = libxfs_readbuf(mp->m_dev,
112 XFS_FSB_TO_DADDR(mp, bmp[i].startblock),
113 XFS_FSB_TO_BB(mp, bmp[i].blockcount), 0);
114 if (!bplist[i])
115 goto failed;
2556c98b 116#ifdef XR_PF_TRACE
f8bc5a6f
BN
117 pftrace("readbuf %p (%llu, %d)", bplist[i],
118 (long long)XFS_BUF_ADDR(bplist[i]),
119 XFS_BUF_COUNT(bplist[i]));
2556c98b 120#endif
2bd0ea18 121 }
f8bc5a6f 122 dabuf = malloc(XFS_DA_BUF_SIZE(nex));
2bd0ea18 123 if (dabuf == NULL) {
507f4e33 124 do_error(_("couldn't malloc dir2 buffer header\n"));
2bd0ea18
NS
125 exit(1);
126 }
127 dabuf->dirty = 0;
128 dabuf->nbuf = nex;
f8bc5a6f 129 if (nex == 1) {
2bd0ea18
NS
130 bp = bplist[0];
131 dabuf->bbcount = (short)BTOBB(XFS_BUF_COUNT(bp));
132 dabuf->data = XFS_BUF_PTR(bp);
133 dabuf->bps[0] = bp;
134 } else {
135 for (i = 0, dabuf->bbcount = 0; i < nex; i++) {
136 dabuf->bps[i] = bp = bplist[i];
137 dabuf->bbcount += BTOBB(XFS_BUF_COUNT(bp));
138 }
139 dabuf->data = malloc(BBTOB(dabuf->bbcount));
140 if (dabuf->data == NULL) {
507f4e33 141 do_error(_("couldn't malloc dir2 buffer data\n"));
2bd0ea18
NS
142 exit(1);
143 }
f8bc5a6f 144 for (i = off = 0; i < nex; i++, off += XFS_BUF_COUNT(bp)) {
2bd0ea18
NS
145 bp = bplist[i];
146 bcopy(XFS_BUF_PTR(bp), (char *)dabuf->data + off,
147 XFS_BUF_COUNT(bp));
148 }
149 }
1e77098c
MV
150 if (bplist != bparray)
151 free(bplist);
2bd0ea18
NS
152 return dabuf;
153failed:
f8bc5a6f 154 for (i = 0; i < nex; i++)
2bd0ea18 155 libxfs_putbuf(bplist[i]);
1e77098c
MV
156 if (bplist != bparray)
157 free(bplist);
2bd0ea18
NS
158 return NULL;
159}
160
161static void
162da_buf_clean(
163 xfs_dabuf_t *dabuf)
164{
165 xfs_buf_t *bp;
166 int i;
167 int off;
168
169 if (dabuf->dirty) {
170 dabuf->dirty = 0;
171 for (i=off=0; i < dabuf->nbuf; i++, off += XFS_BUF_COUNT(bp)) {
172 bp = dabuf->bps[i];
173 bcopy((char *)dabuf->data + off, XFS_BUF_PTR(bp),
174 XFS_BUF_COUNT(bp));
175 }
176 }
177}
178
179static void
180da_buf_done(
181 xfs_dabuf_t *dabuf)
182{
183 da_buf_clean(dabuf);
184 if (dabuf->nbuf > 1)
185 free(dabuf->data);
186 free(dabuf);
187}
188
189int
190da_bwrite(
191 xfs_mount_t *mp,
192 xfs_dabuf_t *dabuf)
193{
194 xfs_buf_t *bp;
195 xfs_buf_t **bplist;
196 int e;
197 int error;
198 int i;
199 int nbuf;
01f8bdf6 200 int off;
2bd0ea18
NS
201
202 if ((nbuf = dabuf->nbuf) == 1) {
203 bplist = &bp;
204 bp = dabuf->bps[0];
205 } else {
206 bplist = malloc(nbuf * sizeof(*bplist));
207 if (bplist == NULL) {
507f4e33 208 do_error(_("couldn't malloc dir2 buffer list\n"));
2bd0ea18
NS
209 exit(1);
210 }
211 bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist));
01f8bdf6
NS
212 for (i = off = 0; i < nbuf; i++, off += XFS_BUF_COUNT(bp)) {
213 bp = bplist[i];
214 bcopy((char *)dabuf->data + off, XFS_BUF_PTR(bp),
215 XFS_BUF_COUNT(bp));
216 }
2bd0ea18
NS
217 }
218 da_buf_done(dabuf);
219 for (i = error = 0; i < nbuf; i++) {
220 e = libxfs_writebuf(bplist[i], 0);
221 if (e)
222 error = e;
223 }
224 if (bplist != &bp)
225 free(bplist);
226 return error;
227}
228
229void
230da_brelse(
231 xfs_dabuf_t *dabuf)
232{
233 xfs_buf_t *bp;
234 xfs_buf_t **bplist;
235 int i;
236 int nbuf;
237
238 if ((nbuf = dabuf->nbuf) == 1) {
239 bplist = &bp;
240 bp = dabuf->bps[0];
241 } else {
242 bplist = malloc(nbuf * sizeof(*bplist));
243 if (bplist == NULL) {
507f4e33 244 do_error(_("couldn't malloc dir2 buffer list\n"));
2bd0ea18
NS
245 exit(1);
246 }
247 bcopy(dabuf->bps, bplist, nbuf * sizeof(*bplist));
248 }
249 da_buf_done(dabuf);
2556c98b
BN
250 for (i = 0; i < nbuf; i++) {
251#ifdef XR_PF_TRACE
252 pftrace("putbuf %p (%llu)", bplist[i], (long long)XFS_BUF_ADDR(bplist[i]));
253#endif
2bd0ea18 254 libxfs_putbuf(bplist[i]);
2556c98b 255 }
2bd0ea18
NS
256 if (bplist != &bp)
257 free(bplist);
258}
259
260/*
261 * walk tree from root to the left-most leaf block reading in
262 * blocks and setting up cursor. passes back file block number of the
263 * left-most leaf block if successful (bno). returns 1 if successful,
264 * 0 if unsuccessful.
265 */
266int
267traverse_int_dir2block(xfs_mount_t *mp,
268 dir2_bt_cursor_t *da_cursor,
269 xfs_dablk_t *rbno)
270{
271 bmap_ext_t *bmp;
272 xfs_dablk_t bno;
273 xfs_dabuf_t *bp;
274 int i;
275 int nex;
4f336d89 276 xfs_da_blkinfo_t *info;
2bd0ea18 277 xfs_da_intnode_t *node;
1e77098c 278 bmap_ext_t lbmp;
2bd0ea18
NS
279
280 /*
281 * traverse down left-side of tree until we hit the
282 * left-most leaf block setting up the btree cursor along
283 * the way.
284 */
285 bno = mp->m_dirleafblk;
286 i = -1;
4f336d89 287 info = NULL;
2bd0ea18
NS
288 da_cursor->active = 0;
289
290 do {
291 /*
292 * read in each block along the way and set up cursor
293 */
294 nex = blkmap_getn(da_cursor->blkmap, bno, mp->m_dirblkfsbs,
1e77098c 295 &bmp, &lbmp);
2bd0ea18
NS
296
297 if (nex == 0)
298 goto error_out;
299
300 bp = da_read_buf(mp, nex, bmp);
1e77098c
MV
301 if (bmp != &lbmp)
302 free(bmp);
2bd0ea18 303 if (bp == NULL) {
507f4e33
NS
304 do_warn(_("can't read block %u for directory inode "
305 "%llu\n"),
2bd0ea18
NS
306 bno, da_cursor->ino);
307 goto error_out;
308 }
309
4f336d89 310 info = bp->data;
2bd0ea18 311
4f336d89 312 if (INT_GET(info->magic, ARCH_CONVERT) ==
2bd0ea18
NS
313 XFS_DIR2_LEAFN_MAGIC) {
314 if ( i != -1 ) {
507f4e33
NS
315 do_warn(_("found non-root LEAFN node in inode "
316 "%llu bno = %u\n"),
2bd0ea18
NS
317 da_cursor->ino, bno);
318 }
2bd0ea18
NS
319 *rbno = 0;
320 da_brelse(bp);
321 return(1);
4f336d89 322 } else if (INT_GET(info->magic, ARCH_CONVERT) !=
2bd0ea18
NS
323 XFS_DA_NODE_MAGIC) {
324 da_brelse(bp);
507f4e33
NS
325 do_warn(_("bad dir magic number 0x%x in inode %llu "
326 "bno = %u\n"),
4f336d89 327 INT_GET(info->magic, ARCH_CONVERT),
2bd0ea18
NS
328 da_cursor->ino, bno);
329 goto error_out;
330 }
4f336d89 331 node = (xfs_da_intnode_t*)info;
2bd0ea18 332 if (INT_GET(node->hdr.count, ARCH_CONVERT) >
6bef826c 333 mp->m_dir_node_ents) {
2bd0ea18 334 da_brelse(bp);
507f4e33
NS
335 do_warn(_("bad record count in inode %llu, count = %d, "
336 "max = %d\n"), da_cursor->ino,
2bd0ea18 337 INT_GET(node->hdr.count, ARCH_CONVERT),
6bef826c 338 mp->m_dir_node_ents);
2bd0ea18
NS
339 goto error_out;
340 }
2bd0ea18
NS
341 /*
342 * maintain level counter
343 */
344 if (i == -1)
345 i = da_cursor->active =
346 INT_GET(node->hdr.level, ARCH_CONVERT);
347 else {
348 if (INT_GET(node->hdr.level, ARCH_CONVERT) == i - 1) {
349 i--;
350 } else {
507f4e33
NS
351 do_warn(_("bad directory btree for directory "
352 "inode %llu\n"),
2bd0ea18
NS
353 da_cursor->ino);
354 da_brelse(bp);
355 goto error_out;
356 }
357 }
358
359 da_cursor->level[i].hashval =
360 INT_GET(node->btree[0].hashval, ARCH_CONVERT);
361 da_cursor->level[i].bp = bp;
362 da_cursor->level[i].bno = bno;
363 da_cursor->level[i].index = 0;
364
365 /*
366 * set up new bno for next level down
367 */
368 bno = INT_GET(node->btree[0].before, ARCH_CONVERT);
4f336d89 369 } while (info != NULL && i > 1);
2bd0ea18
NS
370
371 /*
372 * now return block number and get out
373 */
374 *rbno = da_cursor->level[0].bno = bno;
375 return(1);
376
377error_out:
378 while (i > 1 && i <= da_cursor->active) {
379 da_brelse(da_cursor->level[i].bp);
380 i++;
381 }
382
383 return(0);
384}
385
386/*
387 * blow out buffer for this level and all the rest above as well
388 * if error == 0, we are not expecting to encounter any unreleased
389 * buffers (e.g. if we do, it's a mistake). if error == 1, we're
390 * in an error-handling case so unreleased buffers may exist.
391 */
392void
393release_dir2_cursor_int(xfs_mount_t *mp,
394 dir2_bt_cursor_t *cursor,
395 int prev_level,
396 int error)
397{
398 int level = prev_level + 1;
399
400 if (cursor->level[level].bp != NULL) {
401 if (!error) {
507f4e33
NS
402 do_warn(_("release_dir2_cursor_int got unexpected "
403 "non-null bp, dabno = %u\n"),
2bd0ea18
NS
404 cursor->level[level].bno);
405 }
406 ASSERT(error != 0);
407
408 da_brelse(cursor->level[level].bp);
409 cursor->level[level].bp = NULL;
410 }
411
412 if (level < cursor->active)
413 release_dir2_cursor_int(mp, cursor, level, error);
414
415 return;
416}
417
418void
419release_dir2_cursor(xfs_mount_t *mp,
420 dir2_bt_cursor_t *cursor,
421 int prev_level)
422{
423 release_dir2_cursor_int(mp, cursor, prev_level, 0);
424}
425
426void
427err_release_dir2_cursor(xfs_mount_t *mp,
428 dir2_bt_cursor_t *cursor,
429 int prev_level)
430{
431 release_dir2_cursor_int(mp, cursor, prev_level, 1);
432}
433
434/*
435 * make sure that all entries in all blocks along the right side of
436 * of the tree are used and hashval's are consistent. level is the
437 * level of the descendent block. returns 0 if good (even if it had
438 * to be fixed up), and 1 if bad. The right edge of the tree is
439 * technically a block boundary. This routine should be used then
440 * instead of verify_dir2_path().
441 */
442int
443verify_final_dir2_path(xfs_mount_t *mp,
444 dir2_bt_cursor_t *cursor,
445 const int p_level)
446{
447 xfs_da_intnode_t *node;
448 int bad = 0;
449 int entry;
450 int this_level = p_level + 1;
451
452 /*
453 * the index should point to the next "unprocessed" entry
454 * in the block which should be the final (rightmost) entry
455 */
456 entry = cursor->level[this_level].index;
457 node = (xfs_da_intnode_t *)(cursor->level[this_level].bp->data);
458 /*
459 * check internal block consistency on this level -- ensure
460 * that all entries are used, encountered and expected hashvals
461 * match, etc.
462 */
463 if (entry != INT_GET(node->hdr.count, ARCH_CONVERT) - 1) {
507f4e33
NS
464 do_warn(
465 _("directory block used/count inconsistency - %d / %hu\n"),
2bd0ea18
NS
466 entry, INT_GET(node->hdr.count, ARCH_CONVERT));
467 bad++;
468 }
469 /*
470 * hash values monotonically increasing ???
471 */
507f4e33
NS
472 if (cursor->level[this_level].hashval >=
473 INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) {
474 do_warn(_("directory/attribute block hashvalue inconsistency, "
475 "expected > %u / saw %u\n"),
2bd0ea18
NS
476 cursor->level[this_level].hashval,
477 INT_GET(node->btree[entry].hashval, ARCH_CONVERT));
478 bad++;
479 }
480 if (INT_GET(node->hdr.info.forw, ARCH_CONVERT) != 0) {
507f4e33
NS
481 do_warn(_("bad directory/attribute forward block pointer, "
482 "expected 0, saw %u\n"),
2bd0ea18
NS
483 INT_GET(node->hdr.info.forw, ARCH_CONVERT));
484 bad++;
485 }
486 if (bad) {
507f4e33 487 do_warn(_("bad directory block in inode %llu\n"), cursor->ino);
2bd0ea18
NS
488 return(1);
489 }
490 /*
491 * keep track of greatest block # -- that gets
492 * us the length of the directory
493 */
494 if (cursor->level[this_level].bno > cursor->greatest_bno)
495 cursor->greatest_bno = cursor->level[this_level].bno;
496
497 /*
498 * ok, now check descendant block number against this level
499 */
507f4e33
NS
500 if (cursor->level[p_level].bno !=
501 INT_GET(node->btree[entry].before, ARCH_CONVERT)) {
2bd0ea18
NS
502 return(1);
503 }
504
507f4e33
NS
505 if (cursor->level[p_level].hashval !=
506 INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) {
2bd0ea18 507 if (!no_modify) {
507f4e33
NS
508 do_warn(_("correcting bad hashval in non-leaf dir "
509 "block\n\tin (level %d) in inode %llu.\n"),
2bd0ea18 510 this_level, cursor->ino);
507f4e33
NS
511 INT_SET(node->btree[entry].hashval, ARCH_CONVERT,
512 cursor->level[p_level].hashval);
2bd0ea18
NS
513 cursor->level[this_level].dirty++;
514 } else {
507f4e33
NS
515 do_warn(_("would correct bad hashval in non-leaf dir "
516 "block\n\tin (level %d) in inode %llu.\n"),
2bd0ea18
NS
517 this_level, cursor->ino);
518 }
519 }
520
521 /*
522 * release/write buffer
523 */
524 ASSERT(cursor->level[this_level].dirty == 0 ||
27527004 525 (cursor->level[this_level].dirty && !no_modify));
2bd0ea18
NS
526
527 if (cursor->level[this_level].dirty && !no_modify)
528 da_bwrite(mp, cursor->level[this_level].bp);
529 else
530 da_brelse(cursor->level[this_level].bp);
531
532 cursor->level[this_level].bp = NULL;
533
534 /*
535 * bail out if this is the root block (top of tree)
536 */
537 if (this_level >= cursor->active) {
538 return(0);
539 }
540 /*
541 * set hashvalue to correctl reflect the now-validated
542 * last entry in this block and continue upwards validation
543 */
507f4e33
NS
544 cursor->level[this_level].hashval =
545 INT_GET(node->btree[entry].hashval, ARCH_CONVERT);
2bd0ea18
NS
546
547 return(verify_final_dir2_path(mp, cursor, this_level));
548}
549
550/*
551 * Verifies the path from a descendant block up to the root.
552 * Should be called when the descendant level traversal hits
553 * a block boundary before crossing the boundary (reading in a new
554 * block).
555 *
556 * the directory/attr btrees work differently to the other fs btrees.
557 * each interior block contains records that are <hashval, bno>
558 * pairs. The bno is a file bno, not a filesystem bno. The last
559 * hashvalue in the block <bno> will be <hashval>. BUT unlike
560 * the freespace btrees, the *last* value in each block gets
561 * propagated up the tree instead of the first value in each block.
562 * that is, the interior records point to child blocks and the *greatest*
563 * hash value contained by the child block is the one the block above
564 * uses as the key for the child block.
565 *
566 * level is the level of the descendent block. returns 0 if good,
567 * and 1 if bad. The descendant block may be a leaf block.
568 *
569 * the invariant here is that the values in the cursor for the
570 * levels beneath this level (this_level) and the cursor index
571 * for this level *must* be valid.
572 *
573 * that is, the hashval/bno info is accurate for all
574 * DESCENDANTS and match what the node[index] information
575 * for the current index in the cursor for this level.
576 *
577 * the index values in the cursor for the descendant level
578 * are allowed to be off by one as they will reflect the
579 * next entry at those levels to be processed.
580 *
581 * the hashvalue for the current level can't be set until
582 * we hit the last entry in the block so, it's garbage
583 * until set by this routine.
584 *
585 * bno and bp for the current block/level are always valid
586 * since they have to be set so we can get a buffer for the
587 * block.
588 */
589int
590verify_dir2_path(xfs_mount_t *mp,
591 dir2_bt_cursor_t *cursor,
592 const int p_level)
593{
594 xfs_da_intnode_t *node;
595 xfs_da_intnode_t *newnode;
596 xfs_dablk_t dabno;
597 xfs_dabuf_t *bp;
598 int bad;
599 int entry;
600 int this_level = p_level + 1;
601 bmap_ext_t *bmp;
602 int nex;
1e77098c 603 bmap_ext_t lbmp;
2bd0ea18
NS
604
605 /*
606 * index is currently set to point to the entry that
607 * should be processed now in this level.
608 */
609 entry = cursor->level[this_level].index;
610 node = cursor->level[this_level].bp->data;
611
612 /*
613 * if this block is out of entries, validate this
614 * block and move on to the next block.
615 * and update cursor value for said level
616 */
617 if (entry >= INT_GET(node->hdr.count, ARCH_CONVERT)) {
618 /*
619 * update the hash value for this level before
620 * validating it. bno value should be ok since
621 * it was set when the block was first read in.
622 */
dfc130f3 623 cursor->level[this_level].hashval =
507f4e33 624 INT_GET(node->btree[entry - 1].hashval, ARCH_CONVERT);
2bd0ea18
NS
625
626 /*
627 * keep track of greatest block # -- that gets
628 * us the length of the directory
629 */
630 if (cursor->level[this_level].bno > cursor->greatest_bno)
631 cursor->greatest_bno = cursor->level[this_level].bno;
632
633 /*
634 * validate the path for the current used-up block
635 * before we trash it
636 */
637 if (verify_dir2_path(mp, cursor, this_level))
638 return(1);
639 /*
640 * ok, now get the next buffer and check sibling pointers
641 */
642 dabno = INT_GET(node->hdr.info.forw, ARCH_CONVERT);
643 ASSERT(dabno != 0);
644 nex = blkmap_getn(cursor->blkmap, dabno, mp->m_dirblkfsbs,
1e77098c 645 &bmp, &lbmp);
2bd0ea18 646 if (nex == 0) {
507f4e33
NS
647 do_warn(_("can't get map info for block %u of "
648 "directory inode %llu\n"),
2bd0ea18
NS
649 dabno, cursor->ino);
650 return(1);
651 }
652
653 bp = da_read_buf(mp, nex, bmp);
1e77098c
MV
654 if (bmp != &lbmp)
655 free(bmp);
2bd0ea18
NS
656
657 if (bp == NULL) {
507f4e33
NS
658 do_warn(_("can't read block %u for directory inode "
659 "%llu\n"),
2bd0ea18
NS
660 dabno, cursor->ino);
661 return(1);
662 }
663
664 newnode = bp->data;
665 /*
666 * verify magic number and back pointer, sanity-check
667 * entry count, verify level
668 */
669 bad = 0;
507f4e33
NS
670 if (XFS_DA_NODE_MAGIC !=
671 INT_GET(newnode->hdr.info.magic, ARCH_CONVERT)) {
672 do_warn(_("bad magic number %x in block %u for "
673 "directory inode %llu\n"),
674 INT_GET(newnode->hdr.info.magic, ARCH_CONVERT),
675 dabno, cursor->ino);
2bd0ea18
NS
676 bad++;
677 }
507f4e33
NS
678 if (INT_GET(newnode->hdr.info.back, ARCH_CONVERT) !=
679 cursor->level[this_level].bno) {
680 do_warn(_("bad back pointer in block %u for directory "
681 "inode %llu\n"),
2bd0ea18
NS
682 dabno, cursor->ino);
683 bad++;
684 }
6bef826c
NS
685 if (INT_GET(newnode->hdr.count, ARCH_CONVERT) >
686 mp->m_dir_node_ents) {
507f4e33
NS
687 do_warn(_("entry count %d too large in block %u for "
688 "directory inode %llu\n"),
689 INT_GET(newnode->hdr.count, ARCH_CONVERT),
690 dabno, cursor->ino);
2bd0ea18
NS
691 bad++;
692 }
693 if (INT_GET(newnode->hdr.level, ARCH_CONVERT) != this_level) {
507f4e33
NS
694 do_warn(_("bad level %d in block %u for directory "
695 "inode %llu\n"),
696 INT_GET(newnode->hdr.level, ARCH_CONVERT),
697 dabno, cursor->ino);
2bd0ea18
NS
698 bad++;
699 }
700 if (bad) {
701 da_brelse(bp);
702 return(1);
703 }
704 /*
705 * update cursor, write out the *current* level if
706 * required. don't write out the descendant level
707 */
708 ASSERT(cursor->level[this_level].dirty == 0 ||
27527004 709 (cursor->level[this_level].dirty && !no_modify));
2bd0ea18
NS
710
711 if (cursor->level[this_level].dirty && !no_modify)
712 da_bwrite(mp, cursor->level[this_level].bp);
713 else
714 da_brelse(cursor->level[this_level].bp);
715 cursor->level[this_level].bp = bp;
716 cursor->level[this_level].dirty = 0;
717 cursor->level[this_level].bno = dabno;
507f4e33
NS
718 cursor->level[this_level].hashval =
719 INT_GET(newnode->btree[0].hashval, ARCH_CONVERT);
2bd0ea18
NS
720 node = newnode;
721
722 entry = cursor->level[this_level].index = 0;
723 }
724 /*
725 * ditto for block numbers
726 */
507f4e33
NS
727 if (cursor->level[p_level].bno !=
728 INT_GET(node->btree[entry].before, ARCH_CONVERT)) {
2bd0ea18
NS
729 return(1);
730 }
731 /*
732 * ok, now validate last hashvalue in the descendant
733 * block against the hashval in the current entry
734 */
507f4e33
NS
735 if (cursor->level[p_level].hashval !=
736 INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) {
2bd0ea18 737 if (!no_modify) {
507f4e33
NS
738 do_warn(_("correcting bad hashval in interior dir "
739 "block\n\tin (level %d) in inode %llu.\n"),
2bd0ea18 740 this_level, cursor->ino);
507f4e33
NS
741 INT_SET(node->btree[entry].hashval, ARCH_CONVERT,
742 cursor->level[p_level].hashval);
2bd0ea18
NS
743 cursor->level[this_level].dirty++;
744 } else {
507f4e33
NS
745 do_warn(_("would correct bad hashval in interior dir "
746 "block\n\tin (level %d) in inode %llu.\n"),
2bd0ea18
NS
747 this_level, cursor->ino);
748 }
749 }
750 /*
751 * increment index for this level to point to next entry
752 * (which should point to the next descendant block)
753 */
754 cursor->level[this_level].index++;
755 return(0);
756}
757
758/*
759 * Fix up a shortform directory which was in long form (i8count set)
760 * and is now in short form (i8count clear).
761 * Return pointer to the end of the data when done.
762 */
763void
764process_sf_dir2_fixi8(
765 xfs_dir2_sf_t *sfp,
766 xfs_dir2_sf_entry_t **next_sfep)
767{
768 xfs_ino_t ino;
769 xfs_dir2_sf_t *newsfp;
770 xfs_dir2_sf_entry_t *newsfep;
771 xfs_dir2_sf_t *oldsfp;
772 xfs_dir2_sf_entry_t *oldsfep;
773 int oldsize;
774
775 newsfp = sfp;
776 oldsize = (__psint_t)*next_sfep - (__psint_t)sfp;
777 oldsfp = malloc(oldsize);
778 if (oldsfp == NULL) {
507f4e33 779 do_error(_("couldn't malloc dir2 shortform copy\n"));
2bd0ea18
NS
780 exit(1);
781 }
782 memmove(oldsfp, newsfp, oldsize);
507f4e33
NS
783 INT_SET(newsfp->hdr.count, ARCH_CONVERT,
784 INT_GET(oldsfp->hdr.count, ARCH_CONVERT));
2bd0ea18 785 newsfp->hdr.i8count = 0;
46eca962
NS
786 ino = XFS_DIR2_SF_GET_INUMBER(oldsfp, &oldsfp->hdr.parent);
787 XFS_DIR2_SF_PUT_INUMBER(newsfp, &ino, &newsfp->hdr.parent);
2bd0ea18
NS
788 oldsfep = XFS_DIR2_SF_FIRSTENTRY(oldsfp);
789 newsfep = XFS_DIR2_SF_FIRSTENTRY(newsfp);
790 while ((int)((char *)oldsfep - (char *)oldsfp) < oldsize) {
791 newsfep->namelen = oldsfep->namelen;
46eca962
NS
792 XFS_DIR2_SF_PUT_OFFSET(newsfep,
793 XFS_DIR2_SF_GET_OFFSET(oldsfep));
2bd0ea18 794 memmove(newsfep->name, oldsfep->name, newsfep->namelen);
46eca962
NS
795 ino = XFS_DIR2_SF_GET_INUMBER(oldsfp,
796 XFS_DIR2_SF_INUMBERP(oldsfep));
797 XFS_DIR2_SF_PUT_INUMBER(newsfp, &ino,
798 XFS_DIR2_SF_INUMBERP(newsfep));
2bd0ea18
NS
799 oldsfep = XFS_DIR2_SF_NEXTENTRY(oldsfp, oldsfep);
800 newsfep = XFS_DIR2_SF_NEXTENTRY(newsfp, newsfep);
801 }
802 *next_sfep = newsfep;
803 free(oldsfp);
804}
805
806/*
807 * Regenerate legal (minimal) offsets for the shortform directory.
808 */
809static void
810process_sf_dir2_fixoff(
811 xfs_dinode_t *dip)
812{
813 int i;
814 int offset;
815 xfs_dir2_sf_entry_t *sfep;
816 xfs_dir2_sf_t *sfp;
817
818 for (i = 0, sfp = &dip->di_u.di_dir2sf,
819 sfep = XFS_DIR2_SF_FIRSTENTRY(sfp),
820 offset = XFS_DIR2_DATA_FIRST_OFFSET;
821 i < INT_GET(sfp->hdr.count, ARCH_CONVERT);
822 i++, sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep)) {
46eca962 823 XFS_DIR2_SF_PUT_OFFSET(sfep, offset);
2bd0ea18
NS
824 offset += XFS_DIR2_DATA_ENTSIZE(sfep->namelen);
825 }
826}
827
828/*
829 * this routine performs inode discovery and tries to fix things
830 * in place. available redundancy -- inode data size should match
831 * used directory space in inode.
832 * a non-zero return value means the directory is bogus and should be blasted.
833 */
834/* ARGSUSED */
835static int
836process_sf_dir2(
837 xfs_mount_t *mp,
838 xfs_ino_t ino,
839 xfs_dinode_t *dip,
840 int ino_discovery,
841 int *dino_dirty, /* out - 1 if dinode buffer dirty */
842 char *dirname, /* directory pathname */
843 xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */
844 int *repair) /* out - 1 if dir was fixed up */
845{
846 int bad_offset;
847 int bad_sfnamelen;
848 int i;
849 int i8;
850 __int64_t ino_dir_size;
851 int ino_off;
852 ino_tree_node_t *irec_p;
853 int junkit;
854 char *junkreason = NULL;
855 xfs_ino_t lino;
856 int max_size;
857 char name[MAXNAMELEN + 1];
858 int namelen;
859 xfs_dir2_sf_entry_t *next_sfep;
860 int num_entries;
861 int offset;
862 xfs_dir2_sf_t *sfp;
863 xfs_dir2_sf_entry_t *sfep;
864 int tmp_elen;
865 int tmp_len;
866 xfs_dir2_sf_entry_t *tmp_sfep;
867 xfs_ino_t zero = 0;
868
869 sfp = &dip->di_u.di_dir2sf;
46eca962 870 max_size = XFS_DFORK_DSIZE(dip, mp);
2556c98b 871 num_entries = sfp->hdr.count;
2bd0ea18
NS
872 ino_dir_size = INT_GET(dip->di_core.di_size, ARCH_CONVERT);
873 offset = XFS_DIR2_DATA_FIRST_OFFSET;
e55d768a 874 bad_offset = *repair = 0;
2bd0ea18
NS
875
876 ASSERT(ino_dir_size <= max_size);
877
e55d768a
NS
878 /*
879 * Initialize i8 based on size of parent inode number.
880 */
46eca962 881 i8 = (XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent)
507f4e33 882 > XFS_DIR2_MAX_SHORT_INUM);
e55d768a 883
dfc130f3 884 /*
2bd0ea18
NS
885 * check for bad entry count
886 */
887 if (num_entries * XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, 1) +
888 XFS_DIR2_SF_HDR_SIZE(0) > max_size ||
889 num_entries == 0)
890 num_entries = 0xFF;
891
892 /*
893 * run through entries, stop at first bad entry, don't need
894 * to check for .. since that's encoded in its own field
895 */
896 sfep = next_sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
897 for (i = 0;
898 i < num_entries && ino_dir_size > (char *)next_sfep - (char *)sfp;
899 i++) {
900 tmp_sfep = NULL;
901 sfep = next_sfep;
902 junkit = 0;
903 bad_sfnamelen = 0;
46eca962
NS
904 lino = XFS_DIR2_SF_GET_INUMBER(sfp,
905 XFS_DIR2_SF_INUMBERP(sfep));
2bd0ea18
NS
906 /*
907 * if entry points to self, junk it since only '.' or '..'
908 * should do that and shortform dirs don't contain either
909 * entry. if inode number is invalid, trash entry.
910 * if entry points to special inodes, trash it.
911 * if inode is unknown but number is valid,
912 * add it to the list of uncertain inodes. don't
913 * have to worry about an entry pointing to a
914 * deleted lost+found inode because the entry was
915 * deleted at the same time that the inode was cleared.
916 */
917 if (lino == ino) {
918 junkit = 1;
507f4e33 919 junkreason = _("current");
2bd0ea18
NS
920 } else if (verify_inum(mp, lino)) {
921 junkit = 1;
507f4e33 922 junkreason = _("invalid");
2bd0ea18
NS
923 } else if (lino == mp->m_sb.sb_rbmino) {
924 junkit = 1;
507f4e33 925 junkreason = _("realtime bitmap");
2bd0ea18
NS
926 } else if (lino == mp->m_sb.sb_rsumino) {
927 junkit = 1;
507f4e33 928 junkreason = _("realtime summary");
2bd0ea18
NS
929 } else if (lino == mp->m_sb.sb_uquotino) {
930 junkit = 1;
507f4e33 931 junkreason = _("user quota");
b36eef04 932 } else if (lino == mp->m_sb.sb_gquotino) {
2bd0ea18 933 junkit = 1;
507f4e33 934 junkreason = _("group quota");
2bd0ea18
NS
935 } else if ((irec_p = find_inode_rec(XFS_INO_TO_AGNO(mp, lino),
936 XFS_INO_TO_AGINO(mp, lino))) != NULL) {
937 /*
938 * if inode is marked free and we're in inode
939 * discovery mode, leave the entry alone for now.
940 * if the inode turns out to be used, we'll figure
941 * that out when we scan it. If the inode really
942 * is free, we'll hit this code again in phase 4
943 * after we've finished inode discovery and blow
944 * out the entry then.
945 */
946 ino_off = XFS_INO_TO_AGINO(mp, lino) -
947 irec_p->ino_startnum;
948 ASSERT(is_inode_confirmed(irec_p, ino_off));
949 if (is_inode_free(irec_p, ino_off) && !ino_discovery) {
950 junkit = 1;
507f4e33 951 junkreason = _("free");
2bd0ea18
NS
952 }
953 } else if (ino_discovery) {
954 /*
955 * put the inode on the uncertain list. we'll
956 * pull the inode off the list and check it later.
957 * if the inode turns out be bogus, we'll delete
958 * this entry in phase 6.
959 */
960 add_inode_uncertain(mp, lino, 0);
961 } else {
962 /*
963 * blow the entry out. we know about all
964 * undiscovered entries now (past inode discovery
965 * phase) so this is clearly a bogus entry.
966 */
967 junkit = 1;
507f4e33 968 junkreason = _("non-existent");
2bd0ea18
NS
969 }
970 namelen = sfep->namelen;
971 if (junkit)
507f4e33
NS
972 do_warn(_("entry \"%*.*s\" in shortform directory %llu "
973 "references %s inode %llu\n"),
2bd0ea18
NS
974 namelen, namelen, sfep->name, ino, junkreason,
975 lino);
976 if (namelen == 0) {
977 /*
978 * if we're really lucky, this is
979 * the last entry in which case we
980 * can use the dir size to set the
981 * namelen value. otherwise, forget
982 * it because we're not going to be
983 * able to find the next entry.
984 */
985 bad_sfnamelen = 1;
986
987 if (i == num_entries - 1) {
988 namelen = ino_dir_size -
989 ((__psint_t) &sfep->name[0] -
990 (__psint_t) sfp);
991 if (!no_modify) {
507f4e33
NS
992 do_warn(_("zero length entry in "
993 "shortform dir %llu, "
994 "resetting to %d\n"),
2bd0ea18
NS
995 ino, namelen);
996 sfep->namelen = namelen;
997 } else {
507f4e33
NS
998 do_warn(_("zero length entry in "
999 "shortform dir %llu, "
1000 "would set to %d\n"),
2bd0ea18
NS
1001 ino, namelen);
1002 }
1003 } else {
507f4e33
NS
1004 do_warn(_("zero length entry in shortform dir "
1005 "%llu"),
2bd0ea18
NS
1006 ino);
1007 if (!no_modify)
507f4e33 1008 do_warn(_(", junking %d entries\n"),
2bd0ea18
NS
1009 num_entries - i);
1010 else
507f4e33 1011 do_warn(_(", would junk %d entries\n"),
2bd0ea18
NS
1012 num_entries - i);
1013 /*
1014 * don't process the rest of the directory,
1015 * break out of processing looop
1016 */
1017 break;
1018 }
1019 } else if ((__psint_t) sfep - (__psint_t) sfp +
1020 + XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep)
1021 > ino_dir_size) {
1022 bad_sfnamelen = 1;
1023
1024 if (i == num_entries - 1) {
1025 namelen = ino_dir_size -
1026 ((__psint_t) &sfep->name[0] -
1027 (__psint_t) sfp);
507f4e33
NS
1028 do_warn(_("size of last entry overflows space "
1029 "left in in shortform dir %llu, "),
2bd0ea18
NS
1030 ino);
1031 if (!no_modify) {
507f4e33 1032 do_warn(_("resetting to %d\n"),
2bd0ea18
NS
1033 namelen);
1034 sfep->namelen = namelen;
1035 *dino_dirty = 1;
1036 } else {
507f4e33 1037 do_warn(_("would reset to %d\n"),
2bd0ea18
NS
1038 namelen);
1039 }
1040 } else {
507f4e33
NS
1041 do_warn(_("size of entry #%d overflows space "
1042 "left in in shortform dir %llu\n"),
2bd0ea18
NS
1043 i, ino);
1044 if (!no_modify) {
1045 if (i == num_entries - 1)
507f4e33
NS
1046 do_warn(
1047 _("junking entry #%d\n"),
2bd0ea18
NS
1048 i);
1049 else
507f4e33
NS
1050 do_warn(
1051 _("junking %d entries\n"),
2bd0ea18
NS
1052 num_entries - i);
1053 } else {
1054 if (i == num_entries - 1)
507f4e33
NS
1055 do_warn(
1056 _("would junk entry #%d\n"),
2bd0ea18
NS
1057 i);
1058 else
507f4e33
NS
1059 do_warn(
1060 _("would junk %d entries\n"),
2bd0ea18
NS
1061 num_entries - i);
1062 }
1063
1064 break;
1065 }
1066 }
1067
1068 /*
1069 * check for illegal chars in name.
1070 * no need to check for bad length because
1071 * the length value is stored in a byte
1072 * so it can't be too big, it can only wrap
1073 */
1074 if (namecheck((char *)&sfep->name[0], namelen)) {
1075 /*
1076 * junk entry
1077 */
507f4e33
NS
1078 do_warn(_("entry contains illegal character "
1079 "in shortform dir %llu\n"),
2bd0ea18
NS
1080 ino);
1081 junkit = 1;
1082 }
1083
46eca962 1084 if (XFS_DIR2_SF_GET_OFFSET(sfep) < offset) {
507f4e33
NS
1085 do_warn(_("entry contains offset out of order in "
1086 "shortform dir %llu\n"),
2bd0ea18
NS
1087 ino);
1088 bad_offset = 1;
1089 }
46eca962 1090 offset = XFS_DIR2_SF_GET_OFFSET(sfep) +
2bd0ea18
NS
1091 XFS_DIR2_DATA_ENTSIZE(namelen);
1092
1093 /*
1094 * junk the entry by copying up the rest of the
1095 * fork over the current entry and decrementing
1096 * the entry count. if we're in no_modify mode,
1097 * just issue the warning instead. then continue
1098 * the loop with the next_sfep pointer set to the
1099 * correct place in the fork and other counters
1100 * properly set to reflect the deletion if it
1101 * happened.
1102 */
1103 if (junkit) {
1104 bcopy(sfep->name, name, namelen);
1105 name[namelen] = '\0';
1106
1107 if (!no_modify) {
1108 tmp_elen =
1109 XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep);
507f4e33
NS
1110 INT_MOD(dip->di_core.di_size, ARCH_CONVERT,
1111 -(tmp_elen));
2bd0ea18
NS
1112 ino_dir_size -= tmp_elen;
1113
1114 tmp_sfep = (xfs_dir2_sf_entry_t *)
1115 ((__psint_t) sfep + tmp_elen);
1116 tmp_len = max_size - ((__psint_t) tmp_sfep
1117 - (__psint_t) sfp);
1118
1119 memmove(sfep, tmp_sfep, tmp_len);
1120
1121 INT_MOD(sfp->hdr.count, ARCH_CONVERT, -1);
1122 num_entries--;
1123 bzero((void *) ((__psint_t) sfep + tmp_len),
1124 tmp_elen);
1125
1126 /*
1127 * reset the tmp value to the current
1128 * pointer so we'll process the entry
1129 * we just moved up
1130 */
1131 tmp_sfep = sfep;
1132
1133 /*
1134 * WARNING: drop the index i by one
1135 * so it matches the decremented count
1136 * for accurate comparisons later
1137 */
1138 i--;
1139
1140 *dino_dirty = 1;
1141 *repair = 1;
1142
507f4e33
NS
1143 do_warn(_("junking entry \"%s\" in directory "
1144 "inode %llu\n"),
2bd0ea18
NS
1145 name, ino);
1146 } else {
507f4e33
NS
1147 do_warn(_("would have junked entry \"%s\" in "
1148 "directory inode %llu\n"),
2bd0ea18
NS
1149 name, ino);
1150 }
1151 } else if (lino > XFS_DIR2_MAX_SHORT_INUM)
1152 i8++;
1153 /*
1154 * go onto next entry unless we've just junked an
1155 * entry in which the current entry pointer points
1156 * to an unprocessed entry. have to take into zero-len
1157 * entries into account in no modify mode since we
1158 * calculate size based on next_sfep.
1159 */
1160 next_sfep = (tmp_sfep == NULL)
1161 ? (xfs_dir2_sf_entry_t *) ((__psint_t) sfep
1162 + ((!bad_sfnamelen)
1163 ? XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp,
1164 sfep)
1165 : XFS_DIR2_SF_ENTSIZE_BYNAME(sfp,
1166 namelen)))
1167 : tmp_sfep;
1168 }
1169
1170 /* sync up sizes and entry counts */
1171
1172 if (INT_GET(sfp->hdr.count, ARCH_CONVERT) != i) {
1173 if (no_modify) {
507f4e33
NS
1174 do_warn(_("would have corrected entry count "
1175 "in directory %llu from %d to %d\n"),
2bd0ea18
NS
1176 ino, INT_GET(sfp->hdr.count, ARCH_CONVERT), i);
1177 } else {
507f4e33
NS
1178 do_warn(_("corrected entry count in directory %llu, "
1179 "was %d, now %d\n"),
2bd0ea18
NS
1180 ino, INT_GET(sfp->hdr.count, ARCH_CONVERT), i);
1181 INT_SET(sfp->hdr.count, ARCH_CONVERT, i);
1182 *dino_dirty = 1;
1183 *repair = 1;
1184 }
1185 }
1186
1187 if (sfp->hdr.i8count != i8) {
1188 if (no_modify) {
507f4e33
NS
1189 do_warn(_("would have corrected i8 count in directory "
1190 "%llu from %d to %d\n"),
2bd0ea18
NS
1191 ino, sfp->hdr.i8count, i8);
1192 } else {
507f4e33
NS
1193 do_warn(_("corrected i8 count in directory %llu, "
1194 "was %d, now %d\n"),
2bd0ea18
NS
1195 ino, sfp->hdr.i8count, i8);
1196 if (i8 == 0)
1197 process_sf_dir2_fixi8(sfp, &next_sfep);
1198 else
1199 sfp->hdr.i8count = i8;
1200 *dino_dirty = 1;
1201 *repair = 1;
1202 }
1203 }
1204
1205 if ((__psint_t) next_sfep - (__psint_t) sfp != ino_dir_size) {
1206 if (no_modify) {
507f4e33
NS
1207 do_warn(_("would have corrected directory %llu size "
1208 "from %lld to %lld\n"),
2bd0ea18
NS
1209 ino, (__int64_t) ino_dir_size,
1210 (__int64_t)((__psint_t)next_sfep -
1211 (__psint_t)sfp));
1212 } else {
507f4e33
NS
1213 do_warn(_("corrected directory %llu size, was %lld, "
1214 "now %lld\n"),
2bd0ea18
NS
1215 ino, (__int64_t) ino_dir_size,
1216 (__int64_t)((__psint_t)next_sfep -
1217 (__psint_t)sfp));
1218
507f4e33
NS
1219 INT_SET(dip->di_core.di_size, ARCH_CONVERT,
1220 (xfs_fsize_t)((__psint_t)next_sfep -
2bd0ea18
NS
1221 (__psint_t)sfp));
1222 *dino_dirty = 1;
1223 *repair = 1;
1224 }
1225 }
507f4e33
NS
1226 if (offset +
1227 (INT_GET(sfp->hdr.count, ARCH_CONVERT) + 2) *
1228 sizeof(xfs_dir2_leaf_entry_t) +
2bd0ea18 1229 sizeof(xfs_dir2_block_tail_t) > mp->m_dirblksize) {
507f4e33 1230 do_warn(_("directory %llu offsets too high\n"), ino);
2bd0ea18
NS
1231 bad_offset = 1;
1232 }
1233 if (bad_offset) {
1234 if (no_modify) {
507f4e33
NS
1235 do_warn(_("would have corrected entry offsets in "
1236 "directory %llu\n"),
2bd0ea18
NS
1237 ino);
1238 } else {
507f4e33
NS
1239 do_warn(_("corrected entry offsets in "
1240 "directory %llu\n"),
2bd0ea18
NS
1241 ino);
1242 process_sf_dir2_fixoff(dip);
1243 *dino_dirty = 1;
1244 *repair = 1;
1245 }
1246 }
1247
1248 /*
1249 * check parent (..) entry
1250 */
46eca962 1251 *parent = XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent);
2bd0ea18
NS
1252
1253 /*
1254 * if parent entry is bogus, null it out. we'll fix it later .
1255 */
1256 if (verify_inum(mp, *parent)) {
1257
507f4e33
NS
1258 do_warn(_("bogus .. inode number (%llu) in directory inode "
1259 "%llu, "),
2bd0ea18
NS
1260 *parent, ino);
1261 *parent = NULLFSINO;
1262 if (!no_modify) {
507f4e33 1263 do_warn(_("clearing inode number\n"));
2bd0ea18 1264
46eca962 1265 XFS_DIR2_SF_PUT_INUMBER(sfp, &zero, &sfp->hdr.parent);
2bd0ea18
NS
1266 *dino_dirty = 1;
1267 *repair = 1;
1268 } else {
507f4e33 1269 do_warn(_("would clear inode number\n"));
2bd0ea18
NS
1270 }
1271 } else if (ino == mp->m_sb.sb_rootino && ino != *parent) {
1272 /*
1273 * root directories must have .. == .
1274 */
1275 if (!no_modify) {
507f4e33
NS
1276 do_warn(_("corrected root directory %llu .. entry, "
1277 "was %llu, now %llu\n"),
2bd0ea18
NS
1278 ino, *parent, ino);
1279 *parent = ino;
46eca962 1280 XFS_DIR2_SF_PUT_INUMBER(sfp, parent, &sfp->hdr.parent);
2bd0ea18
NS
1281 *dino_dirty = 1;
1282 *repair = 1;
1283 } else {
507f4e33
NS
1284 do_warn(_("would have corrected root directory %llu .. "
1285 "entry from %llu to %llu\n"),
2bd0ea18
NS
1286 ino, *parent, ino);
1287 }
1288 } else if (ino == *parent && ino != mp->m_sb.sb_rootino) {
1289 /*
1290 * likewise, non-root directories can't have .. pointing
1291 * to .
1292 */
1293 *parent = NULLFSINO;
507f4e33
NS
1294 do_warn(_("bad .. entry in directory inode %llu, points to "
1295 "self, "),
2bd0ea18
NS
1296 ino);
1297 if (!no_modify) {
507f4e33 1298 do_warn(_("clearing inode number\n"));
2bd0ea18 1299
46eca962 1300 XFS_DIR2_SF_PUT_INUMBER(sfp, &zero, &sfp->hdr.parent);
2bd0ea18
NS
1301 *dino_dirty = 1;
1302 *repair = 1;
1303 } else {
507f4e33 1304 do_warn(_("would clear inode number\n"));
2bd0ea18
NS
1305 }
1306 }
1307
1308 return(0);
1309}
1310
1311/*
1312 * Process one directory data block.
1313 */
1314/* ARGSUSED */
1315static int
1316process_dir2_data(
1317 xfs_mount_t *mp,
1318 xfs_ino_t ino,
1319 xfs_dinode_t *dip,
1320 int ino_discovery,
1321 char *dirname, /* directory pathname */
1322 xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */
1323 xfs_dabuf_t *bp,
1324 int *dot, /* out - 1 if there is a dot, else 0 */
1325 int *dotdot, /* out - 1 if there's a dotdot, else 0 */
1326 xfs_dablk_t da_bno,
1327 char *endptr)
1328{
1329 int badbest;
1330 xfs_dir2_data_free_t *bf;
1331 int clearino;
1332 char *clearreason = NULL;
1333 xfs_dir2_data_t *d;
1334 xfs_dir2_data_entry_t *dep;
1335 xfs_dir2_data_free_t *dfp;
1336 xfs_dir2_data_unused_t *dup;
1337 int freeseen;
1338 int i;
1339 int ino_off;
1340 ino_tree_node_t *irec_p;
1341 int junkit;
1342 int lastfree;
1343 int nm_illegal;
1344 char *ptr;
1345
1346 d = bp->data;
1347 bf = d->hdr.bestfree;
1348 ptr = (char *)d->u;
1349 badbest = lastfree = freeseen = 0;
1350 if (INT_GET(bf[0].length, ARCH_CONVERT) == 0) {
1351 badbest |= INT_GET(bf[0].offset, ARCH_CONVERT) != 0;
1352 freeseen |= 1 << 0;
1353 }
1354 if (INT_GET(bf[1].length, ARCH_CONVERT) == 0) {
1355 badbest |= INT_GET(bf[1].offset, ARCH_CONVERT) != 0;
1356 freeseen |= 1 << 1;
1357 }
1358 if (INT_GET(bf[2].length, ARCH_CONVERT) == 0) {
1359 badbest |= INT_GET(bf[2].offset, ARCH_CONVERT) != 0;
1360 freeseen |= 1 << 2;
1361 }
1362 badbest |= INT_GET(bf[0].length, ARCH_CONVERT) < INT_GET(bf[1].length, ARCH_CONVERT);
1363 badbest |= INT_GET(bf[1].length, ARCH_CONVERT) < INT_GET(bf[2].length, ARCH_CONVERT);
1364 while (ptr < endptr) {
1365 dup = (xfs_dir2_data_unused_t *)ptr;
1366 /*
1367 * If it's unused, look for the space in the bestfree table.
1368 * If we find it, account for that, else make sure it doesn't
1369 * need to be there.
1370 */
1371 if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
507f4e33
NS
1372 if (ptr + INT_GET(dup->length, ARCH_CONVERT) > endptr ||
1373 INT_GET(dup->length, ARCH_CONVERT) == 0 ||
2bd0ea18
NS
1374 (INT_GET(dup->length, ARCH_CONVERT) & (XFS_DIR2_DATA_ALIGN - 1)))
1375 break;
46eca962
NS
1376 if (INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P(dup),
1377 ARCH_CONVERT) != (char *)dup - (char *)d)
2bd0ea18
NS
1378 break;
1379 badbest |= lastfree != 0;
1380 dfp = xfs_dir2_data_freefind(d, dup);
1381 if (dfp) {
1382 i = dfp - bf;
1383 badbest |= (freeseen & (1 << i)) != 0;
1384 freeseen |= 1 << i;
1385 } else
507f4e33
NS
1386 badbest |= INT_GET(dup->length, ARCH_CONVERT) >
1387 INT_GET(bf[2].length, ARCH_CONVERT);
2bd0ea18
NS
1388 ptr += INT_GET(dup->length, ARCH_CONVERT);
1389 lastfree = 1;
1390 continue;
1391 }
1392 dep = (xfs_dir2_data_entry_t *)ptr;
1393 if (ptr + XFS_DIR2_DATA_ENTSIZE(dep->namelen) > endptr)
1394 break;
507f4e33
NS
1395 if (INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(dep), ARCH_CONVERT) !=
1396 (char *)dep - (char *)d)
2bd0ea18
NS
1397 break;
1398 ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
1399 lastfree = 0;
1400 }
1401 /*
1402 * Dropped out before we processed everything, give up.
1403 * Phase 6 will kill this block if we don't kill the inode.
1404 */
1405 if (ptr != endptr) {
507f4e33 1406 do_warn(_("corrupt block %u in directory inode %llu\n"),
2bd0ea18
NS
1407 da_bno, ino);
1408 if (!no_modify)
507f4e33 1409 do_warn(_("\twill junk block\n"));
2bd0ea18 1410 else
507f4e33 1411 do_warn(_("\twould junk block\n"));
2bd0ea18
NS
1412 return 1;
1413 }
1414 ptr = (char *)d->u;
1415 /*
1416 * Process the entries now.
1417 */
1418 while (ptr < endptr) {
1419 dup = (xfs_dir2_data_unused_t *)ptr;
507f4e33
NS
1420 if (INT_GET(dup->freetag, ARCH_CONVERT) ==
1421 XFS_DIR2_DATA_FREE_TAG) {
2bd0ea18
NS
1422 ptr += INT_GET(dup->length, ARCH_CONVERT);
1423 continue;
1424 }
1425 dep = (xfs_dir2_data_entry_t *)ptr;
1426 /*
1427 * We may have to blow out an entry because of bad inode
1428 * numbers. Do NOT touch the name until after we've computed
1429 * the hashvalue and done a namecheck() on the name.
1430 */
507f4e33
NS
1431 if (!ino_discovery &&
1432 INT_GET(dep->inumber, ARCH_CONVERT) == BADFSINO) {
2bd0ea18
NS
1433 /*
1434 * Don't do a damned thing. We already found this
1435 * (or did it ourselves) during phase 3.
1436 */
1437 clearino = 0;
1438 } else if (verify_inum(mp, INT_GET(dep->inumber, ARCH_CONVERT))) {
1439 /*
1440 * Bad inode number. Clear the inode number and the
1441 * entry will get removed later. We don't trash the
1442 * directory since it's still structurally intact.
1443 */
1444 clearino = 1;
507f4e33 1445 clearreason = _("invalid");
2bd0ea18
NS
1446 } else if (INT_GET(dep->inumber, ARCH_CONVERT) == mp->m_sb.sb_rbmino) {
1447 clearino = 1;
507f4e33 1448 clearreason = _("realtime bitmap");
2bd0ea18
NS
1449 } else if (INT_GET(dep->inumber, ARCH_CONVERT) == mp->m_sb.sb_rsumino) {
1450 clearino = 1;
507f4e33 1451 clearreason = _("realtime summary");
2bd0ea18
NS
1452 } else if (INT_GET(dep->inumber, ARCH_CONVERT) == mp->m_sb.sb_uquotino) {
1453 clearino = 1;
507f4e33 1454 clearreason = _("user quota");
b36eef04 1455 } else if (INT_GET(dep->inumber, ARCH_CONVERT) == mp->m_sb.sb_gquotino) {
2bd0ea18 1456 clearino = 1;
507f4e33 1457 clearreason = _("group quota");
2bd0ea18 1458 } else if ((irec_p = find_inode_rec(
507f4e33
NS
1459 XFS_INO_TO_AGNO(mp, INT_GET(dep->inumber,
1460 ARCH_CONVERT)),
1461 XFS_INO_TO_AGINO(mp, INT_GET(dep->inumber,
1462 ARCH_CONVERT)))) != NULL) {
2bd0ea18
NS
1463 /*
1464 * Inode recs should have only confirmed inodes in them.
1465 */
507f4e33
NS
1466 ino_off = XFS_INO_TO_AGINO(mp, INT_GET(dep->inumber,
1467 ARCH_CONVERT)) - irec_p->ino_startnum;
2bd0ea18
NS
1468 ASSERT(is_inode_confirmed(irec_p, ino_off));
1469 /*
1470 * If inode is marked free and we're in inode discovery
1471 * mode, leave the entry alone for now. If the inode
1472 * turns out to be used, we'll figure that out when we
1473 * scan it. If the inode really is free, we'll hit this
1474 * code again in phase 4 after we've finished inode
1475 * discovery and blow out the entry then.
1476 */
1477 if (!ino_discovery && is_inode_free(irec_p, ino_off)) {
1478 clearino = 1;
507f4e33 1479 clearreason = _("free");
2bd0ea18
NS
1480 } else
1481 clearino = 0;
1482 } else if (ino_discovery) {
1483 add_inode_uncertain(mp, INT_GET(dep->inumber, ARCH_CONVERT), 0);
1484 clearino = 0;
1485 } else {
1486 clearino = 1;
507f4e33 1487 clearreason = _("non-existent");
2bd0ea18
NS
1488 }
1489 if (clearino)
507f4e33
NS
1490 do_warn(_("entry \"%*.*s\" at block %u offset %d in "
1491 "directory inode %llu references %s inode "
1492 "%llu\n"),
2bd0ea18
NS
1493 dep->namelen, dep->namelen, dep->name,
1494 da_bno, (char *)ptr - (char *)d, ino,
507f4e33
NS
1495 clearreason,
1496 INT_GET(dep->inumber, ARCH_CONVERT));
2bd0ea18
NS
1497 /*
1498 * If the name length is 0 (illegal) make it 1 and blast
1499 * the entry.
1500 */
1501 if (dep->namelen == 0) {
507f4e33
NS
1502 do_warn(_("entry at block %u offset %d in directory "
1503 "inode %llu has 0 namelength\n"),
2bd0ea18
NS
1504 da_bno, (char *)ptr - (char *)d, ino);
1505 if (!no_modify)
1506 dep->namelen = 1;
1507 clearino = 1;
1508 }
1509 /*
1510 * If needed to clear the inode number, do it now.
1511 */
1512 if (clearino) {
1513 if (!no_modify) {
507f4e33
NS
1514 do_warn(_("\tclearing inode number in entry at "
1515 "offset %d...\n"),
2bd0ea18
NS
1516 (char *)ptr - (char *)d);
1517 INT_SET(dep->inumber, ARCH_CONVERT, BADFSINO);
1518 bp->dirty = 1;
1519 } else {
507f4e33
NS
1520 do_warn(_("\twould clear inode number in entry "
1521 "at offset %d...\n"),
2bd0ea18
NS
1522 (char *)ptr - (char *)d);
1523 }
1524 }
1525 /*
1526 * Only complain about illegal names in phase 3 (when inode
1527 * discovery is turned on). Otherwise, we'd complain a lot
1528 * during phase 4.
1529 */
1530 junkit = INT_GET(dep->inumber, ARCH_CONVERT) == BADFSINO;
1531 nm_illegal = namecheck((char *)dep->name, dep->namelen);
1532 if (ino_discovery && nm_illegal) {
507f4e33
NS
1533 do_warn(_("entry at block %u offset %d in directory "
1534 "inode %llu has illegal name \"%*.*s\": "),
2bd0ea18
NS
1535 da_bno, (char *)ptr - (char *)d, ino,
1536 dep->namelen, dep->namelen, dep->name);
1537 junkit = 1;
1538 }
1539 /*
1540 * Now we can mark entries with BADFSINO's bad.
1541 */
507f4e33
NS
1542 if (!no_modify &&
1543 INT_GET(dep->inumber, ARCH_CONVERT) == BADFSINO) {
2bd0ea18
NS
1544 dep->name[0] = '/';
1545 bp->dirty = 1;
1546 junkit = 0;
1547 }
1548 /*
1549 * Special .. entry processing.
1550 */
1551 if (dep->namelen == 2 &&
1552 dep->name[0] == '.' && dep->name[1] == '.') {
1553 if (!*dotdot) {
1554 (*dotdot)++;
1555 *parent = INT_GET(dep->inumber, ARCH_CONVERT);
1556 /*
1557 * What if .. == .? Legal only in the root
1558 * inode. Blow out entry and set parent to
1559 * NULLFSINO otherwise.
1560 */
1561 if (ino == INT_GET(dep->inumber, ARCH_CONVERT) &&
1562 ino != mp->m_sb.sb_rootino) {
1563 *parent = NULLFSINO;
507f4e33
NS
1564 do_warn(_("bad .. entry in directory "
1565 "inode %llu, points to self: "),
2bd0ea18
NS
1566 ino);
1567 junkit = 1;
1568 }
1569 /*
1570 * We have to make sure that . == .. in the
1571 * root inode.
1572 */
1573 else if (ino != INT_GET(dep->inumber, ARCH_CONVERT) &&
1574 ino == mp->m_sb.sb_rootino) {
507f4e33
NS
1575 do_warn(_("bad .. entry in root "
1576 "directory inode %llu, was "
1577 "%llu: "),
2bd0ea18
NS
1578 ino, INT_GET(dep->inumber, ARCH_CONVERT));
1579 if (!no_modify) {
507f4e33 1580 do_warn(_("correcting\n"));
2bd0ea18
NS
1581 INT_SET(dep->inumber, ARCH_CONVERT, ino);
1582 bp->dirty = 1;
1583 } else {
507f4e33 1584 do_warn(_("would correct\n"));
2bd0ea18
NS
1585 }
1586 }
1587 }
1588 /*
1589 * Can't fix the directory unless we know which ..
1590 * entry is the right one. Both have valid inode
1591 * numbers or we wouldn't be here. So since both
1592 * seem equally valid, trash this one.
1593 */
1594 else {
507f4e33
NS
1595 do_warn(_("multiple .. entries in directory "
1596 "inode %llu: "),
2bd0ea18
NS
1597 ino);
1598 junkit = 1;
1599 }
1600 }
1601 /*
1602 * Special . entry processing.
1603 */
1604 else if (dep->namelen == 1 && dep->name[0] == '.') {
1605 if (!*dot) {
1606 (*dot)++;
1607 if (INT_GET(dep->inumber, ARCH_CONVERT) != ino) {
507f4e33
NS
1608 do_warn(_("bad . entry in directory "
1609 "inode %llu, was %llu: "),
2bd0ea18
NS
1610 ino, INT_GET(dep->inumber, ARCH_CONVERT));
1611 if (!no_modify) {
507f4e33 1612 do_warn(_("correcting\n"));
2bd0ea18
NS
1613 INT_SET(dep->inumber, ARCH_CONVERT, ino);
1614 bp->dirty = 1;
1615 } else {
507f4e33 1616 do_warn(_("would correct\n"));
2bd0ea18
NS
1617 }
1618 }
1619 } else {
507f4e33
NS
1620 do_warn(_("multiple . entries in directory "
1621 "inode %llu: "),
2bd0ea18
NS
1622 ino);
1623 junkit = 1;
1624 }
1625 }
1626 /*
1627 * All other entries -- make sure only . references self.
1628 */
1629 else if (INT_GET(dep->inumber, ARCH_CONVERT) == ino) {
507f4e33
NS
1630 do_warn(_("entry \"%*.*s\" in directory inode %llu "
1631 "points to self: "),
2bd0ea18
NS
1632 dep->namelen, dep->namelen, dep->name, ino);
1633 junkit = 1;
1634 }
1635 /*
1636 * Clear junked entries.
1637 */
1638 if (junkit) {
1639 if (!no_modify) {
1640 dep->name[0] = '/';
1641 bp->dirty = 1;
507f4e33 1642 do_warn(_("clearing entry\n"));
2bd0ea18 1643 } else {
507f4e33 1644 do_warn(_("would clear entry\n"));
2bd0ea18
NS
1645 }
1646 }
1647 /*
1648 * Advance to the next entry.
1649 */
1650 ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
1651 }
1652 /*
1653 * Check the bestfree table.
1654 */
1655 if (freeseen != 7 || badbest) {
507f4e33
NS
1656 do_warn(_("bad bestfree table in block %u in directory inode "
1657 "%llu: "),
2bd0ea18
NS
1658 da_bno, ino);
1659 if (!no_modify) {
507f4e33 1660 do_warn(_("repairing table\n"));
2bd0ea18
NS
1661 libxfs_dir2_data_freescan(mp, d, &i, endptr);
1662 bp->dirty = 1;
1663 } else {
507f4e33 1664 do_warn(_("would repair table\n"));
2bd0ea18
NS
1665 }
1666 }
1667 return 0;
1668}
1669
1670/*
1671 * Process a block-format directory.
1672 */
1673/* ARGSUSED */
1674static int
1675process_block_dir2(
1676 xfs_mount_t *mp,
1677 xfs_ino_t ino,
1678 xfs_dinode_t *dip,
1679 int ino_discovery,
1680 int *dino_dirty, /* out - 1 if dinode buffer dirty */
1681 char *dirname, /* directory pathname */
1682 xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */
1683 blkmap_t *blkmap,
1684 int *dot, /* out - 1 if there is a dot, else 0 */
1685 int *dotdot, /* out - 1 if there's a dotdot, else 0 */
1686 int *repair) /* out - 1 if something was fixed */
1687{
1688 xfs_dir2_block_t *block;
1689 xfs_dir2_leaf_entry_t *blp;
1690 bmap_ext_t *bmp;
1691 xfs_dabuf_t *bp;
1692 xfs_dir2_block_tail_t *btp;
1693 int nex;
1694 int rval;
1e77098c 1695 bmap_ext_t lbmp;
2bd0ea18
NS
1696
1697 *repair = *dot = *dotdot = 0;
1698 *parent = NULLFSINO;
1e77098c 1699 nex = blkmap_getn(blkmap, mp->m_dirdatablk, mp->m_dirblkfsbs, &bmp, &lbmp);
2bd0ea18 1700 if (nex == 0) {
507f4e33 1701 do_warn(_("block %u for directory inode %llu is missing\n"),
2bd0ea18
NS
1702 mp->m_dirdatablk, ino);
1703 return 1;
1704 }
1705 bp = da_read_buf(mp, nex, bmp);
1e77098c
MV
1706 if (bmp != &lbmp)
1707 free(bmp);
2bd0ea18 1708 if (bp == NULL) {
507f4e33 1709 do_warn(_("can't read block %u for directory inode %llu\n"),
2bd0ea18
NS
1710 mp->m_dirdatablk, ino);
1711 return 1;
1712 }
1713 /*
1714 * Verify the block
1715 */
1716 block = bp->data;
1717 if (INT_GET(block->hdr.magic, ARCH_CONVERT) != XFS_DIR2_BLOCK_MAGIC)
507f4e33
NS
1718 do_warn(_("bad directory block magic # %#x in block %u for "
1719 "directory inode %llu\n"),
1720 INT_GET(block->hdr.magic, ARCH_CONVERT),
1721 mp->m_dirdatablk, ino);
2bd0ea18
NS
1722 /*
1723 * process the data area
1724 * this also checks & fixes the bestfree
1725 */
1726 btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
46eca962 1727 blp = XFS_DIR2_BLOCK_LEAF_P(btp);
2bd0ea18
NS
1728 /*
1729 * Don't let this go past the end of the block.
1730 */
1731 if ((char *)blp > (char *)btp)
1732 blp = (xfs_dir2_leaf_entry_t *)btp;
1733 rval = process_dir2_data(mp, ino, dip, ino_discovery, dirname, parent,
1734 bp, dot, dotdot, mp->m_dirdatablk, (char *)blp);
1735 if (bp->dirty && !no_modify) {
1736 *repair = 1;
1737 da_bwrite(mp, bp);
1738 } else
1739 da_brelse(bp);
1740 return rval;
1741}
1742
1743/*
1744 * Validates leaf contents, node format directories only.
1745 * magic number and sibling pointers checked by caller.
1746 * Returns 0 if block is ok, 1 if the block is bad.
1747 * Looking for: out of order hash values, bad stale counts.
1748 */
1749static int
1750process_leaf_block_dir2(
1751 xfs_mount_t *mp,
1752 xfs_dir2_leaf_t *leaf,
1753 xfs_dablk_t da_bno,
1754 xfs_ino_t ino,
1755 xfs_dahash_t last_hashval,
1756 xfs_dahash_t *next_hashval)
1757{
1758 int i;
1759 int stale;
1760
1761 for (i = stale = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); i++) {
1762 if ((char *)&leaf->ents[i] >= (char *)leaf + mp->m_dirblksize) {
507f4e33
NS
1763 do_warn(_("bad entry count in block %u of directory "
1764 "inode %llu\n"),
2bd0ea18
NS
1765 da_bno, ino);
1766 return 1;
1767 }
507f4e33
NS
1768 if (INT_GET(leaf->ents[i].address, ARCH_CONVERT) ==
1769 XFS_DIR2_NULL_DATAPTR)
2bd0ea18 1770 stale++;
507f4e33
NS
1771 else if (INT_GET(leaf->ents[i].hashval, ARCH_CONVERT) <
1772 last_hashval) {
1773 do_warn(_("bad hash ordering in block %u of directory "
1774 "inode %llu\n"),
2bd0ea18
NS
1775 da_bno, ino);
1776 return 1;
1777 }
507f4e33
NS
1778 *next_hashval = last_hashval =
1779 INT_GET(leaf->ents[i].hashval, ARCH_CONVERT);
2bd0ea18
NS
1780 }
1781 if (stale != INT_GET(leaf->hdr.stale, ARCH_CONVERT)) {
507f4e33
NS
1782 do_warn(_("bad stale count in block %u of directory "
1783 "inode %llu\n"),
2bd0ea18
NS
1784 da_bno, ino);
1785 return 1;
1786 }
1787 return 0;
1788}
1789
1790/*
1791 * Returns 0 if the directory is ok, 1 if it has to be rebuilt.
1792 */
1793static int
1794process_leaf_level_dir2(
1795 xfs_mount_t *mp,
1796 dir2_bt_cursor_t *da_cursor,
1797 int *repair)
dfc130f3 1798{
2bd0ea18
NS
1799 bmap_ext_t *bmp;
1800 xfs_dabuf_t *bp;
1801 int buf_dirty;
1802 xfs_dahash_t current_hashval;
1803 xfs_dablk_t da_bno;
1804 xfs_dahash_t greatest_hashval;
1805 xfs_ino_t ino;
1806 xfs_dir2_leaf_t *leaf;
1807 int nex;
1808 xfs_dablk_t prev_bno;
1e77098c 1809 bmap_ext_t lbmp;
2bd0ea18
NS
1810
1811 da_bno = da_cursor->level[0].bno;
1812 ino = da_cursor->ino;
1813 prev_bno = 0;
1814 bmp = NULL;
1815 current_hashval = 0;
9234d416 1816 greatest_hashval = 0;
2bd0ea18
NS
1817 buf_dirty = 0;
1818
1819 do {
1820 nex = blkmap_getn(da_cursor->blkmap, da_bno, mp->m_dirblkfsbs,
1e77098c 1821 &bmp, &lbmp);
2bd0ea18
NS
1822 /*
1823 * Directory code uses 0 as the NULL block pointer since 0
1824 * is the root block and no directory block pointer can point
1825 * to the root block of the btree.
1826 */
1827 ASSERT(da_bno != 0);
1828
1829 if (nex == 0) {
507f4e33
NS
1830 do_warn(_("can't map block %u for directory "
1831 "inode %llu\n"),
2bd0ea18
NS
1832 da_bno, ino);
1833 goto error_out;
1834 }
1835 bp = da_read_buf(mp, nex, bmp);
1e77098c
MV
1836 if (bmp != &lbmp)
1837 free(bmp);
2bd0ea18
NS
1838 bmp = NULL;
1839 if (bp == NULL) {
507f4e33
NS
1840 do_warn(_("can't read file block %u for directory "
1841 "inode %llu\n"),
2bd0ea18
NS
1842 da_bno, ino);
1843 goto error_out;
1844 }
1845 leaf = bp->data;
1846 /*
1847 * Check magic number for leaf directory btree block.
1848 */
507f4e33
NS
1849 if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) !=
1850 XFS_DIR2_LEAFN_MAGIC) {
1851 do_warn(_("bad directory leaf magic # %#x for "
1852 "directory inode %llu block %u\n"),
1853 INT_GET(leaf->hdr.info.magic, ARCH_CONVERT),
1854 ino, da_bno);
2bd0ea18
NS
1855 da_brelse(bp);
1856 goto error_out;
1857 }
1858 buf_dirty = 0;
1859 /*
1860 * For each block, process the block, verify its path,
1861 * then get next block. Update cursor values along the way.
1862 */
1863 if (process_leaf_block_dir2(mp, leaf, da_bno, ino,
1864 current_hashval, &greatest_hashval)) {
1865 da_brelse(bp);
1866 goto error_out;
1867 }
1868 /*
1869 * Index can be set to hdr.count so match the indices of the
1870 * interior blocks -- which at the end of the block will point
1871 * to 1 after the final real entry in the block.
1872 */
1873 da_cursor->level[0].hashval = greatest_hashval;
1874 da_cursor->level[0].bp = bp;
1875 da_cursor->level[0].bno = da_bno;
507f4e33
NS
1876 da_cursor->level[0].index =
1877 INT_GET(leaf->hdr.count, ARCH_CONVERT);
2bd0ea18
NS
1878 da_cursor->level[0].dirty = buf_dirty;
1879
1880 if (INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != prev_bno) {
507f4e33
NS
1881 do_warn(_("bad sibling back pointer for block %u in "
1882 "directory inode %llu\n"),
2bd0ea18
NS
1883 da_bno, ino);
1884 da_brelse(bp);
1885 goto error_out;
1886 }
1887 prev_bno = da_bno;
1888 da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
1889 if (da_bno != 0) {
1890 if (verify_dir2_path(mp, da_cursor, 0)) {
1891 da_brelse(bp);
1892 goto error_out;
1893 }
1894 }
1895 current_hashval = greatest_hashval;
27527004 1896 ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify));
2bd0ea18
NS
1897 if (buf_dirty && !no_modify) {
1898 *repair = 1;
1899 da_bwrite(mp, bp);
1900 } else
1901 da_brelse(bp);
1902 } while (da_bno != 0);
1903 if (verify_final_dir2_path(mp, da_cursor, 0)) {
1904 /*
1905 * Verify the final path up (right-hand-side) if still ok.
1906 */
507f4e33 1907 do_warn(_("bad hash path in directory %llu\n"), ino);
2bd0ea18
NS
1908 goto error_out;
1909 }
1910 /*
1911 * Redundant but just for testing.
1912 */
1913 release_dir2_cursor(mp, da_cursor, 0);
1914 return 0;
1915
1916error_out:
1917 /*
1918 * Release all buffers holding interior btree blocks.
1919 */
1920 err_release_dir2_cursor(mp, da_cursor, 0);
1e77098c 1921 if (bmp && (bmp != &lbmp))
2bd0ea18
NS
1922 free(bmp);
1923 return 1;
1924}
1925
1926/*
1927 * Return 1 if the directory's leaf/node space is corrupted and
1928 * needs to be rebuilt, 0 if it's ok.
1929 */
1930static int
1931process_node_dir2(
1932 xfs_mount_t *mp,
1933 xfs_ino_t ino,
1934 xfs_dinode_t *dip,
1935 blkmap_t *blkmap,
1936 int *repair)
1937{
1938 xfs_dablk_t bno;
1939 dir2_bt_cursor_t da_cursor;
1940
1941 /*
1942 * Try again -- traverse down left-side of tree until we hit the
1943 * left-most leaf block setting up the btree cursor along the way.
1944 * Then walk the leaf blocks left-to-right, calling a parent
1945 * verification routine each time we traverse a block.
1946 */
1947 bzero(&da_cursor, sizeof(da_cursor));
1948 da_cursor.ino = ino;
1949 da_cursor.dip = dip;
1950 da_cursor.blkmap = blkmap;
1951
1952 /*
1953 * Now process interior node.
1954 */
1955 if (traverse_int_dir2block(mp, &da_cursor, &bno) == 0)
1956 return 1;
1957
1958 /*
1959 * Skip directories with a root marked XFS_DIR2_LEAFN_MAGIC
1960 */
1961 if (bno == 0) {
1962 release_dir2_cursor(mp, &da_cursor, 0);
1963 return 0;
1964 } else {
1965 /*
1966 * Now pass cursor and bno into leaf-block processing routine.
dfc130f3 1967 * The leaf dir level routine checks the interior paths up to
2bd0ea18
NS
1968 * the root including the final right-most path.
1969 */
1970 return process_leaf_level_dir2(mp, &da_cursor, repair);
1971 }
1972}
1973
1974/*
1975 * Process leaf and node directories.
1976 * Process the data blocks then, if it's a node directory, check
1977 * the consistency of those blocks.
1978 */
1979static int
1980process_leaf_node_dir2(
1981 xfs_mount_t *mp,
1982 xfs_ino_t ino,
1983 xfs_dinode_t *dip,
1984 int ino_discovery,
1985 char *dirname, /* directory pathname */
1986 xfs_ino_t *parent, /* out - NULLFSINO if entry not exist */
1987 blkmap_t *blkmap,
1988 int *dot, /* out - 1 if there is a dot, else 0 */
1989 int *dotdot, /* out - 1 if there's a dotdot, else 0 */
1990 int *repair, /* out - 1 if something was fixed */
1991 int isnode) /* node directory not leaf */
1992{
1993 bmap_ext_t *bmp;
1994 xfs_dabuf_t *bp;
1995 xfs_dir2_data_t *data;
1996 xfs_dfiloff_t dbno;
1997 int good;
1998 int i;
1999 xfs_dfiloff_t ndbno;
2000 int nex;
2001 int t;
1e77098c 2002 bmap_ext_t lbmp;
2bd0ea18
NS
2003
2004 *repair = *dot = *dotdot = good = 0;
2005 *parent = NULLFSINO;
2006 ndbno = NULLDFILOFF;
2007 while ((dbno = blkmap_next_off(blkmap, ndbno, &t)) < mp->m_dirleafblk) {
1e77098c 2008 nex = blkmap_getn(blkmap, dbno, mp->m_dirblkfsbs, &bmp, &lbmp);
2bd0ea18
NS
2009 ndbno = dbno + mp->m_dirblkfsbs - 1;
2010 if (nex == 0) {
507f4e33
NS
2011 do_warn(_("block %llu for directory inode %llu is "
2012 "missing\n"),
2bd0ea18
NS
2013 dbno, ino);
2014 continue;
2015 }
2016 bp = da_read_buf(mp, nex, bmp);
1e77098c
MV
2017 if (bmp != &lbmp)
2018 free(bmp);
2bd0ea18 2019 if (bp == NULL) {
507f4e33
NS
2020 do_warn(_("can't read block %llu for directory inode "
2021 "%llu\n"),
2bd0ea18
NS
2022 dbno, ino);
2023 continue;
2024 }
2025 data = bp->data;
507f4e33
NS
2026 if (INT_GET(data->hdr.magic, ARCH_CONVERT) !=
2027 XFS_DIR2_DATA_MAGIC)
2028 do_warn(_("bad directory block magic # %#x in block "
2029 "%llu for directory inode %llu\n"),
2030 INT_GET(data->hdr.magic, ARCH_CONVERT),
2031 dbno, ino);
2bd0ea18
NS
2032 i = process_dir2_data(mp, ino, dip, ino_discovery, dirname,
2033 parent, bp, dot, dotdot, (xfs_dablk_t)dbno,
2034 (char *)data + mp->m_dirblksize);
2035 if (i == 0)
2036 good++;
2037 if (bp->dirty && !no_modify) {
2038 *repair = 1;
2039 da_bwrite(mp, bp);
2040 } else
2041 da_brelse(bp);
2042 }
2043 if (good == 0)
2044 return 1;
2045 if (!isnode)
2046 return 0;
2047 if (dir2_is_badino(ino))
2048 return 0;
2049
2050 if (process_node_dir2(mp, ino, dip, blkmap, repair))
2051 dir2_add_badlist(ino);
2052 return 0;
2053
2054}
2055
2056/*
2057 * Returns 1 if things are bad (directory needs to be junked)
2058 * and 0 if things are ok. If ino_discovery is 1, add unknown
2059 * inodes to uncertain inode list.
2060 */
2061int
2062process_dir2(
2063 xfs_mount_t *mp,
2064 xfs_ino_t ino,
2065 xfs_dinode_t *dip,
2066 int ino_discovery,
2067 int *dino_dirty,
2068 char *dirname,
2069 xfs_ino_t *parent,
2070 blkmap_t *blkmap)
2071{
2072 int dot;
2073 int dotdot;
2074 xfs_dfiloff_t last;
2075 int repair;
2076 int res;
2077
2078 *parent = NULLFSINO;
2079 dot = dotdot = 0;
2080 last = 0;
2081
2082 /*
2083 * branch off depending on the type of inode. This routine
2084 * is only called ONCE so all the subordinate routines will
2085 * fix '.' and junk '..' if they're bogus.
2086 */
2087 if (blkmap)
2088 last = blkmap_last_off(blkmap);
507f4e33 2089 if (INT_GET(dip->di_core.di_size, ARCH_CONVERT) <=
46eca962 2090 XFS_DFORK_DSIZE(dip, mp) &&
2bd0ea18
NS
2091 dip->di_core.di_format == XFS_DINODE_FMT_LOCAL) {
2092 dot = dotdot = 1;
2093 res = process_sf_dir2(mp, ino, dip, ino_discovery, dino_dirty,
2094 dirname, parent, &repair);
2095 } else if (last == mp->m_dirblkfsbs &&
2096 (dip->di_core.di_format == XFS_DINODE_FMT_EXTENTS ||
2097 dip->di_core.di_format == XFS_DINODE_FMT_BTREE)) {
2098 res = process_block_dir2(mp, ino, dip, ino_discovery,
2099 dino_dirty, dirname, parent, blkmap, &dot, &dotdot,
2100 &repair);
2101 } else if (last >= mp->m_dirleafblk + mp->m_dirblkfsbs &&
2102 (dip->di_core.di_format == XFS_DINODE_FMT_EXTENTS ||
2103 dip->di_core.di_format == XFS_DINODE_FMT_BTREE)) {
2104 res = process_leaf_node_dir2(mp, ino, dip, ino_discovery,
2105 dirname, parent, blkmap, &dot, &dotdot, &repair,
2106 last > mp->m_dirleafblk + mp->m_dirblkfsbs);
2107 } else {
507f4e33 2108 do_warn(_("bad size/format for directory %llu\n"), ino);
2bd0ea18
NS
2109 return 1;
2110 }
2111 /*
2112 * bad . entries in all directories will be fixed up in phase 6
2113 */
2114 if (dot == 0) {
507f4e33 2115 do_warn(_("no . entry for directory %llu\n"), ino);
2bd0ea18
NS
2116 }
2117
2118 /*
2119 * shortform dirs always have a .. entry. .. for all longform
2120 * directories will get fixed in phase 6. .. for other shortform
2121 * dirs also get fixed there. .. for a shortform root was
2122 * fixed in place since we know what it should be
2123 */
2124 if (dotdot == 0 && ino != mp->m_sb.sb_rootino) {
507f4e33 2125 do_warn(_("no .. entry for directory %llu\n"), ino);
2bd0ea18 2126 } else if (dotdot == 0 && ino == mp->m_sb.sb_rootino) {
507f4e33 2127 do_warn(_("no .. entry for root directory %llu\n"), ino);
2bd0ea18
NS
2128 need_root_dotdot = 1;
2129 }
dfc130f3 2130
27527004
NS
2131 ASSERT((ino != mp->m_sb.sb_rootino && ino != *parent) ||
2132 (ino == mp->m_sb.sb_rootino &&
2133 (ino == *parent || need_root_dotdot == 1)));
2bd0ea18
NS
2134
2135 return res;
2136}