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