]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/dinode.c
Need to check for __u32 in our own m4 macro instead of using AC_CHECK_TYPES
[thirdparty/xfsprogs-dev.git] / repair / dinode.c
CommitLineData
2bd0ea18 1/*
da23017d
NS
2 * Copyright (c) 2000-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 "agheader.h"
23#include "incore.h"
24#include "protos.h"
25#include "err_protos.h"
26#include "dir.h"
27#include "dir2.h"
28#include "dinode.h"
29#include "scan.h"
30#include "versions.h"
31#include "attr_repair.h"
32#include "bmap.h"
3b6ac903 33#include "threads.h"
2bd0ea18
NS
34
35/*
36 * inode clearing routines
37 */
38
39/*
40 * return the offset into the inode where the attribute fork starts
41 */
42/* ARGSUSED */
43int
44calc_attr_offset(xfs_mount_t *mp, xfs_dinode_t *dino)
45{
46 xfs_dinode_core_t *dinoc = &dino->di_core;
47 int offset = ((__psint_t) &dino->di_u)
48 - (__psint_t)dino;
49
50 /*
51 * don't worry about alignment when calculating offset
52 * because the data fork is already 8-byte aligned
53 */
54 switch (dinoc->di_format) {
55 case XFS_DINODE_FMT_DEV:
63899e27 56 offset += sizeof(xfs_dev_t);
2bd0ea18
NS
57 break;
58 case XFS_DINODE_FMT_LOCAL:
59 offset += INT_GET(dinoc->di_size, ARCH_CONVERT);
60 break;
61 case XFS_DINODE_FMT_UUID:
62 offset += sizeof(uuid_t);
63 break;
64 case XFS_DINODE_FMT_EXTENTS:
65 offset += INT_GET(dinoc->di_nextents, ARCH_CONVERT) * sizeof(xfs_bmbt_rec_32_t);
66 break;
67 case XFS_DINODE_FMT_BTREE:
68 offset += INT_GET(dino->di_u.di_bmbt.bb_numrecs, ARCH_CONVERT) * sizeof(xfs_bmbt_rec_32_t);
69 break;
70 default:
507f4e33 71 do_error(_("Unknown inode format.\n"));
2bd0ea18
NS
72 abort();
73 break;
74 }
75
76 return(offset);
77}
78
79/* ARGSUSED */
80int
81clear_dinode_attr(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_ino_t ino_num)
82{
83 xfs_dinode_core_t *dinoc = &dino->di_core;
84
85 ASSERT(dinoc->di_forkoff != 0);
86
87 if (!no_modify)
507f4e33 88 fprintf(stderr, _("clearing inode %llu attributes\n"),
5b64e00a 89 (unsigned long long)ino_num);
2bd0ea18 90 else
507f4e33 91 fprintf(stderr, _("would have cleared inode %llu attributes\n"),
5b64e00a 92 (unsigned long long)ino_num);
2bd0ea18
NS
93
94 if (INT_GET(dinoc->di_anextents, ARCH_CONVERT) != 0) {
95 if (no_modify)
96 return(1);
46eca962 97 dinoc->di_anextents = 0;
2bd0ea18
NS
98 }
99
100 if (dinoc->di_aformat != XFS_DINODE_FMT_EXTENTS) {
101 if (no_modify)
102 return(1);
103 dinoc->di_aformat = XFS_DINODE_FMT_EXTENTS;
104 }
105
106 /* get rid of the fork by clearing forkoff */
107
108 /* Originally, when the attr repair code was added, the fork was cleared
109 * by turning it into shortform status. This meant clearing the
110 * hdr.totsize/count fields and also changing aformat to LOCAL
111 * (vs EXTENTS). Over various fixes, the aformat and forkoff have
112 * been updated to not show an attribute fork at all, however.
113 * It could be possible that resetting totsize/count are not needed,
dfc130f3 114 * but just to be safe, leave it in for now.
2bd0ea18
NS
115 */
116
117 if (!no_modify) {
118 xfs_attr_shortform_t *asf = (xfs_attr_shortform_t *)
46eca962 119 XFS_DFORK_APTR(dino);
2bd0ea18
NS
120 INT_SET(asf->hdr.totsize, ARCH_CONVERT,
121 sizeof(xfs_attr_sf_hdr_t));
122 INT_SET(asf->hdr.count, ARCH_CONVERT, 0);
123 dinoc->di_forkoff = 0; /* got to do this after asf is set */
124 }
125
126 /*
127 * always returns 1 since the fork gets zapped
128 */
129 return(1);
130}
131
132/* ARGSUSED */
133int
134clear_dinode_core(xfs_dinode_core_t *dinoc, xfs_ino_t ino_num)
135{
136 int dirty = 0;
137
138 if (INT_GET(dinoc->di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) {
139 dirty = 1;
140
141 if (no_modify)
142 return(1);
143
144 INT_SET(dinoc->di_magic, ARCH_CONVERT, XFS_DINODE_MAGIC);
145 }
146
147 if (!XFS_DINODE_GOOD_VERSION(dinoc->di_version) ||
148 (!fs_inode_nlink && dinoc->di_version > XFS_DINODE_VERSION_1)) {
149 dirty = 1;
150
151 if (no_modify)
152 return(1);
153
154 dinoc->di_version = (fs_inode_nlink) ? XFS_DINODE_VERSION_2
155 : XFS_DINODE_VERSION_1;
156 }
157
158 if (INT_GET(dinoc->di_mode, ARCH_CONVERT) != 0) {
159 dirty = 1;
160
161 if (no_modify)
162 return(1);
163
46eca962 164 dinoc->di_mode = 0;
2bd0ea18
NS
165 }
166
167 if (INT_GET(dinoc->di_flags, ARCH_CONVERT) != 0) {
168 dirty = 1;
169
170 if (no_modify)
171 return(1);
172
46eca962 173 dinoc->di_flags = 0;
2bd0ea18
NS
174 }
175
176 if (INT_GET(dinoc->di_dmevmask, ARCH_CONVERT) != 0) {
177 dirty = 1;
178
179 if (no_modify)
180 return(1);
181
46eca962 182 dinoc->di_dmevmask = 0;
2bd0ea18
NS
183 }
184
185 if (dinoc->di_forkoff != 0) {
186 dirty = 1;
187
188 if (no_modify)
189 return(1);
190
191 dinoc->di_forkoff = 0;
192 }
193
194 if (dinoc->di_format != XFS_DINODE_FMT_EXTENTS) {
195 dirty = 1;
196
197 if (no_modify)
198 return(1);
199
200 dinoc->di_format = XFS_DINODE_FMT_EXTENTS;
201 }
202
203 if (dinoc->di_aformat != XFS_DINODE_FMT_EXTENTS) {
204 dirty = 1;
205
206 if (no_modify)
207 return(1);
208
209 dinoc->di_aformat = XFS_DINODE_FMT_EXTENTS;
210 }
211
212 if (INT_GET(dinoc->di_size, ARCH_CONVERT) != 0) {
213 dirty = 1;
214
215 if (no_modify)
216 return(1);
217
46eca962 218 dinoc->di_size = 0;
2bd0ea18
NS
219 }
220
221 if (INT_GET(dinoc->di_nblocks, ARCH_CONVERT) != 0) {
222 dirty = 1;
223
224 if (no_modify)
225 return(1);
226
46eca962 227 dinoc->di_nblocks = 0;
2bd0ea18
NS
228 }
229
230 if (INT_GET(dinoc->di_onlink, ARCH_CONVERT) != 0) {
231 dirty = 1;
232
233 if (no_modify)
234 return(1);
235
46eca962 236 dinoc->di_onlink = 0;
2bd0ea18
NS
237 }
238
239 if (INT_GET(dinoc->di_nextents, ARCH_CONVERT) != 0) {
240 dirty = 1;
241
242 if (no_modify)
243 return(1);
244
46eca962 245 dinoc->di_nextents = 0;
2bd0ea18
NS
246 }
247
248 if (INT_GET(dinoc->di_anextents, ARCH_CONVERT) != 0) {
249 dirty = 1;
250
251 if (no_modify)
252 return(1);
253
46eca962 254 dinoc->di_anextents = 0;
2bd0ea18
NS
255 }
256
257 if (dinoc->di_version > XFS_DINODE_VERSION_1 &&
258 INT_GET(dinoc->di_nlink, ARCH_CONVERT) != 0) {
259 dirty = 1;
260
261 if (no_modify)
262 return(1);
263
46eca962 264 dinoc->di_nlink = 0;
2bd0ea18
NS
265 }
266
267 return(dirty);
268}
269
270/* ARGSUSED */
271int
272clear_dinode_unlinked(xfs_mount_t *mp, xfs_dinode_t *dino)
273{
274
275 if (dino->di_next_unlinked != NULLAGINO) {
276 if (!no_modify)
277 dino->di_next_unlinked = NULLAGINO;
278 return(1);
279 }
280
281 return(0);
282}
283
284/*
285 * this clears the unlinked list too so it should not be called
286 * until after the agi unlinked lists are walked in phase 3.
287 * returns > zero if the inode has been altered while being cleared
288 */
289int
290clear_dinode(xfs_mount_t *mp, xfs_dinode_t *dino, xfs_ino_t ino_num)
291{
292 int dirty;
293
294 dirty = clear_dinode_core(&dino->di_core, ino_num);
295 dirty += clear_dinode_unlinked(mp, dino);
296
297 /* and clear the forks */
298
299 if (dirty && !no_modify)
300 bzero(&dino->di_u, XFS_LITINO(mp));
301
302 return(dirty);
303}
304
305
306/*
307 * misc. inode-related utility routines
308 */
309
1e77098c
MV
310/*
311 * verify_ag_bno is heavily used. In the common case, it
312 * performs just two number of compares
313 */
314static __inline int
315verify_ag_bno(xfs_sb_t *sbp,
316 xfs_agnumber_t agno,
317 xfs_agblock_t agbno)
318{
99a86c52 319 if (agno < (sbp->sb_agcount - 1)) {
1e77098c
MV
320 if (agbno >= sbp->sb_agblocks) {
321 return 1; /* bad */
322 }
323 return 0; /* good */
324 }
99a86c52 325 if (agno == (sbp->sb_agcount - 1)) {
1e77098c
MV
326 if (agbno >=
327 (sbp->sb_dblocks -
328 (sbp->sb_agcount-1) *
329 sbp->sb_agblocks)) {
330 return 1; /* bad */
331 }
332 return 0; /* good */
333 }
334 return 1; /* bad */
335}
336
2bd0ea18
NS
337/*
338 * returns 0 if inode number is valid, 1 if bogus
339 */
340int
341verify_inum(xfs_mount_t *mp,
342 xfs_ino_t ino)
343{
344 xfs_agnumber_t agno;
345 xfs_agino_t agino;
346 xfs_agblock_t agbno;
347 xfs_sb_t *sbp = &mp->m_sb;;
348
349 /* range check ag #, ag block. range-checking offset is pointless */
350
351 agno = XFS_INO_TO_AGNO(mp, ino);
352 agino = XFS_INO_TO_AGINO(mp, ino);
353 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
1e77098c
MV
354 if (agbno == 0)
355 return 1;
2bd0ea18
NS
356
357 if (ino == 0 || ino == NULLFSINO)
358 return(1);
359
360 if (ino != XFS_AGINO_TO_INO(mp, agno, agino))
361 return(1);
362
1e77098c 363 return verify_ag_bno(sbp, agno, agbno);
2bd0ea18
NS
364}
365
366/*
367 * have a separate routine to ensure that we don't accidentally
368 * lose illegally set bits in the agino by turning it into an FSINO
369 * to feed to the above routine
370 */
371int
372verify_aginum(xfs_mount_t *mp,
373 xfs_agnumber_t agno,
374 xfs_agino_t agino)
375{
376 xfs_agblock_t agbno;
377 xfs_sb_t *sbp = &mp->m_sb;;
378
379 /* range check ag #, ag block. range-checking offset is pointless */
380
381 if (agino == 0 || agino == NULLAGINO)
382 return(1);
383
384 /*
385 * agino's can't be too close to NULLAGINO because the min blocksize
386 * is 9 bits and at most 1 bit of that gets used for the inode offset
387 * so if the agino gets shifted by the # of offset bits and compared
388 * to the legal agbno values, a bogus agino will be too large. there
389 * will be extra bits set at the top that shouldn't be set.
390 */
391 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
1e77098c
MV
392 if (agbno == 0)
393 return 1;
2bd0ea18 394
1e77098c 395 return verify_ag_bno(sbp, agno, agbno);
2bd0ea18
NS
396}
397
398/*
399 * return 1 if block number is good, 0 if out of range
400 */
401int
402verify_dfsbno(xfs_mount_t *mp,
403 xfs_dfsbno_t fsbno)
404{
405 xfs_agnumber_t agno;
406 xfs_agblock_t agbno;
407 xfs_sb_t *sbp = &mp->m_sb;;
408
409 /* range check ag #, ag block. range-checking offset is pointless */
410
411 agno = XFS_FSB_TO_AGNO(mp, fsbno);
412 agbno = XFS_FSB_TO_AGBNO(mp, fsbno);
413
1e77098c
MV
414 return verify_ag_bno(sbp, agno, agbno) == 0;
415}
2bd0ea18 416
1e77098c
MV
417#define XR_DFSBNORANGE_VALID 0
418#define XR_DFSBNORANGE_BADSTART 1
419#define XR_DFSBNORANGE_BADEND 2
420#define XR_DFSBNORANGE_OVERFLOW 3
421
422static __inline int
423verify_dfsbno_range(xfs_mount_t *mp,
424 xfs_dfsbno_t fsbno,
425 xfs_dfilblks_t count)
426{
427 xfs_agnumber_t agno;
428 xfs_agblock_t agbno;
429 xfs_sb_t *sbp = &mp->m_sb;;
430
431 /* the start and end blocks better be in the same allocation group */
432 agno = XFS_FSB_TO_AGNO(mp, fsbno);
433 if (agno != XFS_FSB_TO_AGNO(mp, fsbno + count - 1)) {
434 return XR_DFSBNORANGE_OVERFLOW;
435 }
436
437 agbno = XFS_FSB_TO_AGBNO(mp, fsbno);
438 if (verify_ag_bno(sbp, agno, agbno)) {
439 return XR_DFSBNORANGE_BADSTART;
440 }
441
442 agbno = XFS_FSB_TO_AGBNO(mp, fsbno + count - 1);
443 if (verify_ag_bno(sbp, agno, agbno)) {
444 return XR_DFSBNORANGE_BADEND;
445 }
446
447 return (XR_DFSBNORANGE_VALID);
2bd0ea18
NS
448}
449
450int
451verify_agbno(xfs_mount_t *mp,
452 xfs_agnumber_t agno,
453 xfs_agblock_t agbno)
454{
455 xfs_sb_t *sbp = &mp->m_sb;;
456
457 /* range check ag #, ag block. range-checking offset is pointless */
1e77098c 458 return verify_ag_bno(sbp, agno, agbno) == 0;
2bd0ea18
NS
459}
460
461void
462convert_extent(
463 xfs_bmbt_rec_32_t *rp,
464 xfs_dfiloff_t *op, /* starting offset (blockno in file) */
465 xfs_dfsbno_t *sp, /* starting block (fs blockno) */
466 xfs_dfilblks_t *cp, /* blockcount */
467 int *fp) /* extent flag */
468{
469 xfs_bmbt_irec_t irec, *s = &irec;
93cc2301
NS
470 xfs_bmbt_rec_t rpcopy, *p = &rpcopy;
471
472 memcpy(&rpcopy, rp, sizeof(rpcopy));
2bd0ea18 473 /* Just use the extent parsing routine from the kernel */
f9e56f43 474 libxfs_bmbt_disk_get_all(p, s);
2bd0ea18
NS
475
476 if (fs_has_extflgbit) {
477 if (s->br_state == XFS_EXT_UNWRITTEN) {
478 *fp = 1;
479 } else {
480 *fp = 0;
481 }
482 } else {
483 *fp = 0;
484 }
485 *op = s->br_startoff;
486 *sp = s->br_startblock;
487 *cp = s->br_blockcount;
488}
489
490/*
491 * return address of block fblock if it's within the range described
492 * by the extent list. Otherwise, returns a null address.
493 */
494/* ARGSUSED */
495xfs_dfsbno_t
496get_bmbt_reclist(
497 xfs_mount_t *mp,
498 xfs_bmbt_rec_32_t *rp,
499 int numrecs,
500 xfs_dfiloff_t fblock)
501{
502 int i;
503 xfs_dfilblks_t cnt;
504 xfs_dfiloff_t off_bno;
505 xfs_dfsbno_t start;
506 int flag;
507
508 for (i = 0; i < numrecs; i++, rp++) {
509 convert_extent(rp, &off_bno, &start, &cnt, &flag);
510 if (off_bno >= fblock && off_bno + cnt < fblock)
511 return(start + fblock - off_bno);
512 }
513
514 return(NULLDFSBNO);
515}
516
3b6ac903
MV
517/*
518 * process_bmbt_reclist_int is the most compute intensive
519 * function in repair. The following macros reduce the
520 * the large number of lock/unlock steps it would otherwise
521 * call.
522 */
523#define PROCESS_BMBT_DECL(type, var) type var
524
525#define PROCESS_BMBT_LOCK(agno) \
526 if (do_parallel && (agno != locked_agno)) { \
527 if (locked_agno != -1) /* release old ag lock */ \
528 PREPAIR_RW_UNLOCK_NOTEST(&per_ag_lock[locked_agno]); \
529 PREPAIR_RW_WRITE_LOCK_NOTEST(&per_ag_lock[agno]); \
530 locked_agno = agno; \
531 }
532
533#define PROCESS_BMBT_UNLOCK_RETURN(val) \
534 do { \
535 if (locked_agno != -1) \
536 PREPAIR_RW_UNLOCK_NOTEST(&per_ag_lock[locked_agno]); \
537 return (val); \
538 } while (0)
539
2bd0ea18
NS
540/*
541 * return 1 if inode should be cleared, 0 otherwise
542 * if check_dups should be set to 1, that implies that
543 * the primary purpose of this call is to see if the
544 * file overlaps with any duplicate extents (in the
545 * duplicate extent list).
546 */
547/* ARGSUSED */
548int
549process_bmbt_reclist_int(
550 xfs_mount_t *mp,
551 xfs_bmbt_rec_32_t *rp,
552 int numrecs,
553 int type,
554 xfs_ino_t ino,
555 xfs_drfsbno_t *tot,
556 blkmap_t **blkmapp,
557 xfs_dfiloff_t *first_key,
558 xfs_dfiloff_t *last_key,
559 int check_dups,
560 int whichfork)
561{
562 xfs_dfsbno_t b;
563 xfs_drtbno_t ext;
564 xfs_dfilblks_t c; /* count */
565 xfs_dfilblks_t cp = 0; /* prev count */
566 xfs_dfsbno_t s; /* start */
567 xfs_dfsbno_t sp = 0; /* prev start */
568 xfs_dfiloff_t o = 0; /* offset */
569 xfs_dfiloff_t op = 0; /* prev offset */
570 char *ftype;
571 char *forkname;
572 int i;
573 int state;
574 int flag; /* extent flag */
c1281304 575 int pwe; /* partially-written extent */
1e77098c
MV
576 xfs_dfsbno_t e;
577 xfs_agnumber_t agno;
578 xfs_agblock_t agbno;
3b6ac903
MV
579 PROCESS_BMBT_DECL
580 (xfs_agnumber_t, locked_agno=-1);
2bd0ea18
NS
581
582 if (whichfork == XFS_DATA_FORK)
507f4e33 583 forkname = _("data");
2bd0ea18 584 else
507f4e33 585 forkname = _("attr");
2bd0ea18
NS
586
587 if (type == XR_INO_RTDATA)
507f4e33 588 ftype = _("real-time");
2bd0ea18 589 else
507f4e33 590 ftype = _("regular");
2bd0ea18
NS
591
592 for (i = 0; i < numrecs; i++, rp++) {
593 convert_extent(rp, &o, &s, &c, &flag);
594 if (i == 0)
595 *last_key = *first_key = o;
596 else
597 *last_key = o;
598 if (i > 0 && op + cp > o) {
599 do_warn(
507f4e33
NS
600 _("bmap rec out of order, inode %llu entry %d "
601 "[o s c] [%llu %llu %llu], %d [%llu %llu %llu]\n"),
2bd0ea18 602 ino, i, o, s, c, i-1, op, sp, cp);
3b6ac903 603 PROCESS_BMBT_UNLOCK_RETURN(1);
2bd0ea18
NS
604 }
605 op = o;
606 cp = c;
607 sp = s;
608
609 /*
610 * check numeric validity of the extent
611 */
612 if (c == 0) {
613 do_warn(
507f4e33 614 _("zero length extent (off = %llu, fsbno = %llu) in ino %llu\n"),
2bd0ea18 615 o, s, ino);
3b6ac903 616 PROCESS_BMBT_UNLOCK_RETURN(1);
2bd0ea18
NS
617 }
618 if (type == XR_INO_RTDATA) {
619 if (s >= mp->m_sb.sb_rblocks) {
620 do_warn(
507f4e33 621 _("inode %llu - bad rt extent start block number %llu, offset %llu\n"),
2bd0ea18 622 ino, s, o);
3b6ac903 623 PROCESS_BMBT_UNLOCK_RETURN(1);
2bd0ea18
NS
624 }
625 if (s + c - 1 >= mp->m_sb.sb_rblocks) {
626 do_warn(
507f4e33 627 _("inode %llu - bad rt extent last block number %llu, offset %llu\n"),
2bd0ea18 628 ino, s + c - 1, o);
3b6ac903 629 PROCESS_BMBT_UNLOCK_RETURN(1);
2bd0ea18
NS
630 }
631 if (s + c - 1 < s) {
632 do_warn(
507f4e33
NS
633 _("inode %llu - bad rt extent overflows - start %llu, end %llu, "
634 "offset %llu\n"),
2bd0ea18 635 ino, s, s + c - 1, o);
3b6ac903 636 PROCESS_BMBT_UNLOCK_RETURN(1);
2bd0ea18
NS
637 }
638 } else {
1e77098c
MV
639 switch (verify_dfsbno_range(mp, s, c)) {
640 case XR_DFSBNORANGE_VALID:
641 break;
642 case XR_DFSBNORANGE_BADSTART:
2bd0ea18 643 do_warn(
507f4e33 644 _("inode %llu - bad extent starting block number %llu, offset %llu\n"),
2bd0ea18 645 ino, s, o);
3b6ac903 646 PROCESS_BMBT_UNLOCK_RETURN(1);
1e77098c 647 case XR_DFSBNORANGE_BADEND:
2bd0ea18 648 do_warn(
507f4e33 649 _("inode %llu - bad extent last block number %llu, offset %llu\n"),
2bd0ea18 650 ino, s + c - 1, o);
3b6ac903 651 PROCESS_BMBT_UNLOCK_RETURN(1);
1e77098c 652 case XR_DFSBNORANGE_OVERFLOW:
2bd0ea18 653 do_warn(
1e77098c 654
507f4e33
NS
655 _("inode %llu - bad extent overflows - start %llu, end %llu, "
656 "offset %llu\n"),
2bd0ea18 657 ino, s, s + c - 1, o);
3b6ac903 658 PROCESS_BMBT_UNLOCK_RETURN(1);
2bd0ea18
NS
659 }
660 if (o >= fs_max_file_offset) {
661 do_warn(
507f4e33
NS
662 _("inode %llu - extent offset too large - start %llu, count %llu, "
663 "offset %llu\n"),
2bd0ea18 664 ino, s, c, o);
3b6ac903 665 PROCESS_BMBT_UNLOCK_RETURN(1);
2bd0ea18
NS
666 }
667 }
668
669 /*
670 * realtime file data fork
671 */
672 if (type == XR_INO_RTDATA && whichfork == XFS_DATA_FORK) {
673 /*
674 * XXX - verify that the blocks listed in the record
675 * are multiples of an extent
676 */
218c4496
NS
677 if (XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb) == 0
678 && (s % mp->m_sb.sb_rextsize != 0 ||
679 c % mp->m_sb.sb_rextsize != 0)) {
2bd0ea18 680 do_warn(
507f4e33 681 _("malformed rt inode extent [%llu %llu] (fs rtext size = %u)\n"),
2bd0ea18 682 s, c, mp->m_sb.sb_rextsize);
3b6ac903 683 PROCESS_BMBT_UNLOCK_RETURN(1);
2bd0ea18
NS
684 }
685
686 /*
687 * XXX - set the appropriate number of extents
688 */
689 for (b = s; b < s + c; b += mp->m_sb.sb_rextsize) {
690 ext = (xfs_drtbno_t) b / mp->m_sb.sb_rextsize;
c1281304
GO
691 if (XFS_SB_VERSION_HASEXTFLGBIT(&mp->m_sb) &&
692 flag && (b % mp->m_sb.sb_rextsize != 0)) {
693 pwe = 1;
694 } else {
695 pwe = 0;
696 }
2bd0ea18
NS
697
698 if (check_dups == 1) {
c1281304
GO
699 if (search_rt_dup_extent(mp, ext) &&
700 !pwe) {
2bd0ea18 701 do_warn(
507f4e33
NS
702 _("data fork in rt ino %llu claims dup rt extent, off - %llu, "
703 "start - %llu, count %llu\n"),
2bd0ea18 704 ino, o, s, c);
3b6ac903 705 PROCESS_BMBT_UNLOCK_RETURN(1);
2bd0ea18
NS
706 }
707 continue;
708 }
709
710 state = get_rtbno_state(mp, ext);
711
712 switch (state) {
713 case XR_E_FREE:
714/* XXX - turn this back on after we
715 run process_rtbitmap() in phase2
716 do_warn(
507f4e33 717 _("%s fork in rt ino %llu claims free rt block %llu\n"),
2bd0ea18
NS
718 forkname, ino, ext);
719*/
720 /* fall through ... */
721 case XR_E_UNKNOWN:
722 set_rtbno_state(mp, ext, XR_E_INUSE);
723 break;
724 case XR_E_BAD_STATE:
725 do_error(
507f4e33 726 _("bad state in rt block map %llu\n"), ext);
2bd0ea18
NS
727 abort();
728 break;
729 case XR_E_FS_MAP:
730 case XR_E_INO:
731 case XR_E_INUSE_FS:
732 do_error(
507f4e33 733 _("%s fork in rt inode %llu found metadata block %llu in %s bmap\n"),
2bd0ea18
NS
734 forkname, ino, ext, ftype);
735 case XR_E_INUSE:
c1281304
GO
736 if (pwe)
737 break;
2bd0ea18
NS
738 case XR_E_MULT:
739 set_rtbno_state(mp, ext, XR_E_MULT);
740 do_warn(
507f4e33 741 _("%s fork in rt inode %llu claims used rt block %llu\n"),
2bd0ea18 742 forkname, ino, ext);
3b6ac903 743 PROCESS_BMBT_UNLOCK_RETURN(1);
2bd0ea18
NS
744 case XR_E_FREE1:
745 default:
746 do_error(
507f4e33 747 _("illegal state %d in %s block map %llu\n"),
2bd0ea18
NS
748 state, ftype, b);
749 }
750 }
751
752 /*
753 * bump up the block counter
754 */
755 *tot += c;
756
757 /*
758 * skip rest of loop processing since that's
759 * all for regular file forks and attr forks
760 */
761 continue;
762 }
763
dfc130f3 764
2bd0ea18
NS
765 /*
766 * regular file data fork or attribute fork
767 */
768 if (blkmapp && *blkmapp)
769 blkmap_set_ext(blkmapp, o, s, c);
1e77098c
MV
770 /*
771 * Profiling shows that the following loop takes the
772 * most time in all of xfs_repair.
773 */
774 agno = XFS_FSB_TO_AGNO(mp, s);
775 agbno = XFS_FSB_TO_AGBNO(mp, s);
776 e = s + c;
3b6ac903 777 PROCESS_BMBT_LOCK(agno);
1e77098c 778 for (b = s; b < e; b++, agbno++) {
2bd0ea18
NS
779 if (check_dups == 1) {
780 /*
781 * if we're just checking the bmap for dups,
782 * return if we find one, otherwise, continue
783 * checking each entry without setting the
784 * block bitmap
785 */
1e77098c 786 if (search_dup_extent(mp, agno, agbno)) {
2bd0ea18 787 do_warn(
507f4e33
NS
788 _("%s fork in ino %llu claims dup extent, off - %llu, "
789 "start - %llu, cnt %llu\n"),
2bd0ea18 790 forkname, ino, o, s, c);
3b6ac903 791 PROCESS_BMBT_UNLOCK_RETURN(1);
2bd0ea18
NS
792 }
793 continue;
794 }
795
dfc130f3 796 /* FIX FOR BUG 653709 -- EKN
2bd0ea18 797 * realtime attribute fork, should be valid block number
dfc130f3 798 * in regular data space, not realtime partion.
2bd0ea18 799 */
dfc130f3 800 if (type == XR_INO_RTDATA && whichfork == XFS_ATTR_FORK) {
1e77098c 801 if (mp->m_sb.sb_agcount < agno)
3b6ac903 802 PROCESS_BMBT_UNLOCK_RETURN(1);
dfc130f3
RC
803 }
804
1e77098c
MV
805 /* Process in chunks of 16 (XR_BB_UNIT/XR_BB)
806 * for common XR_E_UNKNOWN to XR_E_INUSE transition
807 */
808 if (((agbno & XR_BB_MASK) == 0) && ((s + c - b) >= (XR_BB_UNIT/XR_BB))) {
809 if (ba_bmap[agno][agbno>>XR_BB] == XR_E_UNKNOWN_LL) {
810 ba_bmap[agno][agbno>>XR_BB] = XR_E_INUSE_LL;
811 agbno += (XR_BB_UNIT/XR_BB) - 1;
812 b += (XR_BB_UNIT/XR_BB) - 1;
813 continue;
814 }
815
816 }
817
818 state = get_agbno_state(mp, agno, agbno);
2bd0ea18
NS
819 switch (state) {
820 case XR_E_FREE:
821 case XR_E_FREE1:
822 do_warn(
507f4e33 823 _("%s fork in ino %llu claims free block %llu\n"),
2bd0ea18
NS
824 forkname, ino, (__uint64_t) b);
825 /* fall through ... */
826 case XR_E_UNKNOWN:
1e77098c 827 set_agbno_state(mp, agno, agbno, XR_E_INUSE);
2bd0ea18
NS
828 break;
829 case XR_E_BAD_STATE:
507f4e33 830 do_error(_("bad state in block map %llu\n"), b);
2bd0ea18
NS
831 abort();
832 break;
833 case XR_E_FS_MAP:
834 case XR_E_INO:
835 case XR_E_INUSE_FS:
836 do_warn(
507f4e33 837 _("%s fork in inode %llu claims metadata block %llu\n"),
2bd0ea18 838 forkname, ino, (__uint64_t) b);
3b6ac903 839 PROCESS_BMBT_UNLOCK_RETURN(1);
2bd0ea18
NS
840 case XR_E_INUSE:
841 case XR_E_MULT:
1e77098c 842 set_agbno_state(mp, agno, agbno, XR_E_MULT);
2bd0ea18 843 do_warn(
507f4e33 844 _("%s fork in %s inode %llu claims used block %llu\n"),
2bd0ea18 845 forkname, ftype, ino, (__uint64_t) b);
3b6ac903 846 PROCESS_BMBT_UNLOCK_RETURN(1);
2bd0ea18 847 default:
507f4e33
NS
848 do_error(
849 _("illegal state %d in block map %llu\n"),
2bd0ea18
NS
850 state, b);
851 abort();
852 }
853 }
854 *tot += c;
855 }
856
3b6ac903 857 PROCESS_BMBT_UNLOCK_RETURN(0);
2bd0ea18
NS
858}
859
860/*
861 * return 1 if inode should be cleared, 0 otherwise, sets block bitmap
862 * as a side-effect
863 */
864int
865process_bmbt_reclist(
866 xfs_mount_t *mp,
867 xfs_bmbt_rec_32_t *rp,
868 int numrecs,
869 int type,
870 xfs_ino_t ino,
871 xfs_drfsbno_t *tot,
872 blkmap_t **blkmapp,
873 xfs_dfiloff_t *first_key,
874 xfs_dfiloff_t *last_key,
875 int whichfork)
876{
877 return(process_bmbt_reclist_int(mp, rp, numrecs, type, ino, tot,
878 blkmapp, first_key, last_key, 0,
879 whichfork));
880}
881
882/*
883 * return 1 if inode should be cleared, 0 otherwise, does not set
884 * block bitmap
885 */
886int
887scan_bmbt_reclist(
888 xfs_mount_t *mp,
889 xfs_bmbt_rec_32_t *rp,
890 int numrecs,
891 int type,
892 xfs_ino_t ino,
893 xfs_drfsbno_t *tot,
894 int whichfork)
895{
896 xfs_dfiloff_t first_key = 0;
897 xfs_dfiloff_t last_key = 0;
898
899 return(process_bmbt_reclist_int(mp, rp, numrecs, type, ino, tot,
900 NULL, &first_key, &last_key, 1,
901 whichfork));
902}
903
904/*
905 * these two are meant for routines that read and work with inodes
906 * one at a time where the inodes may be in any order (like walking
907 * the unlinked lists to look for inodes). the caller is responsible
908 * for writing/releasing the buffer.
909 */
910xfs_buf_t *
911get_agino_buf(xfs_mount_t *mp,
912 xfs_agnumber_t agno,
913 xfs_agino_t agino,
914 xfs_dinode_t **dipp)
915{
916 ino_tree_node_t *irec;
917 xfs_buf_t *bp;
918 int size;
919
920 if ((irec = find_inode_rec(agno, agino)) == NULL)
921 return(NULL);
dfc130f3 922
2bd0ea18
NS
923 size = XFS_FSB_TO_BB(mp, MAX(1, XFS_INODES_PER_CHUNK/inodes_per_block));
924 bp = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno,
925 XFS_AGINO_TO_AGBNO(mp, irec->ino_startnum)), size, 0);
926 if (!bp) {
507f4e33 927 do_warn(_("cannot read inode (%u/%u), disk block %lld\n"),
2bd0ea18
NS
928 agno, irec->ino_startnum,
929 XFS_AGB_TO_DADDR(mp, agno,
930 XFS_AGINO_TO_AGBNO(mp, irec->ino_startnum)));
931 return(NULL);
932 }
933
934 *dipp = XFS_MAKE_IPTR(mp, bp, agino -
935 XFS_OFFBNO_TO_AGINO(mp, XFS_AGINO_TO_AGBNO(mp,
936 irec->ino_startnum),
937 0));
938
939 return(bp);
940}
941
942/*
943 * these next routines return the filesystem blockno of the
944 * block containing the block "bno" in the file whose bmap
945 * tree (or extent list) is rooted by "rootblock".
946 *
947 * the next routines are utility routines for the third
948 * routine, get_bmapi().
949 */
950/* ARGSUSED */
951xfs_dfsbno_t
952getfunc_extlist(xfs_mount_t *mp,
953 xfs_ino_t ino,
954 xfs_dinode_t *dip,
955 xfs_dfiloff_t bno,
956 int whichfork)
957{
958 xfs_dfiloff_t fbno;
959 xfs_dfilblks_t bcnt;
960 xfs_dfsbno_t fsbno;
961 xfs_dfsbno_t final_fsbno = NULLDFSBNO;
962 xfs_bmbt_rec_32_t *rootblock = (xfs_bmbt_rec_32_t *)
46eca962
NS
963 XFS_DFORK_PTR(dip, whichfork);
964 xfs_extnum_t nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
2bd0ea18
NS
965 int i;
966 int flag;
967
968 for (i = 0; i < nextents; i++) {
969 convert_extent(rootblock + i, &fbno, &fsbno, &bcnt, &flag);
970
971 if (fbno <= bno && bno < fbno + bcnt) {
972 final_fsbno = bno - fbno + fsbno;
973 break;
974 }
975 }
976
977 return(final_fsbno);
978}
979
980xfs_dfsbno_t
981getfunc_btree(xfs_mount_t *mp,
982 xfs_ino_t ino,
983 xfs_dinode_t *dip,
984 xfs_dfiloff_t bno,
985 int whichfork)
986{
987 int i;
1e77098c 988#ifdef DEBUG
2bd0ea18 989 int prev_level;
1e77098c 990#endif
2bd0ea18
NS
991 int flag;
992 int found;
993 xfs_bmbt_rec_32_t *rec;
994 xfs_bmbt_ptr_t *pp;
995 xfs_bmbt_key_t *key;
996 xfs_bmdr_key_t *rkey;
997 xfs_bmdr_ptr_t *rp;
998 xfs_dfiloff_t fbno;
999 xfs_dfsbno_t fsbno;
1000 xfs_dfilblks_t bcnt;
1001 xfs_buf_t *bp;
1002 xfs_dfsbno_t final_fsbno = NULLDFSBNO;
1003 xfs_bmbt_block_t *block;
1004 xfs_bmdr_block_t *rootblock = (xfs_bmdr_block_t *)
46eca962 1005 XFS_DFORK_PTR(dip, whichfork);
2bd0ea18
NS
1006
1007 ASSERT(rootblock->bb_level != 0);
1008 /*
1009 * deal with root block, it's got a slightly different
1010 * header structure than interior nodes. We know that
1011 * a btree should have at least 2 levels otherwise it
1012 * would be an extent list.
1013 */
1014 rkey = XFS_BTREE_KEY_ADDR(
46eca962 1015 XFS_DFORK_SIZE(dip, mp, whichfork),
2bd0ea18 1016 xfs_bmdr, rootblock, 1,
46eca962
NS
1017 XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE(dip,
1018 mp, whichfork),
2bd0ea18
NS
1019 xfs_bmdr, 1));
1020 rp = XFS_BTREE_PTR_ADDR(
46eca962 1021 XFS_DFORK_SIZE(dip, mp, whichfork),
2bd0ea18 1022 xfs_bmdr, rootblock, 1,
46eca962
NS
1023 XFS_BTREE_BLOCK_MAXRECS(XFS_DFORK_SIZE(dip,
1024 mp, whichfork),
2bd0ea18
NS
1025 xfs_bmdr, 1));
1026 for (found = -1, i = 0; i < rootblock->bb_numrecs - 1; i++) {
1027 if (rkey[i].br_startoff <= bno
1028 && bno < rkey[i+1].br_startoff) {
1029 found = i;
1030 break;
1031 }
1032 }
1033 if (i == rootblock->bb_numrecs - 1 && bno >= rkey[i].br_startoff)
1034 found = i;
1035
1036 ASSERT(found != -1);
1037
1038 fsbno = INT_GET(rp[found], ARCH_CONVERT);
1039
1040 ASSERT(verify_dfsbno(mp, fsbno));
1041
1042 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
1043 XFS_FSB_TO_BB(mp, 1), 0);
1044 if (!bp) {
507f4e33 1045 do_error(_("cannot read bmap block %llu\n"), fsbno);
2bd0ea18
NS
1046 return(NULLDFSBNO);
1047 }
1048 block = XFS_BUF_TO_BMBT_BLOCK(bp);
1049
1050 /*
1051 * ok, now traverse any interior btree nodes
1052 */
1e77098c
MV
1053#ifdef DEBUG
1054 prev_level = INT_GET(block->bb_level, ARCH_CONVERT);
1055#endif
2bd0ea18
NS
1056
1057 while (INT_GET(block->bb_level, ARCH_CONVERT) > 0) {
1e77098c 1058#ifdef DEBUG
2bd0ea18
NS
1059 ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) < prev_level);
1060
1061 prev_level = INT_GET(block->bb_level, ARCH_CONVERT);
1e77098c 1062#endif
2bd0ea18
NS
1063
1064 if (INT_GET(block->bb_numrecs, ARCH_CONVERT) >
1065 mp->m_bmap_dmxr[1]) {
507f4e33
NS
1066 do_warn(_("# of bmap records in inode %llu exceeds max "
1067 "(%u, max - %u)\n"),
2bd0ea18
NS
1068 ino, INT_GET(block->bb_numrecs, ARCH_CONVERT),
1069 mp->m_bmap_dmxr[1]);
1070 libxfs_putbuf(bp);
1071 return(NULLDFSBNO);
1072 }
1073 if (verbose && INT_GET(block->bb_numrecs, ARCH_CONVERT) <
1074 mp->m_bmap_dmnr[1]) {
507f4e33
NS
1075 do_warn(_("- # of bmap records in inode %llu less than "
1076 "minimum (%u, min - %u), proceeding ...\n"),
2bd0ea18
NS
1077 ino, INT_GET(block->bb_numrecs, ARCH_CONVERT),
1078 mp->m_bmap_dmnr[1]);
1079 }
1080 key = XFS_BTREE_KEY_ADDR(mp->m_sb.sb_blocksize,
1081 xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]);
1082 pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize,
1083 xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]);
1084 for ( found = -1, i = 0;
1085 i < INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1;
1086 i++) {
1087 if (INT_GET(key[i].br_startoff, ARCH_CONVERT) <= bno &&
1088 bno < INT_GET(key[i+1].br_startoff, ARCH_CONVERT)) {
1089 found = i;
1090 break;
1091 }
1092 }
1093 if (i == INT_GET(block->bb_numrecs, ARCH_CONVERT) - 1 &&
1094 bno >= INT_GET(key[i].br_startoff, ARCH_CONVERT))
1095 found = i;
1096
1097 ASSERT(found != -1);
1098 fsbno = INT_GET(pp[found], ARCH_CONVERT);
1099
1100 ASSERT(verify_dfsbno(mp, fsbno));
1101
1102 /*
1103 * release current btree block and read in the
1104 * next btree block to be traversed
1105 */
1106 libxfs_putbuf(bp);
1107 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
1108 XFS_FSB_TO_BB(mp, 1), 0);
1109 if (!bp) {
507f4e33 1110 do_error(_("cannot read bmap block %llu\n"), fsbno);
2bd0ea18
NS
1111 return(NULLDFSBNO);
1112 }
1113 block = XFS_BUF_TO_BMBT_BLOCK(bp);
1114 }
1115
1116 /*
1117 * current block must be a leaf block
1118 */
1119 ASSERT(INT_GET(block->bb_level, ARCH_CONVERT) == 0);
1120 if (INT_GET(block->bb_numrecs, ARCH_CONVERT) > mp->m_bmap_dmxr[0]) {
507f4e33
NS
1121 do_warn(_("# of bmap records in inode %llu greater than "
1122 "maximum (%u, max - %u)\n"),
2bd0ea18
NS
1123 ino, INT_GET(block->bb_numrecs, ARCH_CONVERT),
1124 mp->m_bmap_dmxr[0]);
1125 libxfs_putbuf(bp);
1126 return(NULLDFSBNO);
1127 }
1128 if (verbose && INT_GET(block->bb_numrecs, ARCH_CONVERT) <
1129 mp->m_bmap_dmnr[0])
507f4e33
NS
1130 do_warn(_("- # of bmap records in inode %llu less than minimum "
1131 "(%u, min - %u), continuing...\n"),
2bd0ea18
NS
1132 ino, INT_GET(block->bb_numrecs, ARCH_CONVERT),
1133 mp->m_bmap_dmnr[0]);
1134
1135 rec = (xfs_bmbt_rec_32_t *)XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize,
1136 xfs_bmbt, block, 1, mp->m_bmap_dmxr[0]);
1137 for (i = 0; i < INT_GET(block->bb_numrecs, ARCH_CONVERT); i++) {
1138 convert_extent(rec + i, &fbno, &fsbno, &bcnt, &flag);
1139
1140 if (fbno <= bno && bno < fbno + bcnt) {
1141 final_fsbno = bno - fbno + fsbno;
1142 break;
1143 }
1144 }
1145 libxfs_putbuf(bp);
1146
1147 if (final_fsbno == NULLDFSBNO)
507f4e33 1148 do_warn(_("could not map block %llu\n"), bno);
2bd0ea18
NS
1149
1150 return(final_fsbno);
1151}
1152
1153/*
1154 * this could be smarter. maybe we should have an open inode
1155 * routine that would get the inode buffer and return back
1156 * an inode handle. I'm betting for the moment that this
1157 * is used only by the directory and attribute checking code
1158 * and that the avl tree find and buffer cache search are
1159 * relatively cheap. If they're too expensive, we'll just
1160 * have to fix this and add an inode handle to the da btree
1161 * cursor.
1162 *
1163 * caller is responsible for checking doubly referenced blocks
1164 * and references to holes
1165 */
1166xfs_dfsbno_t
1167get_bmapi(xfs_mount_t *mp, xfs_dinode_t *dino_p,
1168 xfs_ino_t ino_num, xfs_dfiloff_t bno, int whichfork)
1169{
1170 xfs_dfsbno_t fsbno;
1171
46eca962 1172 switch (XFS_DFORK_FORMAT(dino_p, whichfork)) {
2bd0ea18
NS
1173 case XFS_DINODE_FMT_EXTENTS:
1174 fsbno = getfunc_extlist(mp, ino_num, dino_p, bno, whichfork);
1175 break;
1176 case XFS_DINODE_FMT_BTREE:
dfc130f3 1177 fsbno = getfunc_btree(mp, ino_num, dino_p, bno, whichfork);
2bd0ea18
NS
1178 break;
1179 case XFS_DINODE_FMT_LOCAL:
507f4e33
NS
1180 do_error(_("get_bmapi() called for local inode %llu\n"),
1181 ino_num);
2bd0ea18
NS
1182 fsbno = NULLDFSBNO;
1183 break;
1184 default:
1185 /*
1186 * shouldn't happen
1187 */
507f4e33 1188 do_error(_("bad inode format for inode %llu\n"), ino_num);
2bd0ea18
NS
1189 fsbno = NULLDFSBNO;
1190 }
1191
1192 return(fsbno);
1193}
1194
1195/*
1196 * higher level inode processing stuff starts here:
1197 * first, one utility routine for each type of inode
1198 */
1199
1200/*
1201 * return 1 if inode should be cleared, 0 otherwise
1202 */
1203/* ARGSUSED */
1204int
1205process_btinode(
1206 xfs_mount_t *mp,
1207 xfs_agnumber_t agno,
1208 xfs_agino_t ino,
1209 xfs_dinode_t *dip,
1210 int type,
1211 int *dirty,
1212 xfs_drfsbno_t *tot,
1213 __uint64_t *nex,
1214 blkmap_t **blkmapp,
1215 int whichfork,
1216 int check_dups)
1217{
1218 xfs_bmdr_block_t *dib;
1219 xfs_dfiloff_t last_key;
1220 xfs_dfiloff_t first_key = 0;
1221 xfs_ino_t lino;
1222 xfs_bmbt_ptr_t *pp;
1223 xfs_bmbt_key_t *pkey;
1224 char *forkname;
1225 int i;
1226 bmap_cursor_t cursor;
1227
46eca962 1228 dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
2bd0ea18
NS
1229 lino = XFS_AGINO_TO_INO(mp, agno, ino);
1230 *tot = 0;
1231 *nex = 0;
1232
1233 if (whichfork == XFS_DATA_FORK)
507f4e33 1234 forkname = _("data");
2bd0ea18 1235 else
507f4e33 1236 forkname = _("attr");
2bd0ea18
NS
1237
1238 if (INT_GET(dib->bb_level, ARCH_CONVERT) == 0) {
1239 /*
1240 * This should never happen since a btree inode
1241 * has to have at least one other block in the
1242 * bmap in addition to the root block in the
1243 * inode's data fork.
1244 *
1245 * XXX - if we were going to fix up the inode,
1246 * we'd try to treat the fork as an interior
1247 * node and see if we could get an accurate
1248 * level value from one of the blocks pointed
1249 * to by the pointers in the fork. For now
1250 * though, we just bail (and blow out the inode).
1251 */
507f4e33 1252 do_warn(_("bad level 0 in inode %llu bmap btree root block\n"),
2bd0ea18
NS
1253 XFS_AGINO_TO_INO(mp, agno, ino));
1254 return(1);
1255 }
1256 /*
1257 * use bmdr/dfork_dsize since the root block is in the data fork
1258 */
1259 init_bm_cursor(&cursor, INT_GET(dib->bb_level, ARCH_CONVERT) + 1);
1260
1261 if (XFS_BMDR_SPACE_CALC(INT_GET(dib->bb_numrecs, ARCH_CONVERT)) >
1262 ((whichfork == XFS_DATA_FORK) ?
46eca962
NS
1263 XFS_DFORK_DSIZE(dip, mp) :
1264 XFS_DFORK_ASIZE(dip, mp))) {
2bd0ea18 1265 do_warn(
507f4e33
NS
1266 _("indicated size of %s btree root (%d bytes) greater than space in "
1267 "inode %llu %s fork\n"),
1268 forkname, XFS_BMDR_SPACE_CALC(INT_GET(dib->bb_numrecs,
1269 ARCH_CONVERT)),
2bd0ea18
NS
1270 lino, forkname);
1271 return(1);
1272 }
1273
507f4e33 1274 pp = XFS_BTREE_PTR_ADDR(
46eca962 1275 XFS_DFORK_SIZE(dip, mp, whichfork),
2bd0ea18 1276 xfs_bmdr, dib, 1,
507f4e33 1277 XFS_BTREE_BLOCK_MAXRECS(
46eca962 1278 XFS_DFORK_SIZE(dip, mp, whichfork),
2bd0ea18 1279 xfs_bmdr, 0));
507f4e33 1280 pkey = XFS_BTREE_KEY_ADDR(
46eca962 1281 XFS_DFORK_SIZE(dip, mp, whichfork),
2bd0ea18 1282 xfs_bmdr, dib, 1,
507f4e33 1283 XFS_BTREE_BLOCK_MAXRECS(
46eca962 1284 XFS_DFORK_SIZE(dip, mp, whichfork),
2bd0ea18
NS
1285 xfs_bmdr, 0));
1286
1287 last_key = NULLDFILOFF;
1288
1289 for (i = 0; i < INT_GET(dib->bb_numrecs, ARCH_CONVERT); i++) {
1290 /*
1291 * XXX - if we were going to do more to fix up the inode
1292 * btree, we'd do it right here. For now, if there's a
1293 * problem, we'll bail out and presumably clear the inode.
1294 */
1295 if (!verify_dfsbno(mp, INT_GET(pp[i], ARCH_CONVERT))) {
507f4e33 1296 do_warn(_("bad bmap btree ptr 0x%llx in ino %llu\n"),
2bd0ea18
NS
1297 INT_GET(pp[i], ARCH_CONVERT), lino);
1298 return(1);
1299 }
1300
1301 if (scan_lbtree((xfs_dfsbno_t)INT_GET(pp[i], ARCH_CONVERT), INT_GET(dib->bb_level, ARCH_CONVERT),
1302 scanfunc_bmap, type, whichfork,
1303 lino, tot, nex, blkmapp, &cursor,
1304 1, check_dups))
1305 return(1);
1306 /*
1307 * fix key (offset) mismatches between the keys in root
1308 * block records and the first key of each child block.
1309 * fixes cases where entries have been shifted between
1310 * blocks but the parent hasn't been updated
1311 */
1312 if (check_dups == 0 &&
507f4e33
NS
1313 cursor.level[INT_GET(dib->bb_level,
1314 ARCH_CONVERT)-1].first_key !=
1315 INT_GET(pkey[i].br_startoff, ARCH_CONVERT)) {
2bd0ea18
NS
1316 if (!no_modify) {
1317 do_warn(
507f4e33
NS
1318 _("correcting key in bmbt root (was %llu, now %llu) in inode "
1319 "%llu %s fork\n"),
1320 INT_GET(pkey[i].br_startoff,
1321 ARCH_CONVERT),
1322 cursor.level[INT_GET(dib->bb_level,
1323 ARCH_CONVERT)-1].first_key,
2bd0ea18
NS
1324 XFS_AGINO_TO_INO(mp, agno, ino),
1325 forkname);
1326 *dirty = 1;
507f4e33
NS
1327 INT_SET(pkey[i].br_startoff, ARCH_CONVERT,
1328 cursor.level[INT_GET(dib->bb_level,
1329 ARCH_CONVERT)-1].first_key);
2bd0ea18
NS
1330 } else {
1331 do_warn(
507f4e33
NS
1332 _("bad key in bmbt root (is %llu, would reset to %llu) in inode "
1333 "%llu %s fork\n"),
1334 INT_GET(pkey[i].br_startoff,
1335 ARCH_CONVERT),
1336 cursor.level[INT_GET(dib->bb_level,
1337 ARCH_CONVERT)-1].first_key,
2bd0ea18
NS
1338 XFS_AGINO_TO_INO(mp, agno, ino),
1339 forkname);
1340 }
1341 }
1342 /*
1343 * make sure that keys are in ascending order. blow out
1344 * inode if the ordering doesn't hold
1345 */
1346 if (check_dups == 0) {
1347 if (last_key != NULLDFILOFF && last_key >=
507f4e33
NS
1348 cursor.level[INT_GET(dib->bb_level,
1349 ARCH_CONVERT)-1].first_key) {
2bd0ea18 1350 do_warn(
507f4e33 1351 _("out of order bmbt root key %llu in inode %llu %s fork\n"),
2bd0ea18
NS
1352 first_key,
1353 XFS_AGINO_TO_INO(mp, agno, ino),
1354 forkname);
1355 return(1);
1356 }
507f4e33
NS
1357 last_key = cursor.level[INT_GET(dib->bb_level,
1358 ARCH_CONVERT)-1].first_key;
2bd0ea18
NS
1359 }
1360 }
1361 /*
1362 * Check that the last child block's forward sibling pointer
1363 * is NULL.
1364 */
1365 if (check_dups == 0 &&
1366 cursor.level[0].right_fsbno != NULLDFSBNO) {
1367 do_warn(
507f4e33 1368 _("bad fwd (right) sibling pointer (saw %llu should be NULLDFSBNO)\n"),
2bd0ea18
NS
1369 cursor.level[0].right_fsbno);
1370 do_warn(
507f4e33 1371 _("\tin inode %u (%s fork) bmap btree block %llu\n"),
2bd0ea18
NS
1372 XFS_AGINO_TO_INO(mp, agno, ino), forkname,
1373 cursor.level[0].fsbno);
1374 return(1);
1375 }
dfc130f3 1376
2bd0ea18
NS
1377 return(0);
1378}
1379
1380/*
1381 * return 1 if inode should be cleared, 0 otherwise
1382 */
1383/* ARGSUSED */
1384int
1385process_exinode(
1386 xfs_mount_t *mp,
1387 xfs_agnumber_t agno,
1388 xfs_agino_t ino,
1389 xfs_dinode_t *dip,
1390 int type,
1391 int *dirty,
1392 xfs_drfsbno_t *tot,
1393 __uint64_t *nex,
1394 blkmap_t **blkmapp,
1395 int whichfork,
1396 int check_dups)
1397{
1398 xfs_ino_t lino;
1399 xfs_bmbt_rec_32_t *rp;
1400 xfs_dfiloff_t first_key;
1401 xfs_dfiloff_t last_key;
1402
1403 lino = XFS_AGINO_TO_INO(mp, agno, ino);
46eca962 1404 rp = (xfs_bmbt_rec_32_t *)XFS_DFORK_PTR(dip, whichfork);
2bd0ea18 1405 *tot = 0;
46eca962 1406 *nex = XFS_DFORK_NEXTENTS(dip, whichfork);
2bd0ea18
NS
1407 /*
1408 * XXX - if we were going to fix up the btree record,
1409 * we'd do it right here. For now, if there's a problem,
1410 * we'll bail out and presumably clear the inode.
1411 */
1412 if (check_dups == 0)
1413 return(process_bmbt_reclist(mp, rp, *nex, type, lino,
1414 tot, blkmapp, &first_key, &last_key,
1415 whichfork));
1416 else
1417 return(scan_bmbt_reclist(mp, rp, *nex, type, lino, tot,
1418 whichfork));
1419}
1420
1421/*
1422 * return 1 if inode should be cleared, 0 otherwise
1423 */
1424/* ARGSUSED */
1425int
1426process_lclinode(
1427 xfs_mount_t *mp,
1428 xfs_agnumber_t agno,
1429 xfs_agino_t ino,
1430 xfs_dinode_t *dip,
1431 int type,
1432 int *dirty,
1433 xfs_drfsbno_t *tot,
1434 __uint64_t *nex,
1435 blkmap_t **blkmapp,
1436 int whichfork,
1437 int check_dups)
1438{
1439 xfs_attr_shortform_t *asf;
1440 xfs_dinode_core_t *dic;
1441 xfs_ino_t lino;
1442
1443 *tot = 0;
1444 *nex = 0; /* local inodes have 0 extents */
1445
1446 dic = &dip->di_core;
1447 lino = XFS_AGINO_TO_INO(mp, agno, ino);
1448 if (whichfork == XFS_DATA_FORK &&
507f4e33 1449 INT_GET(dic->di_size, ARCH_CONVERT) >
46eca962 1450 XFS_DFORK_DSIZE(dip, mp)) {
2bd0ea18 1451 do_warn(
507f4e33
NS
1452 _("local inode %llu data fork is too large (size = %lld, max = %d)\n"),
1453 lino, INT_GET(dic->di_size, ARCH_CONVERT),
46eca962 1454 XFS_DFORK_DSIZE(dip, mp));
2bd0ea18
NS
1455 return(1);
1456 } else if (whichfork == XFS_ATTR_FORK) {
507f4e33 1457 asf = (xfs_attr_shortform_t *)
46eca962 1458 XFS_DFORK_APTR(dip);
507f4e33 1459 if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) >
46eca962 1460 XFS_DFORK_ASIZE(dip, mp)) {
2bd0ea18 1461 do_warn(
507f4e33
NS
1462 _("local inode %llu attr fork too large (size %d, max = %d)\n"),
1463 lino, INT_GET(asf->hdr.totsize, ARCH_CONVERT),
46eca962 1464 XFS_DFORK_ASIZE(dip, mp));
2bd0ea18
NS
1465 return(1);
1466 }
507f4e33
NS
1467 if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) <
1468 sizeof(xfs_attr_sf_hdr_t)) {
2bd0ea18 1469 do_warn(
507f4e33
NS
1470 _("local inode %llu attr too small (size = %d, min size = %d)\n"),
1471 lino, INT_GET(asf->hdr.totsize, ARCH_CONVERT),
1472 sizeof(xfs_attr_sf_hdr_t));
2bd0ea18
NS
1473 return(1);
1474 }
1475 }
1476
1477 return(0);
1478}
1479
1480int
1481process_symlink_extlist(xfs_mount_t *mp, xfs_ino_t lino, xfs_dinode_t *dino)
1482{
1483 xfs_dfsbno_t start; /* start */
1484 xfs_dfilblks_t cnt; /* count */
1485 xfs_dfiloff_t offset; /* offset */
1486 xfs_dfiloff_t expected_offset;
1487 xfs_bmbt_rec_32_t *rp;
1488 int numrecs;
1489 int i;
1490 int max_blocks;
1491 int whichfork = XFS_DATA_FORK;
1492 int flag;
1493
507f4e33 1494 if (INT_GET(dino->di_core.di_size, ARCH_CONVERT) <=
46eca962 1495 XFS_DFORK_SIZE(dino, mp, whichfork)) {
2bd0ea18
NS
1496 if (dino->di_core.di_format == XFS_DINODE_FMT_LOCAL) {
1497 return(0);
1498 } else {
1499 do_warn(
507f4e33 1500 _("mismatch between format (%d) and size (%lld) in symlink ino %llu\n"),
2bd0ea18
NS
1501 dino->di_core.di_format,
1502 INT_GET(dino->di_core.di_size, ARCH_CONVERT),
1503 lino);
1504 return(1);
1505 }
1506 } else if (dino->di_core.di_format == XFS_DINODE_FMT_LOCAL) {
1507 do_warn(
507f4e33 1508 _("mismatch between format (%d) and size (%lld) in symlink inode %llu\n"),
2bd0ea18
NS
1509 dino->di_core.di_format,
1510 INT_GET(dino->di_core.di_size, ARCH_CONVERT),
1511 lino);
1512 return(1);
1513 }
1514
46eca962
NS
1515 rp = (xfs_bmbt_rec_32_t *)XFS_DFORK_PTR(dino, whichfork);
1516 numrecs = XFS_DFORK_NEXTENTS(dino, whichfork);
2bd0ea18
NS
1517
1518 /*
1519 * the max # of extents in a symlink inode is equal to the
dfc130f3 1520 * number of max # of blocks required to store the symlink
2bd0ea18
NS
1521 */
1522 if (numrecs > max_symlink_blocks) {
1523 do_warn(
507f4e33 1524 _("bad number of extents (%d) in symlink %llu data fork\n"),
2bd0ea18
NS
1525 numrecs, lino);
1526 return(1);
1527 }
1528
1529 max_blocks = max_symlink_blocks;
1530 expected_offset = 0;
1531
1532 for (i = 0; numrecs > 0; i++, numrecs--) {
1533 convert_extent(rp, &offset, &start, &cnt, &flag);
1534
1535 if (offset != expected_offset) {
1536 do_warn(
507f4e33 1537 _("bad extent #%d offset (%llu) in symlink %llu data fork\n"),
2bd0ea18
NS
1538 i, offset, lino);
1539 return(1);
1540 }
1541 if (cnt == 0 || cnt > max_blocks) {
1542 do_warn(
507f4e33 1543 _("bad extent #%d count (%llu) in symlink %llu data fork\n"),
2bd0ea18
NS
1544 i, cnt, lino);
1545 return(1);
1546 }
1547
1548 max_blocks -= cnt;
1549 expected_offset += cnt;
1550 }
1551
1552 return(0);
1553}
1554
1555/*
1556 * takes a name and length and returns 1 if the name contains
1557 * a \0, returns 0 otherwise
1558 */
1559int
1560null_check(char *name, int length)
1561{
1562 int i;
1563
1564 ASSERT(length < MAXPATHLEN);
1565
1566 for (i = 0; i < length; i++, name++) {
1567 if (*name == '\0')
1568 return(1);
1569 }
1570
1571 return(0);
1572}
1573
1574/*
1575 * like usual, returns 0 if everything's ok and 1 if something's
1576 * bogus
1577 */
1578int
1579process_symlink(xfs_mount_t *mp, xfs_ino_t lino, xfs_dinode_t *dino,
1580 blkmap_t *blkmap)
1581{
1582 xfs_dfsbno_t fsbno;
1583 xfs_dinode_core_t *dinoc = &dino->di_core;
1584 xfs_buf_t *bp = NULL;
1585 char *symlink, *cptr, *buf_data;
1586 int i, size, amountdone;
1587 char data[MAXPATHLEN];
1588
1589 /*
1590 * check size against kernel symlink limits. we know
1591 * size is consistent with inode storage format -- e.g.
1592 * the inode is structurally ok so we don't have to check
1593 * for that
1594 */
1595 if (INT_GET(dinoc->di_size, ARCH_CONVERT) >= MAXPATHLEN) {
507f4e33 1596 do_warn(_("symlink in inode %llu too long (%lld chars)\n"),
2bd0ea18
NS
1597 lino, INT_GET(dinoc->di_size, ARCH_CONVERT));
1598 return(1);
1599 }
1600
1601 /*
1602 * have to check symlink component by component.
1603 * get symlink contents into data area
1604 */
1605 symlink = &data[0];
1606 if (INT_GET(dinoc->di_size, ARCH_CONVERT)
46eca962 1607 <= XFS_DFORK_DSIZE(dino, mp)) {
2bd0ea18
NS
1608 /*
1609 * local symlink, just copy the symlink out of the
1610 * inode into the data area
1611 */
46eca962 1612 bcopy((char *)XFS_DFORK_DPTR(dino),
2bd0ea18
NS
1613 symlink, INT_GET(dinoc->di_size, ARCH_CONVERT));
1614 } else {
1615 /*
1616 * stored in a meta-data file, have to bmap one block
1617 * at a time and copy the symlink into the data area
1618 */
1619 i = size = amountdone = 0;
1620 cptr = symlink;
1621
1622 while (amountdone < INT_GET(dinoc->di_size, ARCH_CONVERT)) {
1623 fsbno = blkmap_get(blkmap, i);
1624 if (fsbno != NULLDFSBNO)
1625 bp = libxfs_readbuf(mp->m_dev,
1626 XFS_FSB_TO_DADDR(mp, fsbno),
1627 XFS_FSB_TO_BB(mp, 1), 0);
1628 if (!bp || fsbno == NULLDFSBNO) {
507f4e33
NS
1629 do_warn(
1630 _("cannot read inode %llu, file block %d, disk block %llu\n"),
1631 lino, i, fsbno);
2bd0ea18
NS
1632 return(1);
1633 }
1634
1635 buf_data = (char *)XFS_BUF_PTR(bp);
1636 size = MIN(INT_GET(dinoc->di_size, ARCH_CONVERT)
1637 - amountdone, (int)XFS_FSB_TO_BB(mp, 1)*BBSIZE);
1638 bcopy(buf_data, cptr, size);
1639 cptr += size;
1640 amountdone += size;
1641 i++;
1642 libxfs_putbuf(bp);
1643 }
1644 }
1645 data[INT_GET(dinoc->di_size, ARCH_CONVERT)] = '\0';
1646
1647 /*
1648 * check for nulls
1649 */
1650 if (null_check(symlink, (int) INT_GET(dinoc->di_size, ARCH_CONVERT))) {
507f4e33
NS
1651 do_warn(
1652 _("found illegal null character in symlink inode %llu\n"),
2bd0ea18
NS
1653 lino);
1654 return(1);
1655 }
1656
1657 /*
1658 * check for any component being too long
1659 */
1660 if (INT_GET(dinoc->di_size, ARCH_CONVERT) >= MAXNAMELEN) {
1661 cptr = strchr(symlink, '/');
1662
1663 while (cptr != NULL) {
1664 if (cptr - symlink >= MAXNAMELEN) {
1665 do_warn(
507f4e33 1666 _("component of symlink in inode %llu too long\n"),
2bd0ea18
NS
1667 lino);
1668 return(1);
1669 }
1670 symlink = cptr + 1;
1671 cptr = strchr(symlink, '/');
1672 }
1673
1674 if (strlen(symlink) >= MAXNAMELEN) {
507f4e33
NS
1675 do_warn(
1676 _("component of symlink in inode %llu too long\n"),
2bd0ea18
NS
1677 lino);
1678 return(1);
1679 }
1680 }
1681
1682 return(0);
1683}
1684
1685/*
1686 * called to process the set of misc inode special inode types
1687 * that have no associated data storage (fifos, pipes, devices, etc.).
1688 */
1689/* ARGSUSED */
1690int
1691process_misc_ino_types(xfs_mount_t *mp,
1692 xfs_dinode_t *dino,
1693 xfs_ino_t lino,
1694 int type)
1695{
1696 /*
1697 * disallow mountpoint inodes until such time as the
1698 * kernel actually allows them to be created (will
1699 * probably require a superblock version rev, sigh).
1700 */
1701 if (type == XR_INO_MOUNTPOINT) {
507f4e33 1702 do_warn(_("inode %llu has bad inode type (IFMNT)\n"), lino);
2bd0ea18
NS
1703 return(1);
1704 }
1705
1706 /*
1707 * must also have a zero size
1708 */
1709 if (INT_GET(dino->di_core.di_size, ARCH_CONVERT) != 0) {
1710 switch (type) {
1711 case XR_INO_CHRDEV:
507f4e33
NS
1712 do_warn(_("size of character device inode %llu != 0 "
1713 "(%lld bytes)\n"), lino,
2bd0ea18
NS
1714 INT_GET(dino->di_core.di_size, ARCH_CONVERT));
1715 break;
1716 case XR_INO_BLKDEV:
507f4e33
NS
1717 do_warn(_("size of block device inode %llu != 0 "
1718 "(%lld bytes)\n"), lino,
2bd0ea18
NS
1719 INT_GET(dino->di_core.di_size, ARCH_CONVERT));
1720 break;
1721 case XR_INO_SOCK:
507f4e33
NS
1722 do_warn(_("size of socket inode %llu != 0 "
1723 "(%lld bytes)\n"), lino,
2bd0ea18
NS
1724 INT_GET(dino->di_core.di_size, ARCH_CONVERT));
1725 break;
1726 case XR_INO_FIFO:
507f4e33
NS
1727 do_warn(_("size of fifo inode %llu != 0 "
1728 "(%lld bytes)\n"), lino,
2bd0ea18
NS
1729 INT_GET(dino->di_core.di_size, ARCH_CONVERT));
1730 break;
1731 default:
507f4e33
NS
1732 do_warn(_("Internal error - process_misc_ino_types, "
1733 "illegal type %d\n"), type);
2bd0ea18
NS
1734 abort();
1735 }
1736
1737 return(1);
1738 }
1739
1740 return(0);
1741}
1742
1e77098c 1743static __inline int
2bd0ea18
NS
1744process_misc_ino_types_blocks(xfs_drfsbno_t totblocks, xfs_ino_t lino, int type)
1745{
1746 /*
1747 * you can not enforce all misc types have zero data fork blocks
1748 * by checking dino->di_core.di_nblocks because atotblocks (attribute
1749 * blocks) are part of nblocks. We must check this later when atotblocks
dfc130f3 1750 * has been calculated or by doing a simple check that anExtents == 0.
2bd0ea18
NS
1751 * We must also guarantee that totblocks is 0. Thus nblocks checking
1752 * will be done later in process_dinode_int for misc types.
1753 */
1754
1755 if (totblocks != 0) {
1756 switch (type) {
1757 case XR_INO_CHRDEV:
1758 do_warn(
507f4e33 1759 _("size of character device inode %llu != 0 (%llu blocks)\n"),
2bd0ea18
NS
1760 lino, totblocks);
1761 break;
1762 case XR_INO_BLKDEV:
1763 do_warn(
507f4e33 1764 _("size of block device inode %llu != 0 (%llu blocks)\n"),
2bd0ea18
NS
1765 lino, totblocks);
1766 break;
1767 case XR_INO_SOCK:
1768 do_warn(
507f4e33 1769 _("size of socket inode %llu != 0 (%llu blocks)\n"),
2bd0ea18
NS
1770 lino, totblocks);
1771 break;
1772 case XR_INO_FIFO:
1773 do_warn(
507f4e33 1774 _("size of fifo inode %llu != 0 (%llu blocks)\n"),
2bd0ea18
NS
1775 lino, totblocks);
1776 break;
1777 default:
1778 return(0);
1779 }
1780 return(1);
1781 }
1782 return (0);
1783}
1784
1785/*
1786 * returns 0 if the inode is ok, 1 if the inode is corrupt
1787 * check_dups can be set to 1 *only* when called by the
1788 * first pass of the duplicate block checking of phase 4.
1789 * *dirty is set > 0 if the dinode has been altered and
1790 * needs to be written out.
1791 *
1792 * for detailed, info, look at process_dinode() comments.
1793 */
1794/* ARGSUSED */
1795int
1796process_dinode_int(xfs_mount_t *mp,
1797 xfs_dinode_t *dino,
1798 xfs_agnumber_t agno,
1799 xfs_agino_t ino,
1800 int was_free, /* 1 if inode is currently free */
1801 int *dirty, /* out == > 0 if inode is now dirty */
1802 int *cleared, /* out == 1 if inode was cleared */
1803 int *used, /* out == 1 if inode is in use */
1804 int verify_mode, /* 1 == verify but don't modify inode */
1805 int uncertain, /* 1 == inode is uncertain */
1806 int ino_discovery, /* 1 == check dirs for unknown inodes */
1807 int check_dups, /* 1 == check if inode claims
1808 * duplicate blocks */
1809 int extra_attr_check, /* 1 == do attribute format and value checks */
1810 int *isa_dir, /* out == 1 if inode is a directory */
1811 xfs_ino_t *parent) /* out -- parent if ino is a dir */
1812{
1813 xfs_drfsbno_t totblocks = 0;
1814 xfs_drfsbno_t atotblocks = 0;
1815 xfs_dinode_core_t *dinoc;
1816 char *rstring;
1817 int type;
1818 int rtype;
1819 int do_rt;
1820 int err;
1821 int retval = 0;
1822 __uint64_t nextents;
1823 __uint64_t anextents;
1824 xfs_ino_t lino;
1825 const int is_free = 0;
1826 const int is_used = 1;
1827 int repair = 0;
1828 blkmap_t *ablkmap = NULL;
1829 blkmap_t *dblkmap = NULL;
1830 static char okfmts[] = {
1831 0, /* free inode */
1832 1 << XFS_DINODE_FMT_DEV, /* FIFO */
1833 1 << XFS_DINODE_FMT_DEV, /* CHR */
1834 0, /* type 3 unused */
1835 (1 << XFS_DINODE_FMT_LOCAL) |
1836 (1 << XFS_DINODE_FMT_EXTENTS) |
1837 (1 << XFS_DINODE_FMT_BTREE), /* DIR */
1838 0, /* type 5 unused */
1839 1 << XFS_DINODE_FMT_DEV, /* BLK */
1840 0, /* type 7 unused */
1841 (1 << XFS_DINODE_FMT_EXTENTS) |
1842 (1 << XFS_DINODE_FMT_BTREE), /* REG */
1843 0, /* type 9 unused */
1844 (1 << XFS_DINODE_FMT_LOCAL) |
1845 (1 << XFS_DINODE_FMT_EXTENTS), /* LNK */
1846 0, /* type 11 unused */
1847 1 << XFS_DINODE_FMT_DEV, /* SOCK */
1848 0, /* type 13 unused */
1849 1 << XFS_DINODE_FMT_UUID, /* MNT */
1850 0 /* type 15 unused */
1851 };
1852
1853 retval = 0;
1854 totblocks = atotblocks = 0;
1855 *dirty = *isa_dir = *cleared = 0;
1856 *used = is_used;
1857 type = rtype = XR_INO_UNKNOWN;
1858 rstring = NULL;
1859 do_rt = 0;
1860
1861 dinoc = &dino->di_core;
1862 lino = XFS_AGINO_TO_INO(mp, agno, ino);
1863
1864 /*
1865 * if in verify mode, don't modify the inode.
1866 *
1867 * if correcting, reset stuff that has known values
1868 *
1869 * if in uncertain mode, be silent on errors since we're
1870 * trying to find out if these are inodes as opposed
1871 * to assuming that they are. Just return the appropriate
1872 * return code in that case.
1873 */
1874
1875 if (INT_GET(dinoc->di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC) {
1876 retval++;
1877 if (!verify_mode) {
507f4e33 1878 do_warn(_("bad magic number 0x%x on inode %llu, "),
2bd0ea18
NS
1879 INT_GET(dinoc->di_magic, ARCH_CONVERT), lino);
1880 if (!no_modify) {
507f4e33 1881 do_warn(_("resetting magic number\n"));
2bd0ea18 1882 *dirty = 1;
507f4e33
NS
1883 INT_SET(dinoc->di_magic, ARCH_CONVERT,
1884 XFS_DINODE_MAGIC);
2bd0ea18 1885 } else {
507f4e33 1886 do_warn(_("would reset magic number\n"));
2bd0ea18
NS
1887 }
1888 } else if (!uncertain) {
507f4e33 1889 do_warn(_("bad magic number 0x%x on inode %llu\n"),
2bd0ea18
NS
1890 INT_GET(dinoc->di_magic, ARCH_CONVERT), lino);
1891 }
1892 }
1893
1894 if (!XFS_DINODE_GOOD_VERSION(dinoc->di_version) ||
1895 (!fs_inode_nlink && dinoc->di_version > XFS_DINODE_VERSION_1)) {
1896 retval++;
1897 if (!verify_mode) {
507f4e33 1898 do_warn(_("bad version number 0x%x on inode %llu, "),
2bd0ea18
NS
1899 dinoc->di_version, lino);
1900 if (!no_modify) {
507f4e33 1901 do_warn(_("resetting version number\n"));
2bd0ea18
NS
1902 *dirty = 1;
1903 dinoc->di_version = (fs_inode_nlink) ?
1904 XFS_DINODE_VERSION_2 :
1905 XFS_DINODE_VERSION_1;
1906 } else {
507f4e33 1907 do_warn(_("would reset version number\n"));
2bd0ea18
NS
1908 }
1909 } else if (!uncertain) {
507f4e33 1910 do_warn(_("bad version number 0x%x on inode %llu\n"),
2bd0ea18
NS
1911 dinoc->di_version, lino);
1912 }
1913 }
1914
1915 /*
1916 * blow out of here if the inode size is < 0
1917 */
1918 if (INT_GET(dinoc->di_size, ARCH_CONVERT) < 0) {
1919 retval++;
1920 if (!verify_mode) {
507f4e33 1921 do_warn(_("bad (negative) size %lld on inode %llu\n"),
2bd0ea18
NS
1922 INT_GET(dinoc->di_size, ARCH_CONVERT), lino);
1923 if (!no_modify) {
1924 *dirty += clear_dinode(mp, dino, lino);
1925 *cleared = 1;
1926 } else {
1927 *dirty = 1;
1928 *cleared = 1;
1929 }
1930 *used = is_free;
1931 } else if (!uncertain) {
507f4e33 1932 do_warn(_("bad (negative) size %lld on inode %llu\n"),
2bd0ea18
NS
1933 INT_GET(dinoc->di_size, ARCH_CONVERT), lino);
1934 }
1935
1936 return(1);
1937 }
1938
1939 /*
1940 * was_free value is not meaningful if we're in verify mode
1941 */
1942 if (!verify_mode && INT_GET(dinoc->di_mode, ARCH_CONVERT) == 0 && was_free == 1) {
1943 /*
1944 * easy case, inode free -- inode and map agree, clear
1945 * it just in case to ensure that format, etc. are
1946 * set correctly
1947 */
1948 if (!no_modify) {
1949 err = clear_dinode(mp, dino, lino);
1950 if (err) {
1951 *dirty = 1;
1952 *cleared = 1;
1953 }
1954 }
1955 *used = is_free;
1956 return(0);
1957 } else if (!verify_mode && INT_GET(dinoc->di_mode, ARCH_CONVERT) == 0 && was_free == 0) {
1958 /*
1959 * the inode looks free but the map says it's in use.
1960 * clear the inode just to be safe and mark the inode
1961 * free.
1962 */
507f4e33 1963 do_warn(_("imap claims a free inode %llu is in use, "), lino);
2bd0ea18
NS
1964
1965 if (!no_modify) {
507f4e33 1966 do_warn(_("correcting imap and clearing inode\n"));
2bd0ea18
NS
1967
1968 err = clear_dinode(mp, dino, lino);
1969 if (err) {
1970 retval++;
1971 *dirty = 1;
1972 *cleared = 1;
1973 }
1974 } else {
507f4e33 1975 do_warn(_("would correct imap and clear inode\n"));
2bd0ea18
NS
1976
1977 *dirty = 1;
1978 *cleared = 1;
1979 }
1980
1981 *used = is_free;
1982
1983 return(retval > 0 ? 1 : 0);
1984 }
1985
1986 /*
1987 * because of the lack of any write ordering guarantee, it's
1988 * possible that the core got updated but the forks didn't.
1989 * so rather than be ambitious (and probably incorrect),
dfc130f3 1990 * if there's an inconsistency, we get conservative and
2bd0ea18
NS
1991 * just pitch the file. blow off checking formats of
1992 * free inodes since technically any format is legal
1993 * as we reset the inode when we re-use it.
1994 */
1995 if (INT_GET(dinoc->di_mode, ARCH_CONVERT) != 0 &&
322f2a29 1996 ((((INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT) >> 12) > 15) ||
1e77098c 1997 (uchar_t) dinoc->di_format > XFS_DINODE_FMT_UUID ||
322f2a29 1998 (!(okfmts[(INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT) >> 12] &
2bd0ea18
NS
1999 (1 << dinoc->di_format))))) {
2000 /* bad inode format */
2001 retval++;
2002 if (!uncertain)
507f4e33 2003 do_warn(_("bad inode format in inode %llu\n"), lino);
2bd0ea18
NS
2004 if (!verify_mode) {
2005 if (!no_modify) {
2006 *dirty += clear_dinode(mp, dino, lino);
2007 ASSERT(*dirty > 0);
2008 }
2009 }
2010 *cleared = 1;
2011 *used = is_free;
2012
2013 return(retval > 0 ? 1 : 0);
2014 }
2015
2016 if (verify_mode)
2017 return(retval > 0 ? 1 : 0);
2018
2019 /*
2020 * clear the next unlinked field if necessary on a good
2021 * inode only during phase 4 -- when checking for inodes
2022 * referencing duplicate blocks. then it's safe because
2023 * we've done the inode discovery and have found all the inodes
2024 * we're going to find. check_dups is set to 1 only during
2025 * phase 4. Ugly.
2026 */
2027 if (check_dups && !no_modify)
2028 *dirty += clear_dinode_unlinked(mp, dino);
2029
2030 /* set type and map type info */
2031
322f2a29
SL
2032 switch (INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT) {
2033 case S_IFDIR:
2bd0ea18
NS
2034 type = XR_INO_DIR;
2035 *isa_dir = 1;
2036 break;
322f2a29 2037 case S_IFREG:
2bd0ea18
NS
2038 if (INT_GET(dinoc->di_flags, ARCH_CONVERT) & XFS_DIFLAG_REALTIME)
2039 type = XR_INO_RTDATA;
2040 else if (lino == mp->m_sb.sb_rbmino)
2041 type = XR_INO_RTBITMAP;
2042 else if (lino == mp->m_sb.sb_rsumino)
2043 type = XR_INO_RTSUM;
2044 else
2045 type = XR_INO_DATA;
2046 break;
322f2a29 2047 case S_IFLNK:
2bd0ea18
NS
2048 type = XR_INO_SYMLINK;
2049 break;
322f2a29 2050 case S_IFCHR:
2bd0ea18
NS
2051 type = XR_INO_CHRDEV;
2052 break;
322f2a29 2053 case S_IFBLK:
2bd0ea18
NS
2054 type = XR_INO_BLKDEV;
2055 break;
322f2a29 2056 case S_IFSOCK:
2bd0ea18
NS
2057 type = XR_INO_SOCK;
2058 break;
322f2a29 2059 case S_IFIFO:
2bd0ea18
NS
2060 type = XR_INO_FIFO;
2061 break;
2bd0ea18 2062 default:
c426c8b7
BN
2063 retval++;
2064 if (!verify_mode) {
2065 do_warn(_("bad inode type %#o inode %llu\n"),
2066 (int) (INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT), lino);
2067 if (!no_modify)
2068 *dirty += clear_dinode(mp, dino, lino);
2069 else
2070 *dirty = 1;
2071 *cleared = 1;
2072 *used = is_free;
2073 } else if (!uncertain) {
2074 do_warn(_("bad inode type %#o inode %llu\n"),
2075 (int) (INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT), lino);
2076 }
2077 return 1;
2bd0ea18
NS
2078 }
2079
2080 /*
2081 * type checks for root, realtime inodes, and quota inodes
2082 */
2083 if (lino == mp->m_sb.sb_rootino && type != XR_INO_DIR) {
507f4e33 2084 do_warn(_("bad inode type for root inode %llu, "), lino);
2bd0ea18
NS
2085 type = XR_INO_DIR;
2086
2087 if (!no_modify) {
507f4e33
NS
2088 do_warn(_("resetting to directory\n"));
2089 INT_MOD_EXPR(dinoc->di_mode, ARCH_CONVERT,
322f2a29 2090 &= ~(INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT));
507f4e33 2091 INT_MOD_EXPR(dinoc->di_mode, ARCH_CONVERT,
322f2a29 2092 |= INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFDIR);
2bd0ea18 2093 } else {
507f4e33 2094 do_warn(_("would reset to directory\n"));
2bd0ea18
NS
2095 }
2096 } else if (lino == mp->m_sb.sb_rsumino) {
2097 do_rt = 1;
507f4e33 2098 rstring = _("summary");
2bd0ea18
NS
2099 rtype = XR_INO_RTSUM;
2100 } else if (lino == mp->m_sb.sb_rbmino) {
2101 do_rt = 1;
507f4e33 2102 rstring = _("bitmap");
2bd0ea18
NS
2103 rtype = XR_INO_RTBITMAP;
2104 } else if (lino == mp->m_sb.sb_uquotino) {
2105 if (type != XR_INO_DATA) {
507f4e33 2106 do_warn(_("user quota inode has bad type 0x%x\n"),
322f2a29 2107 INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT);
2bd0ea18
NS
2108
2109 if (!no_modify) {
2110 *dirty += clear_dinode(mp, dino, lino);
2111 ASSERT(*dirty > 0);
2112 }
2113
2114 *cleared = 1;
2115 *used = is_free;
2116 *isa_dir = 0;
2117
2118 mp->m_sb.sb_uquotino = NULLFSINO;
2119
2120 return(1);
2121 }
b36eef04 2122 } else if (lino == mp->m_sb.sb_gquotino) {
2bd0ea18 2123 if (type != XR_INO_DATA) {
507f4e33 2124 do_warn(_("group quota inode has bad type 0x%x\n"),
322f2a29 2125 INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT);
2bd0ea18
NS
2126
2127 if (!no_modify) {
2128 *dirty += clear_dinode(mp, dino, lino);
2129 ASSERT(*dirty > 0);
2130 }
2131
2132 *cleared = 1;
2133 *used = is_free;
2134 *isa_dir = 0;
2135
b36eef04 2136 mp->m_sb.sb_gquotino = NULLFSINO;
2bd0ea18
NS
2137
2138 return(1);
2139 }
2140 }
2141
2142 if (do_rt && type != rtype) {
2143 type = XR_INO_DATA;
2144
507f4e33 2145 do_warn(_("bad inode type for realtime %s inode %llu, "),
2bd0ea18
NS
2146 rstring, lino);
2147
2148 if (!no_modify) {
507f4e33
NS
2149 do_warn(_("resetting to regular file\n"));
2150 INT_MOD_EXPR(dinoc->di_mode, ARCH_CONVERT,
322f2a29 2151 &= ~(INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFMT));
507f4e33 2152 INT_MOD_EXPR(dinoc->di_mode, ARCH_CONVERT,
322f2a29 2153 |= INT_GET(dinoc->di_mode, ARCH_CONVERT) & S_IFREG);
2bd0ea18 2154 } else {
507f4e33 2155 do_warn(_("would reset to regular file\n"));
2bd0ea18
NS
2156 }
2157 }
2158
2159 /*
ae541a2b
NS
2160 * only regular files with REALTIME or EXTSIZE flags set can have
2161 * extsize set, or directories with EXTSZINHERIT.
2bd0ea18 2162 */
ae541a2b
NS
2163 if (INT_GET(dinoc->di_extsize, ARCH_CONVERT) != 0) {
2164 if ((type == XR_INO_RTDATA) ||
2165 (type == XR_INO_DIR &&
2166 (INT_GET(dinoc->di_flags, ARCH_CONVERT) &
2167 XFS_DIFLAG_EXTSZINHERIT)) ||
2168 (type == XR_INO_DATA &&
2169 (INT_GET(dinoc->di_flags, ARCH_CONVERT) &
2170 XFS_DIFLAG_EXTSIZE))) {
2171 /* s'okay */ ;
2172 } else {
2173 do_warn(
2174 _("bad non-zero extent size %u for non-realtime/extsize inode %llu, "),
2175 INT_GET(dinoc->di_extsize, ARCH_CONVERT), lino);
2bd0ea18 2176
ae541a2b
NS
2177 if (!no_modify) {
2178 do_warn(_("resetting to zero\n"));
2179 dinoc->di_extsize = 0;
2180 *dirty = 1;
2181 } else {
2182 do_warn(_("would reset to zero\n"));
2183 }
2bd0ea18
NS
2184 }
2185 }
2186
2187 /*
2188 * for realtime inodes, check sizes to see that
2189 * they are consistent with the # of realtime blocks.
2190 * also, verify that they contain only one extent and
2191 * are extent format files. If anything's wrong, clear
2192 * the inode -- we'll recreate it in phase 6.
2193 */
184cb918
ES
2194 if (do_rt &&
2195 ((lino == mp->m_sb.sb_rbmino &&
2196 INT_GET(dinoc->di_size, ARCH_CONVERT)
2197 != mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize) ||
2198 (lino == mp->m_sb.sb_rsumino &&
2199 INT_GET(dinoc->di_size, ARCH_CONVERT) != mp->m_rsumsize))) {
2200
507f4e33 2201 do_warn(_("bad size %llu for realtime %s inode %llu\n"),
2bd0ea18
NS
2202 INT_GET(dinoc->di_size, ARCH_CONVERT), rstring, lino);
2203
2204 if (!no_modify) {
2205 *dirty += clear_dinode(mp, dino, lino);
2206 ASSERT(*dirty > 0);
2207 }
2208
2209 *cleared = 1;
2210 *used = is_free;
2211 *isa_dir = 0;
2212
2213 return(1);
2214 }
2215
2216 if (do_rt && mp->m_sb.sb_rblocks == 0 && INT_GET(dinoc->di_nextents, ARCH_CONVERT) != 0) {
507f4e33 2217 do_warn(_("bad # of extents (%u) for realtime %s inode %llu\n"),
2bd0ea18
NS
2218 INT_GET(dinoc->di_nextents, ARCH_CONVERT), rstring, lino);
2219
2220 if (!no_modify) {
2221 *dirty += clear_dinode(mp, dino, lino);
2222 ASSERT(*dirty > 0);
2223 }
2224
2225 *cleared = 1;
2226 *used = is_free;
2227 *isa_dir = 0;
2228
2229 return(1);
2230 }
2231
2232 /*
2233 * Setup nextents and anextents for blkmap_alloc calls.
2234 */
2235 nextents = INT_GET(dinoc->di_nextents, ARCH_CONVERT);
2236 if (nextents > INT_GET(dinoc->di_nblocks, ARCH_CONVERT) || nextents > XFS_MAX_INCORE_EXTENTS)
2237 nextents = 1;
2238 anextents = INT_GET(dinoc->di_anextents, ARCH_CONVERT);
2239 if (anextents > INT_GET(dinoc->di_nblocks, ARCH_CONVERT) || anextents > XFS_MAX_INCORE_EXTENTS)
2240 anextents = 1;
2241
2242 /*
2243 * general size/consistency checks:
2244 *
2245 * if the size <= size of the data fork, directories must be
2246 * local inodes unlike regular files which would be extent inodes.
2247 * all the other mentioned types have to have a zero size value.
2248 *
2249 * if the size and format don't match, get out now rather than
2250 * risk trying to process a non-existent extents or btree
2251 * type data fork.
2252 */
2253 switch (type) {
2254 case XR_INO_DIR:
507f4e33 2255 if (INT_GET(dinoc->di_size, ARCH_CONVERT) <=
46eca962 2256 XFS_DFORK_DSIZE(dino, mp) &&
507f4e33 2257 (dinoc->di_format != XFS_DINODE_FMT_LOCAL)) {
2bd0ea18 2258 do_warn(
507f4e33 2259_("mismatch between format (%d) and size (%lld) in directory ino %llu\n"),
2bd0ea18
NS
2260 dinoc->di_format,
2261 INT_GET(dinoc->di_size, ARCH_CONVERT),
2262 lino);
2263
2264 if (!no_modify) {
2265 *dirty += clear_dinode(mp,
2266 dino, lino);
2267 ASSERT(*dirty > 0);
2268 }
2269
2270 *cleared = 1;
2271 *used = is_free;
2272 *isa_dir = 0;
2273
2274 return(1);
2275 }
2276 if (dinoc->di_format != XFS_DINODE_FMT_LOCAL)
2277 dblkmap = blkmap_alloc(nextents);
2278 break;
2279 case XR_INO_SYMLINK:
2280 if (process_symlink_extlist(mp, lino, dino)) {
507f4e33 2281 do_warn(_("bad data fork in symlink %llu\n"), lino);
2bd0ea18
NS
2282
2283 if (!no_modify) {
2284 *dirty += clear_dinode(mp,
2285 dino, lino);
2286 ASSERT(*dirty > 0);
2287 }
2288
2289 *cleared = 1;
2290 *used = is_free;
2291 *isa_dir = 0;
2292
2293 return(1);
2294 }
2295 if (dinoc->di_format != XFS_DINODE_FMT_LOCAL)
2296 dblkmap = blkmap_alloc(nextents);
2297 break;
2298 case XR_INO_CHRDEV: /* fall through to FIFO case ... */
2299 case XR_INO_BLKDEV: /* fall through to FIFO case ... */
2300 case XR_INO_SOCK: /* fall through to FIFO case ... */
2301 case XR_INO_MOUNTPOINT: /* fall through to FIFO case ... */
2302 case XR_INO_FIFO:
2303 if (process_misc_ino_types(mp, dino, lino, type)) {
2304 if (!no_modify) {
2305 *dirty += clear_dinode(mp, dino, lino);
2306 ASSERT(*dirty > 0);
2307 }
2308
2309 *cleared = 1;
2310 *used = is_free;
2311 *isa_dir = 0;
2312
2313 return(1);
2314 }
2315 break;
2316 case XR_INO_RTDATA:
2317 /*
2318 * if we have no realtime blocks, any inode claiming
2319 * to be a real-time file is bogus
2320 */
2321 if (mp->m_sb.sb_rblocks == 0) {
2322 do_warn(
507f4e33 2323 _("found inode %llu claiming to be a real-time file\n"),
2bd0ea18
NS
2324 lino);
2325
2326 if (!no_modify) {
2327 *dirty += clear_dinode(mp, dino, lino);
2328 ASSERT(*dirty > 0);
2329 }
2330
2331 *cleared = 1;
2332 *used = is_free;
2333 *isa_dir = 0;
2334
2335 return(1);
2336 }
2337 break;
2338 case XR_INO_RTBITMAP:
507f4e33
NS
2339 if (INT_GET(dinoc->di_size, ARCH_CONVERT) !=
2340 (__int64_t)mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize) {
2bd0ea18 2341 do_warn(
507f4e33 2342 _("realtime bitmap inode %llu has bad size %lld (should be %lld)\n"),
2bd0ea18
NS
2343 lino, INT_GET(dinoc->di_size, ARCH_CONVERT),
2344 (__int64_t) mp->m_sb.sb_rbmblocks *
2345 mp->m_sb.sb_blocksize);
2346
2347 if (!no_modify) {
2348 *dirty += clear_dinode(mp, dino, lino);
2349 ASSERT(*dirty > 0);
2350 }
2351
2352 *cleared = 1;
2353 *used = is_free;
2354 *isa_dir = 0;
2355
2356 return(1);
2357 }
2358 dblkmap = blkmap_alloc(nextents);
2359 break;
2360 case XR_INO_RTSUM:
2361 if (INT_GET(dinoc->di_size, ARCH_CONVERT) != mp->m_rsumsize) {
2362 do_warn(
507f4e33
NS
2363 _("realtime summary inode %llu has bad size %lld (should be %d)\n"),
2364 lino, INT_GET(dinoc->di_size, ARCH_CONVERT),
2365 mp->m_rsumsize);
2bd0ea18
NS
2366
2367 if (!no_modify) {
2368 *dirty += clear_dinode(mp, dino, lino);
2369 ASSERT(*dirty > 0);
2370 }
2371
2372 *cleared = 1;
2373 *used = is_free;
2374 *isa_dir = 0;
2375
2376 return(1);
2377 }
2378 dblkmap = blkmap_alloc(nextents);
2379 break;
2380 default:
2381 break;
2382 }
2383
2384 /*
2385 * check for illegal values of forkoff
2386 */
2387 err = 0;
2388 if (dinoc->di_forkoff != 0) {
2389 switch (dinoc->di_format) {
2390 case XFS_DINODE_FMT_DEV:
2391 if (dinoc->di_forkoff !=
63899e27 2392 (roundup(sizeof(xfs_dev_t), 8) >> 3)) {
2bd0ea18 2393 do_warn(
507f4e33 2394 _("bad attr fork offset %d in dev inode %llu, should be %d\n"),
2bd0ea18
NS
2395 (int) dinoc->di_forkoff,
2396 lino,
63899e27 2397 (int) (roundup(sizeof(xfs_dev_t), 8) >> 3));
2bd0ea18
NS
2398 err = 1;
2399 }
2400 break;
2401 case XFS_DINODE_FMT_UUID:
2402 if (dinoc->di_forkoff !=
2403 (roundup(sizeof(uuid_t), 8) >> 3)) {
2404 do_warn(
507f4e33 2405 _("bad attr fork offset %d in uuid inode %llu, should be %d\n"),
2bd0ea18
NS
2406 (int) dinoc->di_forkoff,
2407 lino,
2408 (int)(roundup(sizeof(uuid_t), 8) >> 3));
2409 err = 1;
2410 }
2411 break;
2412 case XFS_DINODE_FMT_LOCAL: /* fall through ... */
2413 case XFS_DINODE_FMT_EXTENTS: /* fall through ... */
ca86e759
NS
2414 case XFS_DINODE_FMT_BTREE: {
2415 if (dinoc->di_forkoff >= (XFS_LITINO(mp) >> 3)) {
2bd0ea18 2416 do_warn(
ca86e759 2417 _("bad attr fork offset %d in inode %llu, max=%d\n"),
2bd0ea18 2418 (int) dinoc->di_forkoff,
ca86e759 2419 lino, XFS_LITINO(mp) >> 3);
2bd0ea18
NS
2420 err = 1;
2421 }
2422 break;
ca86e759 2423 }
2bd0ea18 2424 default:
507f4e33 2425 do_error(_("unexpected inode format %d\n"),
2bd0ea18
NS
2426 (int) dinoc->di_format);
2427 break;
2428 }
2429 }
2430
2431 if (err) {
2432 if (!no_modify) {
2433 *dirty += clear_dinode(mp, dino, lino);
2434 ASSERT(*dirty > 0);
2435 }
2436
2437 *cleared = 1;
2438 *used = is_free;
2439 *isa_dir = 0;
2440 blkmap_free(dblkmap);
2441 return(1);
2442 }
2443
2444 /*
2445 * check data fork -- if it's bad, clear the inode
2446 */
2447 nextents = 0;
2448 switch (dinoc->di_format) {
2449 case XFS_DINODE_FMT_LOCAL:
2450 err = process_lclinode(mp, agno, ino, dino, type,
2451 dirty, &totblocks, &nextents, &dblkmap,
2452 XFS_DATA_FORK, check_dups);
2453 break;
2454 case XFS_DINODE_FMT_EXTENTS:
2455 err = process_exinode(mp, agno, ino, dino, type,
2456 dirty, &totblocks, &nextents, &dblkmap,
2457 XFS_DATA_FORK, check_dups);
2458 break;
2459 case XFS_DINODE_FMT_BTREE:
2460 err = process_btinode(mp, agno, ino, dino, type,
2461 dirty, &totblocks, &nextents, &dblkmap,
2462 XFS_DATA_FORK, check_dups);
2463 break;
2464 case XFS_DINODE_FMT_DEV: /* fall through */
2465 case XFS_DINODE_FMT_UUID:
2466 err = 0;
2467 break;
2468 default:
507f4e33
NS
2469 do_error(_("unknown format %d, ino %llu (mode = %d)\n"),
2470 dinoc->di_format, lino,
2471 INT_GET(dinoc->di_mode, ARCH_CONVERT));
2bd0ea18
NS
2472 }
2473
2474 if (err) {
2475 /*
2476 * problem in the data fork, clear out the inode
2477 * and get out
2478 */
507f4e33 2479 do_warn(_("bad data fork in inode %llu\n"), lino);
2bd0ea18
NS
2480
2481 if (!no_modify) {
2482 *dirty += clear_dinode(mp, dino, lino);
2483 ASSERT(*dirty > 0);
2484 }
2485
2486 *cleared = 1;
2487 *used = is_free;
2488 *isa_dir = 0;
2489 blkmap_free(dblkmap);
2bd0ea18
NS
2490 return(1);
2491 }
2492
2493 if (check_dups) {
2494 /*
2495 * if check_dups was non-zero, we have to
2496 * re-process data fork to set bitmap since the
2497 * bitmap wasn't set the first time through
2498 */
2499 switch (dinoc->di_format) {
2500 case XFS_DINODE_FMT_LOCAL:
2501 err = process_lclinode(mp, agno, ino, dino, type,
2502 dirty, &totblocks, &nextents, &dblkmap,
2503 XFS_DATA_FORK, 0);
2504 break;
2505 case XFS_DINODE_FMT_EXTENTS:
2506 err = process_exinode(mp, agno, ino, dino, type,
2507 dirty, &totblocks, &nextents, &dblkmap,
2508 XFS_DATA_FORK, 0);
2509 break;
2510 case XFS_DINODE_FMT_BTREE:
2511 err = process_btinode(mp, agno, ino, dino, type,
2512 dirty, &totblocks, &nextents, &dblkmap,
2513 XFS_DATA_FORK, 0);
2514 break;
2515 case XFS_DINODE_FMT_DEV: /* fall through */
2516 case XFS_DINODE_FMT_UUID:
2517 err = 0;
2518 break;
2519 default:
507f4e33
NS
2520 do_error(_("unknown format %d, ino %llu (mode = %d)\n"),
2521 dinoc->di_format, lino,
2522 INT_GET(dinoc->di_mode, ARCH_CONVERT));
2bd0ea18
NS
2523 }
2524
2525 if (no_modify && err != 0) {
2526 *cleared = 1;
2527 *used = is_free;
2528 *isa_dir = 0;
2529 blkmap_free(dblkmap);
2bd0ea18
NS
2530 return(1);
2531 }
2532
2533 ASSERT(err == 0);
2534 }
2535
2536 /*
2537 * check attribute fork if necessary. attributes are
2538 * always stored in the regular filesystem.
2539 */
2540
46eca962 2541 if (!XFS_DFORK_Q(dino) &&
507f4e33
NS
2542 dinoc->di_aformat != XFS_DINODE_FMT_EXTENTS) {
2543 do_warn(_("bad attribute format %d in inode %llu, "),
2bd0ea18
NS
2544 dinoc->di_aformat, lino);
2545 if (!no_modify) {
507f4e33 2546 do_warn(_("resetting value\n"));
2bd0ea18
NS
2547 dinoc->di_aformat = XFS_DINODE_FMT_EXTENTS;
2548 *dirty = 1;
2549 } else
507f4e33 2550 do_warn(_("would reset value\n"));
2bd0ea18 2551 anextents = 0;
46eca962 2552 } else if (XFS_DFORK_Q(dino)) {
2bd0ea18
NS
2553 switch (dinoc->di_aformat) {
2554 case XFS_DINODE_FMT_LOCAL:
2555 anextents = 0;
2556 err = process_lclinode(mp, agno, ino, dino,
2557 type, dirty, &atotblocks, &anextents, &ablkmap,
2558 XFS_ATTR_FORK, check_dups);
2559 break;
2560 case XFS_DINODE_FMT_EXTENTS:
2561 ablkmap = blkmap_alloc(anextents);
2562 anextents = 0;
2563 err = process_exinode(mp, agno, ino, dino,
2564 type, dirty, &atotblocks, &anextents, &ablkmap,
2565 XFS_ATTR_FORK, check_dups);
2566 break;
2567 case XFS_DINODE_FMT_BTREE:
2568 ablkmap = blkmap_alloc(anextents);
2569 anextents = 0;
2570 err = process_btinode(mp, agno, ino, dino,
2571 type, dirty, &atotblocks, &anextents, &ablkmap,
2572 XFS_ATTR_FORK, check_dups);
2573 break;
2574 default:
2575 anextents = 0;
507f4e33 2576 do_warn(_("illegal attribute format %d, ino %llu\n"),
2bd0ea18
NS
2577 dinoc->di_aformat, lino);
2578 err = 1;
2579 break;
2580 }
2581
2582 if (err) {
2583 /*
2584 * clear the attribute fork if necessary. we can't
2585 * clear the inode because we've already put the
2586 * inode space info into the blockmap.
2587 *
2588 * XXX - put the inode onto the "move it" list and
2589 * log the the attribute scrubbing
2590 */
507f4e33 2591 do_warn(_("bad attribute fork in inode %llu"), lino);
2bd0ea18
NS
2592
2593 if (!no_modify) {
2594 if (delete_attr_ok) {
507f4e33 2595 do_warn(_(", clearing attr fork\n"));
2bd0ea18
NS
2596 *dirty += clear_dinode_attr(mp,
2597 dino, lino);
2598 } else {
2599 do_warn("\n");
2600 *dirty += clear_dinode(mp,
2601 dino, lino);
2602 }
2603 ASSERT(*dirty > 0);
2604 } else {
507f4e33 2605 do_warn(_(", would clear attr fork\n"));
2bd0ea18
NS
2606 }
2607
2608 atotblocks = 0;
2609 anextents = 0;
2610
2611 if (delete_attr_ok) {
2612 if (!no_modify)
2613 dinoc->di_aformat = XFS_DINODE_FMT_LOCAL;
2614 } else {
2615 *cleared = 1;
2616 *used = is_free;
2617 *isa_dir = 0;
2618 blkmap_free(dblkmap);
2619 blkmap_free(ablkmap);
2620 }
2621 return(1);
dfc130f3 2622
2bd0ea18
NS
2623 } else if (check_dups) {
2624 switch (dinoc->di_aformat) {
2625 case XFS_DINODE_FMT_LOCAL:
2626 err = process_lclinode(mp, agno, ino, dino,
2627 type, dirty, &atotblocks, &anextents,
2628 &ablkmap, XFS_ATTR_FORK, 0);
2629 break;
2630 case XFS_DINODE_FMT_EXTENTS:
2631 err = process_exinode(mp, agno, ino, dino,
2632 type, dirty, &atotblocks, &anextents,
2633 &ablkmap, XFS_ATTR_FORK, 0);
2634 break;
2635 case XFS_DINODE_FMT_BTREE:
2636 err = process_btinode(mp, agno, ino, dino,
2637 type, dirty, &atotblocks, &anextents,
2638 &ablkmap, XFS_ATTR_FORK, 0);
2639 break;
2640 default:
507f4e33
NS
2641 do_error(
2642 _("illegal attribute fmt %d, ino %llu\n"),
2643 dinoc->di_aformat, lino);
2bd0ea18
NS
2644 }
2645
2646 if (no_modify && err != 0) {
2647 *cleared = 1;
2648 *used = is_free;
2649 *isa_dir = 0;
2650 blkmap_free(dblkmap);
2651 blkmap_free(ablkmap);
2bd0ea18
NS
2652 return(1);
2653 }
2654
2655 ASSERT(err == 0);
2656 }
2657
2658 /*
2659 * do attribute semantic-based consistency checks now
2660 */
2661
2662 /* get this only in phase 3, not in both phase 3 and 4 */
2663 if (extra_attr_check) {
2664 if ((err = process_attributes(mp, lino, dino, ablkmap,
2665 &repair))) {
507f4e33
NS
2666 do_warn(
2667 _("problem with attribute contents in inode %llu\n"), lino);
2bd0ea18
NS
2668 if(!repair) {
2669 /* clear attributes if not done already */
2670 if (!no_modify) {
2671 *dirty += clear_dinode_attr(
2672 mp, dino, lino);
2673 dinoc->di_aformat =
2674 XFS_DINODE_FMT_LOCAL;
2675 } else {
507f4e33
NS
2676 do_warn(
2677 _("would clear attr fork\n"));
2bd0ea18
NS
2678 }
2679 atotblocks = 0;
dfc130f3 2680 anextents = 0;
2bd0ea18
NS
2681 }
2682 else {
2683 *dirty = 1; /* it's been repaired */
2684 }
2685 }
2686 }
2687 blkmap_free(ablkmap);
2688
2689 } else
2690 anextents = 0;
2691
dfc130f3
RC
2692 /*
2693 * enforce totblocks is 0 for misc types
2bd0ea18
NS
2694 */
2695 if (process_misc_ino_types_blocks(totblocks, lino, type)) {
2696 if (!no_modify) {
2697 *dirty += clear_dinode(mp, dino, lino);
2698 ASSERT(*dirty > 0);
2699 }
2700 *cleared = 1;
2701 *used = is_free;
2702 *isa_dir = 0;
2703 blkmap_free(dblkmap);
2bd0ea18
NS
2704 return(1);
2705 }
2706
2707 /*
2708 * correct space counters if required
2709 */
2710 if (totblocks + atotblocks != INT_GET(dinoc->di_nblocks, ARCH_CONVERT)) {
2711 if (!no_modify) {
507f4e33
NS
2712 do_warn(
2713 _("correcting nblocks for inode %llu, was %llu - counted %llu\n"),
2bd0ea18
NS
2714 lino, INT_GET(dinoc->di_nblocks, ARCH_CONVERT),
2715 totblocks + atotblocks);
2716 *dirty = 1;
2717 INT_SET(dinoc->di_nblocks, ARCH_CONVERT, totblocks + atotblocks);
2718 } else {
507f4e33
NS
2719 do_warn(
2720 _("bad nblocks %llu for inode %llu, would reset to %llu\n"),
2bd0ea18
NS
2721 INT_GET(dinoc->di_nblocks, ARCH_CONVERT), lino,
2722 totblocks + atotblocks);
2723 }
2724 }
2725
2726 if (nextents > MAXEXTNUM) {
507f4e33 2727 do_warn(_("too many data fork extents (%llu) in inode %llu\n"),
2bd0ea18
NS
2728 nextents, lino);
2729
2730 if (!no_modify) {
2731 *dirty += clear_dinode(mp, dino, lino);
2732 ASSERT(*dirty > 0);
2733 }
2734 *cleared = 1;
2735 *used = is_free;
2736 *isa_dir = 0;
2737 blkmap_free(dblkmap);
2738
2739 return(1);
2740 }
2741 if (nextents != INT_GET(dinoc->di_nextents, ARCH_CONVERT)) {
2742 if (!no_modify) {
507f4e33
NS
2743 do_warn(
2744 _("correcting nextents for inode %llu, was %d - counted %llu\n"),
2745 lino, INT_GET(dinoc->di_nextents, ARCH_CONVERT),
2746 nextents);
2bd0ea18 2747 *dirty = 1;
507f4e33
NS
2748 INT_SET(dinoc->di_nextents, ARCH_CONVERT,
2749 (xfs_extnum_t) nextents);
2bd0ea18
NS
2750 } else {
2751 do_warn(
507f4e33
NS
2752 _("bad nextents %d for inode %llu, would reset to %llu\n"),
2753 INT_GET(dinoc->di_nextents, ARCH_CONVERT),
2754 lino, nextents);
2bd0ea18
NS
2755 }
2756 }
2757
2758 if (anextents > MAXAEXTNUM) {
507f4e33 2759 do_warn(_("too many attr fork extents (%llu) in inode %llu\n"),
2bd0ea18
NS
2760 anextents, lino);
2761
2762 if (!no_modify) {
2763 *dirty += clear_dinode(mp, dino, lino);
2764 ASSERT(*dirty > 0);
2765 }
2766 *cleared = 1;
2767 *used = is_free;
2768 *isa_dir = 0;
2769 blkmap_free(dblkmap);
2bd0ea18
NS
2770 return(1);
2771 }
2772 if (anextents != INT_GET(dinoc->di_anextents, ARCH_CONVERT)) {
2773 if (!no_modify) {
507f4e33
NS
2774 do_warn(
2775 _("correcting anextents for inode %llu, was %d - counted %llu\n"),
2776 lino,
2777 INT_GET(dinoc->di_anextents, ARCH_CONVERT),
2778 anextents);
2bd0ea18 2779 *dirty = 1;
507f4e33
NS
2780 INT_SET(dinoc->di_anextents, ARCH_CONVERT,
2781 (xfs_aextnum_t) anextents);
2bd0ea18
NS
2782 } else {
2783 do_warn(
507f4e33
NS
2784 _("bad anextents %d for inode %llu, would reset to %llu\n"),
2785 INT_GET(dinoc->di_anextents, ARCH_CONVERT),
2786 lino, anextents);
2bd0ea18
NS
2787 }
2788 }
2789
2790 /*
2791 * do any semantic type-based checking here
2792 */
2793 switch (type) {
2794 case XR_INO_DIR:
2795 if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb))
2796 err = process_dir2(mp, lino, dino, ino_discovery,
2797 dirty, "", parent, dblkmap);
2798 else
2799 err = process_dir(mp, lino, dino, ino_discovery,
2800 dirty, "", parent, dblkmap);
2801 if (err)
2802 do_warn(
507f4e33 2803 _("problem with directory contents in inode %llu\n"),
2bd0ea18
NS
2804 lino);
2805 break;
2806 case XR_INO_RTBITMAP:
2807 /* process_rtbitmap XXX */
2808 err = 0;
2809 break;
2810 case XR_INO_RTSUM:
2811 /* process_rtsummary XXX */
2812 err = 0;
2813 break;
2814 case XR_INO_SYMLINK:
2815 if ((err = process_symlink(mp, lino, dino, dblkmap)))
507f4e33 2816 do_warn(_("problem with symbolic link in inode %llu\n"),
2bd0ea18
NS
2817 lino);
2818 break;
2819 case XR_INO_DATA: /* fall through to FIFO case ... */
2820 case XR_INO_RTDATA: /* fall through to FIFO case ... */
2821 case XR_INO_CHRDEV: /* fall through to FIFO case ... */
2822 case XR_INO_BLKDEV: /* fall through to FIFO case ... */
2823 case XR_INO_SOCK: /* fall through to FIFO case ... */
2824 case XR_INO_FIFO:
2825 err = 0;
2826 break;
2827 default:
507f4e33 2828 printf(_("Unexpected inode type\n"));
2bd0ea18
NS
2829 abort();
2830 }
2831
1e77098c
MV
2832 if (dblkmap)
2833 blkmap_free(dblkmap);
2bd0ea18
NS
2834
2835 if (err) {
2836 /*
2837 * problem in the inode type-specific semantic
2838 * checking, clear out the inode and get out
2839 */
2840 if (!no_modify) {
2841 *dirty += clear_dinode(mp, dino, lino);
2842 ASSERT(*dirty > 0);
2843 }
2844 *cleared = 1;
2845 *used = is_free;
2846 *isa_dir = 0;
2847
2848 return(1);
2849 }
2850
2851 /*
2852 * check nlinks feature, if it's a version 1 inode,
2853 * just leave nlinks alone. even if it's set wrong,
2854 * it'll be reset when read in.
2855 */
2856 if (dinoc->di_version > XFS_DINODE_VERSION_1 && !fs_inode_nlink) {
2857 /*
2858 * do we have a fs/inode version mismatch with a valid
2859 * version 2 inode here that has to stay version 2 or
2860 * lose links?
2861 */
2862 if (INT_GET(dinoc->di_nlink, ARCH_CONVERT) > XFS_MAXLINK_1) {
2863 /*
2864 * yes. are nlink inodes allowed?
2865 */
2866 if (fs_inode_nlink_allowed) {
2867 /*
2868 * yes, update status variable which will
2869 * cause sb to be updated later.
2870 */
2871 fs_inode_nlink = 1;
2872 do_warn(
507f4e33 2873 _("version 2 inode %llu claims > %u links, "),
2bd0ea18
NS
2874 lino, XFS_MAXLINK_1);
2875 if (!no_modify) {
2876 do_warn(
507f4e33 2877 _("updating superblock version number\n"));
2bd0ea18
NS
2878 } else {
2879 do_warn(
507f4e33 2880 _("would update superblock version number\n"));
2bd0ea18
NS
2881 }
2882 } else {
2883 /*
2884 * no, have to convert back to onlinks
2885 * even if we lose some links
2886 */
2887 do_warn(
507f4e33 2888 _("WARNING: version 2 inode %llu claims > %u links, "),
2bd0ea18
NS
2889 lino, XFS_MAXLINK_1);
2890 if (!no_modify) {
2891 do_warn(
507f4e33
NS
2892 _("converting back to version 1,\n\tthis may destroy %d links\n"),
2893 INT_GET(dinoc->di_nlink,
2894 ARCH_CONVERT)
2bd0ea18
NS
2895 - XFS_MAXLINK_1);
2896
2897 dinoc->di_version =
2898 XFS_DINODE_VERSION_1;
507f4e33
NS
2899 INT_SET(dinoc->di_nlink, ARCH_CONVERT,
2900 XFS_MAXLINK_1);
2901 INT_SET(dinoc->di_onlink, ARCH_CONVERT,
2902 XFS_MAXLINK_1);
2bd0ea18
NS
2903
2904 *dirty = 1;
2905 } else {
2906 do_warn(
507f4e33
NS
2907 _("would convert back to version 1,\n\tthis might destroy %d links\n"),
2908 INT_GET(dinoc->di_nlink,
2909 ARCH_CONVERT)
2bd0ea18
NS
2910 - XFS_MAXLINK_1);
2911 }
2912 }
2913 } else {
2914 /*
2915 * do we have a v2 inode that we could convert back
2916 * to v1 without losing any links? if we do and
2917 * we have a mismatch between superblock bits and the
2918 * version bit, alter the version bit in this case.
2919 *
2920 * the case where we lost links was handled above.
2921 */
507f4e33 2922 do_warn(_("found version 2 inode %llu, "), lino);
2bd0ea18 2923 if (!no_modify) {
507f4e33 2924 do_warn(_("converting back to version 1\n"));
2bd0ea18
NS
2925
2926 dinoc->di_version =
2927 XFS_DINODE_VERSION_1;
507f4e33
NS
2928 INT_SET(dinoc->di_onlink, ARCH_CONVERT,
2929 INT_GET(dinoc->di_nlink, ARCH_CONVERT));
2bd0ea18
NS
2930
2931 *dirty = 1;
2932 } else {
507f4e33 2933 do_warn(_("would convert back to version 1\n"));
2bd0ea18
NS
2934 }
2935 }
2936 }
2937
2938 /*
2939 * ok, if it's still a version 2 inode, it's going
2940 * to stay a version 2 inode. it should have a zero
2941 * onlink field, so clear it.
2942 */
2943 if (dinoc->di_version > XFS_DINODE_VERSION_1 &&
507f4e33
NS
2944 INT_GET(dinoc->di_onlink, ARCH_CONVERT) > 0 &&
2945 fs_inode_nlink > 0) {
2bd0ea18
NS
2946 if (!no_modify) {
2947 do_warn(
507f4e33 2948_("clearing obsolete nlink field in version 2 inode %llu, was %d, now 0\n"),
2bd0ea18 2949 lino, INT_GET(dinoc->di_onlink, ARCH_CONVERT));
46eca962 2950 dinoc->di_onlink = 0;
2bd0ea18
NS
2951 *dirty = 1;
2952 } else {
2953 do_warn(
507f4e33 2954_("would clear obsolete nlink field in version 2 inode %llu, currently %d\n"),
2bd0ea18
NS
2955 lino, INT_GET(dinoc->di_onlink, ARCH_CONVERT));
2956 *dirty = 1;
2957 }
2958 }
2959
2960 return(retval > 0 ? 1 : 0);
2961}
2962
2963/*
2964 * returns 1 if inode is used, 0 if free.
2965 * performs any necessary salvaging actions.
2966 * note that we leave the generation count alone
2967 * because nothing we could set it to would be
2968 * guaranteed to be correct so the best guess for
2969 * the correct value is just to leave it alone.
2970 *
2971 * The trick is detecting empty files. For those,
2972 * the core and the forks should all be in the "empty"
2973 * or zero-length state -- a zero or possibly minimum length
2974 * (in the case of dirs) extent list -- although inline directories
2975 * and symlinks might be handled differently. So it should be
2976 * possible to sanity check them against each other.
2977 *
2978 * If the forks are an empty extent list though, then forget it.
2979 * The file is toast anyway since we can't recover its storage.
2980 *
2981 * Parameters:
2982 * Ins:
2983 * mp -- mount structure
2984 * dino -- pointer to on-disk inode structure
2985 * agno/ino -- inode numbers
2986 * free -- whether the map thinks the inode is free (1 == free)
2987 * ino_discovery -- whether we should examine directory
2988 * contents to discover new inodes
2989 * check_dups -- whether we should check to see if the
2990 * inode references duplicate blocks
2991 * if so, we compare the inode's claimed
2992 * blocks against the contents of the
2993 * duplicate extent list but we don't
2994 * set the bitmap. If not, we set the
2995 * bitmap and try and detect multiply
2996 * claimed blocks using the bitmap.
2997 * Outs:
2998 * dirty -- whether we changed the inode (1 == yes)
2999 * cleared -- whether we cleared the inode (1 == yes). In
3000 * no modify mode, if we would have cleared it
3001 * used -- 1 if the inode is used, 0 if free. In no modify
3002 * mode, whether the inode should be used or free
3003 * isa_dir -- 1 if the inode is a directory, 0 if not. In
3004 * no modify mode, if the inode would be a dir or not.
3005 *
3006 * Return value -- 0 if the inode is good, 1 if it is/was corrupt
3007 */
3008
3009int
3010process_dinode(xfs_mount_t *mp,
3011 xfs_dinode_t *dino,
3012 xfs_agnumber_t agno,
3013 xfs_agino_t ino,
3014 int was_free,
3015 int *dirty,
3016 int *cleared,
3017 int *used,
3018 int ino_discovery,
3019 int check_dups,
3020 int extra_attr_check,
3021 int *isa_dir,
3022 xfs_ino_t *parent)
3023{
3024 const int verify_mode = 0;
3025 const int uncertain = 0;
3026
3027#ifdef XR_INODE_TRACE
3028 fprintf(stderr, "processing inode %d/%d\n", agno, ino);
3029#endif
3030 return(process_dinode_int(mp, dino, agno, ino, was_free, dirty,
3031 cleared, used, verify_mode, uncertain,
3032 ino_discovery, check_dups, extra_attr_check,
3033 isa_dir, parent));
3034}
3035
3036/*
3037 * a more cursory check, check inode core, *DON'T* check forks
3038 * this basically just verifies whether the inode is an inode
3039 * and whether or not it has been totally trashed. returns 0
3040 * if the inode passes the cursory sanity check, 1 otherwise.
3041 */
3042int
3043verify_dinode(xfs_mount_t *mp,
3044 xfs_dinode_t *dino,
3045 xfs_agnumber_t agno,
3046 xfs_agino_t ino)
3047{
3048 xfs_ino_t parent;
3049 int cleared = 0;
3050 int used = 0;
3051 int dirty = 0;
3052 int isa_dir = 0;
3053 const int verify_mode = 1;
3054 const int check_dups = 0;
3055 const int ino_discovery = 0;
3056 const int uncertain = 0;
3057
3058 return(process_dinode_int(mp, dino, agno, ino, 0, &dirty,
3059 &cleared, &used, verify_mode,
3060 uncertain, ino_discovery, check_dups,
3061 0, &isa_dir, &parent));
3062}
3063
3064/*
3065 * like above only for inode on the uncertain list. it sets
3066 * the uncertain flag which makes process_dinode_int quieter.
3067 * returns 0 if the inode passes the cursory sanity check, 1 otherwise.
3068 */
3069int
3070verify_uncertain_dinode(xfs_mount_t *mp,
3071 xfs_dinode_t *dino,
3072 xfs_agnumber_t agno,
3073 xfs_agino_t ino)
3074{
3075 xfs_ino_t parent;
3076 int cleared = 0;
3077 int used = 0;
3078 int dirty = 0;
3079 int isa_dir = 0;
3080 const int verify_mode = 1;
3081 const int check_dups = 0;
3082 const int ino_discovery = 0;
3083 const int uncertain = 1;
3084
3085 return(process_dinode_int(mp, dino, agno, ino, 0, &dirty,
3086 &cleared, &used, verify_mode,
3087 uncertain, ino_discovery, check_dups,
3088 0, &isa_dir, &parent));
3089}