]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - repair/dir.c
Update copyright/license notices to match SGI legal prefered boilerplate.
[thirdparty/xfsprogs-dev.git] / repair / dir.c
1 /*
2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <libxfs.h>
20 #include "avl.h"
21 #include "globals.h"
22 #include "agheader.h"
23 #include "incore.h"
24 #include "protos.h"
25 #include "err_protos.h"
26 #include "dinode.h"
27 #include "dir.h"
28 #include "bmap.h"
29
30 #if XFS_DIR_LEAF_MAPSIZE >= XFS_ATTR_LEAF_MAPSIZE
31 #define XR_DA_LEAF_MAPSIZE XFS_DIR_LEAF_MAPSIZE
32 #else
33 #define XR_DA_LEAF_MAPSIZE XFS_ATTR_LEAF_MAPSIZE
34 #endif
35
36
37
38 typedef struct da_hole_map {
39 int lost_holes;
40 int num_holes;
41 struct {
42 int base;
43 int size;
44 } hentries[XR_DA_LEAF_MAPSIZE];
45 } da_hole_map_t;
46
47 /*
48 * takes a name and length (name need not be null-terminated)
49 * and returns 1 if the name contains a '/' or a \0, returns 0
50 * otherwise
51 */
52 int
53 namecheck(char *name, int length)
54 {
55 char *c;
56 int i;
57
58 ASSERT(length < MAXNAMELEN);
59
60 for (c = name, i = 0; i < length; i++, c++) {
61 if (*c == '/' || *c == '\0')
62 return(1);
63 }
64
65 return(0);
66 }
67
68 /*
69 * this routine performs inode discovery and tries to fix things
70 * in place. available redundancy -- inode data size should match
71 * used directory space in inode. returns number of valid directory
72 * entries. a non-zero return value means the directory is bogus
73 * and should be blasted.
74 */
75 /* ARGSUSED */
76 int
77 process_shortform_dir(
78 xfs_mount_t *mp,
79 xfs_ino_t ino,
80 xfs_dinode_t *dip,
81 int ino_discovery,
82 int *dino_dirty, /* out - 1 if dinode buffer dirty? */
83 xfs_ino_t *parent, /* out - NULLFSINO if entry doesn't exist */
84 char *dirname, /* directory pathname */
85 int *repair) /* out - 1 if dir was fixed up */
86 {
87 xfs_dir_shortform_t *sf;
88 xfs_dir_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe;
89 xfs_ino_t lino;
90 int max_size;
91 __int64_t ino_dir_size;
92 int num_entries;
93 int ino_off;
94 int namelen;
95 int i;
96 int junkit;
97 int tmp_len;
98 int tmp_elen;
99 int bad_sfnamelen;
100 ino_tree_node_t *irec_p;
101 char name[MAXNAMELEN + 1];
102
103 #ifdef XR_DIR_TRACE
104 fprintf(stderr, "process_shortform_dir - inode %llu\n", ino);
105 #endif
106
107 sf = &dip->di_u.di_dirsf;
108
109 max_size = XFS_DFORK_DSIZE(dip, mp);
110 num_entries = INT_GET(sf->hdr.count, ARCH_CONVERT);
111 ino_dir_size = INT_GET(dip->di_core.di_size, ARCH_CONVERT);
112 *repair = 0;
113
114 ASSERT(ino_dir_size <= max_size);
115
116 /*
117 * check for bad entry count
118 */
119 if (num_entries * sizeof(xfs_dir_sf_entry_t) + sizeof(xfs_dir_sf_hdr_t)
120 > max_size || num_entries == 0)
121 num_entries = 0xFF;
122
123 /*
124 * run through entries, stop at first bad entry, don't need
125 * to check for .. since that's encoded in its own field
126 */
127 sf_entry = next_sfe = &sf->list[0];
128 for (i = 0; i < num_entries && ino_dir_size >
129 (__psint_t)next_sfe - (__psint_t)sf; i++) {
130 tmp_sfe = NULL;
131 sf_entry = next_sfe;
132 junkit = 0;
133 bad_sfnamelen = 0;
134 XFS_DIR_SF_GET_DIRINO(&sf_entry->inumber, &lino);
135
136 /*
137 * if entry points to self, junk it since only '.' or '..'
138 * should do that and shortform dirs don't contain either
139 * entry. if inode number is invalid, trash entry.
140 * if entry points to special inodes, trash it.
141 * if inode is unknown but number is valid,
142 * add it to the list of uncertain inodes. don't
143 * have to worry about an entry pointing to a
144 * deleted lost+found inode because the entry was
145 * deleted at the same time that the inode was cleared.
146 */
147 if (lino == ino) {
148 junkit = 1;
149 } else if (verify_inum(mp, lino)) {
150 /*
151 * junk the entry, mark lino as NULL since it's bad
152 */
153 do_warn(
154 _("invalid inode number %llu in directory %llu\n"), lino, ino);
155 lino = NULLFSINO;
156 junkit = 1;
157 } else if (lino == mp->m_sb.sb_rbmino) {
158 do_warn(
159 _("entry in shortform dir %llu references rt bitmap inode %llu\n"),
160 ino, lino);
161 junkit = 1;
162 } else if (lino == mp->m_sb.sb_rsumino) {
163 do_warn(
164 _("entry in shortform dir %llu references rt summary inode %llu\n"),
165 ino, lino);
166 junkit = 1;
167 } else if (lino == mp->m_sb.sb_uquotino) {
168 do_warn(
169 _("entry in shortform dir %llu references user quota inode %llu\n"),
170 ino, lino);
171 junkit = 1;
172 } else if (lino == mp->m_sb.sb_gquotino) {
173 do_warn(
174 _("entry in shortform dir %llu references group quota inode %llu\n"),
175 ino, lino);
176 junkit = 1;
177 } else if ((irec_p = find_inode_rec(XFS_INO_TO_AGNO(mp, lino),
178 XFS_INO_TO_AGINO(mp, lino))) != NULL) {
179 /*
180 * if inode is marked free and we're in inode
181 * discovery mode, leave the entry alone for now.
182 * if the inode turns out to be used, we'll figure
183 * that out when we scan it. If the inode really
184 * is free, we'll hit this code again in phase 4
185 * after we've finished inode discovery and blow
186 * out the entry then.
187 */
188 ino_off = XFS_INO_TO_AGINO(mp, lino) -
189 irec_p->ino_startnum;
190 ASSERT(is_inode_confirmed(irec_p, ino_off));
191
192 if (!ino_discovery && is_inode_free(irec_p, ino_off)) {
193 do_warn(
194 _("entry references free inode %llu in shortform directory %llu\n"),
195 lino, ino);
196 junkit = 1;
197 }
198 } else if (ino_discovery) {
199 /*
200 * put the inode on the uncertain list. we'll
201 * pull the inode off the list and check it later.
202 * if the inode turns out be bogus, we'll delete
203 * this entry in phase 6.
204 */
205 add_inode_uncertain(mp, lino, 0);
206 } else {
207 /*
208 * blow the entry out. we know about all
209 * undiscovered entries now (past inode discovery
210 * phase) so this is clearly a bogus entry.
211 */
212 do_warn(
213 _("entry references non-existent inode %llu in shortform dir %llu\n"),
214 lino, ino);
215 junkit = 1;
216 }
217
218 namelen = sf_entry->namelen;
219
220 if (namelen == 0) {
221 /*
222 * if we're really lucky, this is
223 * the last entry in which case we
224 * can use the dir size to set the
225 * namelen value. otherwise, forget
226 * it because we're not going to be
227 * able to find the next entry.
228 */
229 bad_sfnamelen = 1;
230
231 if (i == num_entries - 1) {
232 namelen = ino_dir_size -
233 ((__psint_t) &sf_entry->name[0] -
234 (__psint_t) sf);
235 if (!no_modify) {
236 do_warn(
237 _("zero length entry in shortform dir %llu, resetting to %d\n"),
238 ino, namelen);
239 sf_entry->namelen = namelen;
240 } else {
241 do_warn(
242 _("zero length entry in shortform dir %llu, would set to %d\n"),
243 ino, namelen);
244 }
245 } else {
246 do_warn(
247 _("zero length entry in shortform dir %llu, "),
248 ino);
249 if (!no_modify)
250 do_warn(_("junking %d entries\n"),
251 num_entries - i);
252 else
253 do_warn(_("would junk %d entries\n"),
254 num_entries - i);
255 /*
256 * don't process the rest of the directory,
257 * break out of processing looop
258 */
259 break;
260 }
261 } else if ((__psint_t) sf_entry - (__psint_t) sf +
262 + XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry)
263 > ino_dir_size) {
264 bad_sfnamelen = 1;
265
266 if (i == num_entries - 1) {
267 namelen = ino_dir_size -
268 ((__psint_t) &sf_entry->name[0] -
269 (__psint_t) sf);
270 do_warn(
271 _("size of last entry overflows space left in in shortform dir %llu, "),
272 ino);
273 if (!no_modify) {
274 do_warn(_("resetting to %d\n"),
275 namelen);
276 sf_entry->namelen = namelen;
277 *dino_dirty = 1;
278 } else {
279 do_warn(_("would reset to %d\n"),
280 namelen);
281 }
282 } else {
283 do_warn(
284 _("size of entry #%d overflows space left in in shortform dir %llu\n"),
285 i, ino);
286 if (!no_modify) {
287 if (i == num_entries - 1)
288 do_warn(
289 _("junking entry #%d\n"),
290 i);
291 else
292 do_warn(
293 _("junking %d entries\n"),
294 num_entries - i);
295 } else {
296 if (i == num_entries - 1)
297 do_warn(
298 _("would junk entry #%d\n"),
299 i);
300 else
301 do_warn(
302 _("would junk %d entries\n"),
303 num_entries - i);
304 }
305
306 break;
307 }
308 }
309
310 /*
311 * check for illegal chars in name.
312 * no need to check for bad length because
313 * the length value is stored in a byte
314 * so it can't be too big, it can only wrap
315 */
316 if (namecheck((char *)&sf_entry->name[0], namelen)) {
317 /*
318 * junk entry
319 */
320 do_warn(
321 _("entry contains illegal character in shortform dir %llu\n"),
322 ino);
323 junkit = 1;
324 }
325
326 /*
327 * junk the entry by copying up the rest of the
328 * fork over the current entry and decrementing
329 * the entry count. if we're in no_modify mode,
330 * just issue the warning instead. then continue
331 * the loop with the next_sfe pointer set to the
332 * correct place in the fork and other counters
333 * properly set to reflect the deletion if it
334 * happened.
335 */
336 if (junkit) {
337 bcopy(sf_entry->name, name, namelen);
338 name[namelen] = '\0';
339
340 if (!no_modify) {
341 tmp_elen = XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry);
342 INT_MOD(dip->di_core.di_size,
343 ARCH_CONVERT, -(tmp_elen));
344 ino_dir_size -= tmp_elen;
345
346 tmp_sfe = (xfs_dir_sf_entry_t *)
347 ((__psint_t) sf_entry + tmp_elen);
348 tmp_len = max_size - ((__psint_t) tmp_sfe
349 - (__psint_t) sf);
350
351 memmove(sf_entry, tmp_sfe, tmp_len);
352
353 INT_MOD(sf->hdr.count, ARCH_CONVERT, -1);
354 num_entries--;
355 bzero((void *) ((__psint_t) sf_entry + tmp_len),
356 tmp_elen);
357
358 /*
359 * reset the tmp value to the current
360 * pointer so we'll process the entry
361 * we just moved up
362 */
363 tmp_sfe = sf_entry;
364
365 /*
366 * WARNING: drop the index i by one
367 * so it matches the decremented count
368 * for accurate comparisons later
369 */
370 i--;
371
372 *dino_dirty = 1;
373 *repair = 1;
374
375 do_warn(
376 _("junking entry \"%s\" in directory inode %llu\n"),
377 name, ino);
378 } else {
379 do_warn(
380 _("would have junked entry \"%s\" in directory inode %llu\n"),
381 name, ino);
382 }
383 }
384
385 /*
386 * go onto next entry unless we've just junked an
387 * entry in which the current entry pointer points
388 * to an unprocessed entry. have to take into zero-len
389 * entries into account in no modify mode since we
390 * calculate size based on next_sfe.
391 */
392 next_sfe = (tmp_sfe == NULL)
393 ? (xfs_dir_sf_entry_t *) ((__psint_t) sf_entry
394 + ((!bad_sfnamelen)
395 ? XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry)
396 : sizeof(xfs_dir_sf_entry_t) - 1
397 + namelen))
398 : tmp_sfe;
399 }
400
401 /* sync up sizes and entry counts */
402
403 if (INT_GET(sf->hdr.count, ARCH_CONVERT) != i) {
404 if (no_modify) {
405 do_warn(
406 _("would have corrected entry count in directory %llu from %d to %d\n"),
407 ino, INT_GET(sf->hdr.count, ARCH_CONVERT), i);
408 } else {
409 do_warn(
410 _("corrected entry count in directory %llu, was %d, now %d\n"),
411 ino, INT_GET(sf->hdr.count, ARCH_CONVERT), i);
412 INT_SET(sf->hdr.count, ARCH_CONVERT, i);
413 *dino_dirty = 1;
414 *repair = 1;
415 }
416 }
417
418 if ((__psint_t) next_sfe - (__psint_t) sf != ino_dir_size) {
419 if (no_modify) {
420 do_warn(
421 _("would have corrected directory %llu size from %lld to %lld\n"),
422 ino, (__int64_t) ino_dir_size,
423 (__int64_t)((__psint_t) next_sfe - (__psint_t) sf));
424 } else {
425 do_warn(
426 _("corrected directory %llu size, was %lld, now %lld\n"),
427 ino, (__int64_t) ino_dir_size,
428 (__int64_t)((__psint_t) next_sfe - (__psint_t) sf));
429
430 INT_SET(dip->di_core.di_size,
431 ARCH_CONVERT, (xfs_fsize_t)
432 ((__psint_t) next_sfe - (__psint_t) sf));
433 *dino_dirty = 1;
434 *repair = 1;
435 }
436 }
437 /*
438 * check parent (..) entry
439 */
440 XFS_DIR_SF_GET_DIRINO(&sf->hdr.parent, parent);
441
442 /*
443 * if parent entry is bogus, null it out. we'll fix it later .
444 */
445 if (verify_inum(mp, *parent)) {
446 *parent = NULLFSINO;
447
448 do_warn(
449 _("bogus .. inode number (%llu) in directory inode %llu, "),
450 *parent, ino);
451 if (!no_modify) {
452 do_warn(_("clearing inode number\n"));
453
454 XFS_DIR_SF_PUT_DIRINO(parent, &sf->hdr.parent);
455 *dino_dirty = 1;
456 *repair = 1;
457 } else {
458 do_warn(_("would clear inode number\n"));
459 }
460 } else if (ino == mp->m_sb.sb_rootino && ino != *parent) {
461 /*
462 * root directories must have .. == .
463 */
464 if (!no_modify) {
465 do_warn(
466 _("corrected root directory %llu .. entry, was %llu, now %llu\n"),
467 ino, *parent, ino);
468 *parent = ino;
469 XFS_DIR_SF_PUT_DIRINO(parent, &sf->hdr.parent);
470 *dino_dirty = 1;
471 *repair = 1;
472 } else {
473 do_warn(
474 _("would have corrected root directory %llu .. entry from %llu to %llu\n"),
475 ino, *parent, ino);
476 }
477 } else if (ino == *parent && ino != mp->m_sb.sb_rootino) {
478 /*
479 * likewise, non-root directories can't have .. pointing
480 * to .
481 */
482 *parent = NULLFSINO;
483 do_warn(_("bad .. entry in dir ino %llu, points to self, "),
484 ino);
485 if (!no_modify) {
486 do_warn(_("clearing inode number\n"));
487
488 XFS_DIR_SF_PUT_DIRINO(parent, &sf->hdr.parent);
489 *dino_dirty = 1;
490 *repair = 1;
491 } else {
492 do_warn(_("would clear inode number\n"));
493 }
494 }
495
496 return(0);
497 }
498
499 /*
500 * freespace map for directory leaf blocks (1 bit per byte)
501 * 1 == used, 0 == free
502 */
503 static da_freemap_t dir_freemap[DA_BMAP_SIZE];
504
505 #if 0
506 unsigned char *
507 alloc_da_freemap(xfs_mount_t *mp)
508 {
509 unsigned char *freemap;
510
511 if ((freemap = malloc(mp->m_sb.sb_blocksize)) == NULL)
512 return(NULL);
513
514 bzero(freemap, mp->m_sb.sb_blocksize/NBBY);
515
516 return(freemap);
517 }
518 #endif
519
520 void
521 init_da_freemap(da_freemap_t *dir_freemap)
522 {
523 bzero(dir_freemap, sizeof(da_freemap_t) * DA_BMAP_SIZE);
524 }
525
526 /*
527 * sets directory freemap, returns 1 if there is a conflict
528 * returns 0 if everything's good. the range [start, stop) is set.
529 * right now, we just use the static array since only one directory
530 * block will be processed at once even though the interface allows
531 * you to pass in arbitrary da_freemap_t array's.
532 *
533 * Within a char, the lowest bit of the char represents the byte with
534 * the smallest address
535 */
536 int
537 set_da_freemap(xfs_mount_t *mp, da_freemap_t *map, int start, int stop)
538 {
539 const da_freemap_t mask = 0x1;
540 int i;
541
542 if (start > stop) {
543 /*
544 * allow == relation since [x, x) claims 1 byte
545 */
546 do_warn(_("bad range claimed [%d, %d) in da block\n"),
547 start, stop);
548 return(1);
549 }
550
551 if (stop > mp->m_sb.sb_blocksize) {
552 do_warn(
553 _("byte range end [%d %d) in da block larger than blocksize %d\n"),
554 start, stop, mp->m_sb.sb_blocksize);
555 return(1);
556 }
557
558 for (i = start; i < stop; i ++) {
559 if (map[i / NBBY] & (mask << i % NBBY)) {
560 do_warn(_("multiply claimed byte %d in da block\n"), i);
561 return(1);
562 }
563 map[i / NBBY] |= (mask << i % NBBY);
564 }
565
566 return(0);
567 }
568
569 /*
570 * returns 0 if holemap is consistent with reality (as expressed by
571 * the da_freemap_t). returns 1 if there's a conflict.
572 */
573 int
574 verify_da_freemap(xfs_mount_t *mp, da_freemap_t *map, da_hole_map_t *holes,
575 xfs_ino_t ino, xfs_dablk_t da_bno)
576 {
577 int i, j, start, len;
578 const da_freemap_t mask = 0x1;
579
580 for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++) {
581 if (holes->hentries[i].size == 0)
582 continue;
583
584 start = holes->hentries[i].base;
585 len = holes->hentries[i].size;
586
587 if (start >= mp->m_sb.sb_blocksize ||
588 start + len > mp->m_sb.sb_blocksize) {
589 do_warn(
590 _("hole (start %d, len %d) out of range, block %d, dir ino %llu\n"),
591 start, len, da_bno, ino);
592 return(1);
593 }
594
595 for (j = start; j < start + len; j++) {
596 if ((map[j / NBBY] & (mask << (j % NBBY))) != 0) {
597 /*
598 * bad news -- hole claims a used byte is free
599 */
600 do_warn(
601 _("hole claims used byte %d, block %d, dir ino %llu\n"),
602 j, da_bno, ino);
603 return(1);
604 }
605 }
606 }
607
608 return(0);
609 }
610
611 void
612 process_da_freemap(xfs_mount_t *mp, da_freemap_t *map, da_hole_map_t *holes)
613 {
614 int i, j, in_hole, start, length, smallest, num_holes;
615 const da_freemap_t mask = 0x1;
616
617 num_holes = in_hole = start = length = 0;
618
619 for (i = 0; i < mp->m_sb.sb_blocksize; i++) {
620 if ((map[i / NBBY] & (mask << (i % NBBY))) == 0) {
621 /*
622 * byte is free (unused)
623 */
624 if (in_hole == 1)
625 continue;
626 /*
627 * start of a new hole
628 */
629 in_hole = 1;
630 start = i;
631 } else {
632 /*
633 * byte is used
634 */
635 if (in_hole == 0)
636 continue;
637 /*
638 * end of a hole
639 */
640 in_hole = 0;
641 /*
642 * if the hole disappears, throw it away
643 */
644 length = i - start;
645
646 if (length <= 0)
647 continue;
648
649 num_holes++;
650
651 for (smallest = j = 0; j < XR_DA_LEAF_MAPSIZE; j++) {
652 if (holes->hentries[j].size <
653 holes->hentries[smallest].size)
654 smallest = j;
655
656 }
657 if (length > holes->hentries[smallest].size) {
658 holes->hentries[smallest].base = start;
659 holes->hentries[smallest].size = length;
660 }
661 }
662 }
663
664 /*
665 * see if we have a big hole at the end
666 */
667 if (in_hole == 1) {
668 /*
669 * duplicate of hole placement code above
670 */
671 length = i - start;
672
673 if (length > 0) {
674 num_holes++;
675
676 for (smallest = j = 0; j < XR_DA_LEAF_MAPSIZE; j++) {
677 if (holes->hentries[j].size <
678 holes->hentries[smallest].size)
679 smallest = j;
680
681 }
682 if (length > holes->hentries[smallest].size) {
683 holes->hentries[smallest].base = start;
684 holes->hentries[smallest].size = length;
685 }
686 }
687 }
688
689 holes->lost_holes = MAX(num_holes - XR_DA_LEAF_MAPSIZE, 0);
690 holes->num_holes = num_holes;
691
692 return;
693 }
694
695 /*
696 * returns 1 if the hole info doesn't match, 0 if it does
697 */
698 /* ARGSUSED */
699 int
700 compare_da_freemaps(xfs_mount_t *mp, da_hole_map_t *holemap,
701 da_hole_map_t *block_hmap, int entries,
702 xfs_ino_t ino, xfs_dablk_t da_bno)
703 {
704 int i, k, res, found;
705
706 res = 0;
707
708 /*
709 * we chop holemap->lost_holes down to being two-valued
710 * value (1 or 0) for the test because the filesystem
711 * value is two-valued
712 */
713 if ((holemap->lost_holes > 0 ? 1 : 0) != block_hmap->lost_holes) {
714 if (verbose) {
715 do_warn(
716 _("- derived hole value %d, saw %d, block %d, dir ino %llu\n"),
717 holemap->lost_holes, block_hmap->lost_holes,
718 da_bno, ino);
719 res = 1;
720 } else
721 return(1);
722 }
723
724 for (i = 0; i < entries; i++) {
725 for (found = k = 0; k < entries; k++) {
726 if (holemap->hentries[i].base ==
727 block_hmap->hentries[k].base
728 && holemap->hentries[i].size ==
729 block_hmap->hentries[k].size)
730 found = 1;
731 }
732 if (!found) {
733 if (verbose) {
734 do_warn(
735 _("- derived hole (base %d, size %d) in block %d, dir inode %llu not found\n"),
736 holemap->hentries[i].base,
737 holemap->hentries[i].size,
738 da_bno, ino);
739 res = 1;
740 } else
741 return(1);
742 }
743 }
744
745 return(res);
746 }
747
748 #if 0
749 void
750 test(xfs_mount_t *mp)
751 {
752 int i = 0;
753 da_hole_map_t holemap;
754
755 init_da_freemap(dir_freemap);
756 bzero(&holemap, sizeof(da_hole_map_t));
757
758 set_da_freemap(mp, dir_freemap, 0, 50);
759 set_da_freemap(mp, dir_freemap, 100, 126);
760 set_da_freemap(mp, dir_freemap, 126, 129);
761 set_da_freemap(mp, dir_freemap, 130, 131);
762 set_da_freemap(mp, dir_freemap, 150, 160);
763 process_da_freemap(mp, dir_freemap, &holemap);
764
765 return;
766 }
767 #endif
768
769
770 /*
771 * walk tree from root to the left-most leaf block reading in
772 * blocks and setting up cursor. passes back file block number of the
773 * left-most leaf block if successful (bno). returns 1 if successful,
774 * 0 if unsuccessful.
775 */
776 int
777 traverse_int_dablock(xfs_mount_t *mp,
778 da_bt_cursor_t *da_cursor,
779 xfs_dablk_t *rbno,
780 int whichfork)
781 {
782 xfs_dablk_t bno;
783 int i;
784 xfs_da_intnode_t *node;
785 xfs_dfsbno_t fsbno;
786 xfs_buf_t *bp;
787
788 /*
789 * traverse down left-side of tree until we hit the
790 * left-most leaf block setting up the btree cursor along
791 * the way.
792 */
793 bno = 0;
794 i = -1;
795 node = NULL;
796 da_cursor->active = 0;
797
798 do {
799 /*
800 * read in each block along the way and set up cursor
801 */
802 fsbno = blkmap_get(da_cursor->blkmap, bno);
803
804 if (fsbno == NULLDFSBNO)
805 goto error_out;
806
807 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
808 XFS_FSB_TO_BB(mp, 1), 0);
809 if (!bp) {
810 if (whichfork == XFS_DATA_FORK)
811 do_warn(_("can't read block %u (fsbno %llu) "
812 "for directory inode %llu\n"),
813 bno, fsbno, da_cursor->ino);
814 else
815 do_warn(_("can't read block %u (fsbno %llu) "
816 "for attrbute fork of inode %llu\n"),
817 bno, fsbno, da_cursor->ino);
818 goto error_out;
819 }
820
821 node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
822
823 if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) {
824 do_warn(_("bad dir/attr magic number in inode %llu, "
825 "file bno = %u, fsbno = %llu\n"),
826 da_cursor->ino, bno, fsbno);
827 libxfs_putbuf(bp);
828 goto error_out;
829 }
830 if (INT_GET(node->hdr.count, ARCH_CONVERT) >
831 mp->m_dir_node_ents) {
832 do_warn(_("bad record count in inode %llu, "
833 "count = %d, max = %d\n"),
834 da_cursor->ino,
835 INT_GET(node->hdr.count, ARCH_CONVERT),
836 mp->m_dir_node_ents);
837 libxfs_putbuf(bp);
838 goto error_out;
839 }
840
841 /*
842 * maintain level counter
843 */
844 if (i == -1)
845 i = da_cursor->active = INT_GET(node->hdr.level, ARCH_CONVERT);
846 else {
847 if (INT_GET(node->hdr.level, ARCH_CONVERT) == i - 1) {
848 i--;
849 } else {
850 if (whichfork == XFS_DATA_FORK)
851 do_warn(_("bad directory btree for "
852 "directory inode %llu\n"),
853 da_cursor->ino);
854 else
855 do_warn(_("bad attribute fork btree "
856 "for inode %llu\n"),
857 da_cursor->ino);
858 libxfs_putbuf(bp);
859 goto error_out;
860 }
861 }
862
863 da_cursor->level[i].hashval =
864 INT_GET(node->btree[0].hashval, ARCH_CONVERT);
865 da_cursor->level[i].bp = bp;
866 da_cursor->level[i].bno = bno;
867 da_cursor->level[i].index = 0;
868 #ifdef XR_DIR_TRACE
869 da_cursor->level[i].n = XFS_BUF_TO_DA_INTNODE(bp);
870 #endif
871
872 /*
873 * set up new bno for next level down
874 */
875 bno = INT_GET(node->btree[0].before, ARCH_CONVERT);
876 } while(node != NULL && i > 1);
877
878 /*
879 * now return block number and get out
880 */
881 *rbno = da_cursor->level[0].bno = bno;
882 return(1);
883
884 error_out:
885 while (i > 1 && i <= da_cursor->active) {
886 libxfs_putbuf(da_cursor->level[i].bp);
887 i++;
888 }
889
890 return(0);
891 }
892
893 /*
894 * blow out buffer for this level and all the rest above as well
895 * if error == 0, we are not expecting to encounter any unreleased
896 * buffers (e.g. if we do, it's a mistake). if error == 1, we're
897 * in an error-handling case so unreleased buffers may exist.
898 */
899 void
900 release_da_cursor_int(xfs_mount_t *mp,
901 da_bt_cursor_t *cursor,
902 int prev_level,
903 int error)
904 {
905 int level = prev_level + 1;
906
907 if (cursor->level[level].bp != NULL) {
908 if (!error) {
909 do_warn(_("release_da_cursor_int got unexpected "
910 "non-null bp, dabno = %u\n"),
911 cursor->level[level].bno);
912 }
913 ASSERT(error != 0);
914
915 libxfs_putbuf(cursor->level[level].bp);
916 cursor->level[level].bp = NULL;
917 }
918
919 if (level < cursor->active)
920 release_da_cursor_int(mp, cursor, level, error);
921
922 return;
923 }
924
925 void
926 release_da_cursor(xfs_mount_t *mp,
927 da_bt_cursor_t *cursor,
928 int prev_level)
929 {
930 release_da_cursor_int(mp, cursor, prev_level, 0);
931 }
932
933 void
934 err_release_da_cursor(xfs_mount_t *mp,
935 da_bt_cursor_t *cursor,
936 int prev_level)
937 {
938 release_da_cursor_int(mp, cursor, prev_level, 1);
939 }
940
941 /*
942 * like traverse_int_dablock only it does far less checking
943 * and doesn't maintain the cursor. Just gets you to the
944 * leftmost block in the directory. returns the fsbno
945 * of that block if successful, NULLDFSBNO if not.
946 */
947 xfs_dfsbno_t
948 get_first_dblock_fsbno(xfs_mount_t *mp,
949 xfs_ino_t ino,
950 xfs_dinode_t *dino)
951 {
952 xfs_dablk_t bno;
953 int i;
954 xfs_da_intnode_t *node;
955 xfs_dfsbno_t fsbno;
956 xfs_buf_t *bp;
957
958 /*
959 * traverse down left-side of tree until we hit the
960 * left-most leaf block setting up the btree cursor along
961 * the way.
962 */
963 bno = 0;
964 i = -1;
965 node = NULL;
966
967 fsbno = get_bmapi(mp, dino, ino, bno, XFS_DATA_FORK);
968
969 if (fsbno == NULLDFSBNO) {
970 do_warn(_("bmap of block #%u of inode %llu failed\n"),
971 bno, ino);
972 return(fsbno);
973 }
974
975 if (INT_GET(dino->di_core.di_size, ARCH_CONVERT) <= XFS_LBSIZE(mp))
976 return(fsbno);
977
978 do {
979 /*
980 * walk down left side of btree, release buffers as you
981 * go. if the root block is a leaf (single-level btree),
982 * just return it.
983 *
984 */
985
986 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
987 XFS_FSB_TO_BB(mp, 1), 0);
988 if (!bp) {
989 do_warn(_("can't read block %u (fsbno %llu) "
990 "for directory inode %llu\n"),
991 bno, fsbno, ino);
992 return(NULLDFSBNO);
993 }
994
995 node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
996
997 if (XFS_DA_NODE_MAGIC !=
998 INT_GET(node->hdr.info.magic, ARCH_CONVERT)) {
999 do_warn(_("bad dir/attr magic number in inode %llu, "
1000 "file bno = %u, fsbno = %llu\n"),
1001 ino, bno, fsbno);
1002 libxfs_putbuf(bp);
1003 return(NULLDFSBNO);
1004 }
1005
1006 if (i == -1)
1007 i = INT_GET(node->hdr.level, ARCH_CONVERT);
1008 bno = INT_GET(node->btree[0].before, ARCH_CONVERT);
1009
1010 libxfs_putbuf(bp);
1011
1012 fsbno = get_bmapi(mp, dino, ino, bno, XFS_DATA_FORK);
1013
1014 if (fsbno == NULLDFSBNO) {
1015 do_warn(_("bmap of block #%u of inode %llu failed\n"),
1016 bno, ino);
1017 return(NULLDFSBNO);
1018 }
1019
1020 i--;
1021 } while(i > 0);
1022
1023 return(fsbno);
1024 }
1025
1026 /*
1027 * make sure that all entries in all blocks along the right side of
1028 * of the tree are used and hashval's are consistent. level is the
1029 * level of the descendent block. returns 0 if good (even if it had
1030 * to be fixed up), and 1 if bad. The right edge of the tree is
1031 * technically a block boundary. this routine should be used then
1032 * instead of verify_da_path().
1033 */
1034 int
1035 verify_final_da_path(xfs_mount_t *mp,
1036 da_bt_cursor_t *cursor,
1037 const int p_level)
1038 {
1039 xfs_da_intnode_t *node;
1040 xfs_dahash_t hashval;
1041 int bad = 0;
1042 int entry;
1043 int this_level = p_level + 1;
1044
1045 #ifdef XR_DIR_TRACE
1046 fprintf(stderr, "in verify_final_da_path, this_level = %d\n",
1047 this_level);
1048 #endif
1049 /*
1050 * the index should point to the next "unprocessed" entry
1051 * in the block which should be the final (rightmost) entry
1052 */
1053 entry = cursor->level[this_level].index;
1054 node = (xfs_da_intnode_t *)XFS_BUF_PTR(cursor->level[this_level].bp);
1055 /*
1056 * check internal block consistency on this level -- ensure
1057 * that all entries are used, encountered and expected hashvals
1058 * match, etc.
1059 */
1060 if (entry != INT_GET(node->hdr.count, ARCH_CONVERT) - 1) {
1061 do_warn(_("directory/attribute block used/count "
1062 "inconsistency - %d/%hu\n"),
1063 entry, INT_GET(node->hdr.count, ARCH_CONVERT));
1064 bad++;
1065 }
1066 /*
1067 * hash values monotonically increasing ???
1068 */
1069 if (cursor->level[this_level].hashval >=
1070 INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) {
1071 do_warn(_("directory/attribute block hashvalue inconsistency, "
1072 "expected > %u / saw %u\n"),
1073 cursor->level[this_level].hashval,
1074 INT_GET(node->btree[entry].hashval, ARCH_CONVERT));
1075 bad++;
1076 }
1077 if (INT_GET(node->hdr.info.forw, ARCH_CONVERT) != 0) {
1078 do_warn(_("bad directory/attribute forward block pointer, "
1079 "expected 0, saw %u\n"),
1080 INT_GET(node->hdr.info.forw, ARCH_CONVERT));
1081 bad++;
1082 }
1083 if (bad) {
1084 do_warn(_("bad directory block in dir ino %llu\n"),
1085 cursor->ino);
1086 return(1);
1087 }
1088 /*
1089 * keep track of greatest block # -- that gets
1090 * us the length of the directory
1091 */
1092 if (cursor->level[this_level].bno > cursor->greatest_bno)
1093 cursor->greatest_bno = cursor->level[this_level].bno;
1094
1095 /*
1096 * ok, now check descendant block number against this level
1097 */
1098 if (cursor->level[p_level].bno !=
1099 INT_GET(node->btree[entry].before, ARCH_CONVERT)) {
1100 #ifdef XR_DIR_TRACE
1101 fprintf(stderr, "bad directory btree pointer, child bno should "
1102 "be %d, block bno is %d, hashval is %u\n",
1103 INT_GET(node->btree[entry].before, ARCH_CONVERT),
1104 cursor->level[p_level].bno,
1105 cursor->level[p_level].hashval);
1106 fprintf(stderr, "verify_final_da_path returns 1 (bad) #1a\n");
1107 #endif
1108 return(1);
1109 }
1110
1111 if (cursor->level[p_level].hashval !=
1112 INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) {
1113 if (!no_modify) {
1114 do_warn(_("correcting bad hashval in non-leaf "
1115 "dir/attr block\n\tin (level %d) in "
1116 "inode %llu.\n"),
1117 this_level, cursor->ino);
1118 INT_SET(node->btree[entry].hashval, ARCH_CONVERT,
1119 cursor->level[p_level].hashval);
1120 cursor->level[this_level].dirty++;
1121 } else {
1122 do_warn(_("would correct bad hashval in non-leaf "
1123 "dir/attr block\n\tin (level %d) in "
1124 "inode %llu.\n"),
1125 this_level, cursor->ino);
1126 }
1127 }
1128
1129 /*
1130 * Note: squirrel hashval away _before_ releasing the
1131 * buffer, preventing a use-after-free problem.
1132 */
1133 hashval = INT_GET(node->btree[entry].hashval, ARCH_CONVERT);
1134
1135 /*
1136 * release/write buffer
1137 */
1138 ASSERT(cursor->level[this_level].dirty == 0 ||
1139 (cursor->level[this_level].dirty && !no_modify));
1140
1141 if (cursor->level[this_level].dirty && !no_modify)
1142 libxfs_writebuf(cursor->level[this_level].bp, 0);
1143 else
1144 libxfs_putbuf(cursor->level[this_level].bp);
1145
1146 cursor->level[this_level].bp = NULL;
1147
1148 /*
1149 * bail out if this is the root block (top of tree)
1150 */
1151 if (this_level >= cursor->active) {
1152 #ifdef XR_DIR_TRACE
1153 fprintf(stderr, "verify_final_da_path returns 0 (ok)\n");
1154 #endif
1155 return(0);
1156 }
1157 /*
1158 * set hashvalue to correctly reflect the now-validated
1159 * last entry in this block and continue upwards validation
1160 */
1161 cursor->level[this_level].hashval = hashval;
1162 return(verify_final_da_path(mp, cursor, this_level));
1163 }
1164
1165 /*
1166 * Verifies the path from a descendant block up to the root.
1167 * Should be called when the descendant level traversal hits
1168 * a block boundary before crossing the boundary (reading in a new
1169 * block).
1170 *
1171 * the directory/attr btrees work differently to the other fs btrees.
1172 * each interior block contains records that are <hashval, bno>
1173 * pairs. The bno is a file bno, not a filesystem bno. The last
1174 * hashvalue in the block <bno> will be <hashval>. BUT unlike
1175 * the freespace btrees, the *last* value in each block gets
1176 * propagated up the tree instead of the first value in each block.
1177 * that is, the interior records point to child blocks and the *greatest*
1178 * hash value contained by the child block is the one the block above
1179 * uses as the key for the child block.
1180 *
1181 * level is the level of the descendent block. returns 0 if good,
1182 * and 1 if bad. The descendant block may be a leaf block.
1183 *
1184 * the invariant here is that the values in the cursor for the
1185 * levels beneath this level (this_level) and the cursor index
1186 * for this level *must* be valid.
1187 *
1188 * that is, the hashval/bno info is accurate for all
1189 * DESCENDANTS and match what the node[index] information
1190 * for the current index in the cursor for this level.
1191 *
1192 * the index values in the cursor for the descendant level
1193 * are allowed to be off by one as they will reflect the
1194 * next entry at those levels to be processed.
1195 *
1196 * the hashvalue for the current level can't be set until
1197 * we hit the last entry in the block so, it's garbage
1198 * until set by this routine.
1199 *
1200 * bno and bp for the current block/level are always valid
1201 * since they have to be set so we can get a buffer for the
1202 * block.
1203 */
1204 int
1205 verify_da_path(xfs_mount_t *mp,
1206 da_bt_cursor_t *cursor,
1207 const int p_level)
1208 {
1209 xfs_da_intnode_t *node;
1210 xfs_da_intnode_t *newnode;
1211 xfs_dfsbno_t fsbno;
1212 xfs_dablk_t dabno;
1213 xfs_buf_t *bp;
1214 int bad;
1215 int entry;
1216 int this_level = p_level + 1;
1217
1218 /*
1219 * index is currently set to point to the entry that
1220 * should be processed now in this level.
1221 */
1222 entry = cursor->level[this_level].index;
1223 node = (xfs_da_intnode_t *)XFS_BUF_PTR(cursor->level[this_level].bp);
1224
1225 /*
1226 * if this block is out of entries, validate this
1227 * block and move on to the next block.
1228 * and update cursor value for said level
1229 */
1230 if (entry >= INT_GET(node->hdr.count, ARCH_CONVERT)) {
1231 /*
1232 * update the hash value for this level before
1233 * validating it. bno value should be ok since
1234 * it was set when the block was first read in.
1235 */
1236 cursor->level[this_level].hashval =
1237 INT_GET(node->btree[entry - 1].hashval, ARCH_CONVERT);
1238
1239 /*
1240 * keep track of greatest block # -- that gets
1241 * us the length of the directory
1242 */
1243 if (cursor->level[this_level].bno > cursor->greatest_bno)
1244 cursor->greatest_bno = cursor->level[this_level].bno;
1245
1246 /*
1247 * validate the path for the current used-up block
1248 * before we trash it
1249 */
1250 if (verify_da_path(mp, cursor, this_level))
1251 return(1);
1252 /*
1253 * ok, now get the next buffer and check sibling pointers
1254 */
1255 dabno = INT_GET(node->hdr.info.forw, ARCH_CONVERT);
1256 ASSERT(dabno != 0);
1257 fsbno = blkmap_get(cursor->blkmap, dabno);
1258
1259 if (fsbno == NULLDFSBNO) {
1260 do_warn(_("can't get map info for block %u "
1261 "of directory inode %llu\n"),
1262 dabno, cursor->ino);
1263 return(1);
1264 }
1265
1266 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
1267 XFS_FSB_TO_BB(mp, 1), 0);
1268 if (!bp) {
1269 do_warn(_("can't read block %u (%llu) "
1270 "for directory inode %llu\n"),
1271 dabno, fsbno, cursor->ino);
1272 return(1);
1273 }
1274
1275 newnode = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
1276 /*
1277 * verify magic number and back pointer, sanity-check
1278 * entry count, verify level
1279 */
1280 bad = 0;
1281 if (XFS_DA_NODE_MAGIC !=
1282 INT_GET(newnode->hdr.info.magic, ARCH_CONVERT)) {
1283 do_warn(_("bad magic number %x in block %u (%llu) "
1284 "for directory inode %llu\n"),
1285 INT_GET(newnode->hdr.info.magic, ARCH_CONVERT),
1286 dabno, fsbno, cursor->ino);
1287 bad++;
1288 }
1289 if (INT_GET(newnode->hdr.info.back, ARCH_CONVERT) !=
1290 cursor->level[this_level].bno) {
1291 do_warn(_("bad back pointer in block %u (%llu) "
1292 "for directory inode %llu\n"),
1293 dabno, fsbno, cursor->ino);
1294 bad++;
1295 }
1296 if (INT_GET(newnode->hdr.count, ARCH_CONVERT) >
1297 mp->m_dir_node_ents) {
1298 do_warn(_("entry count %d too large in block %u (%llu) "
1299 "for directory inode %llu\n"),
1300 INT_GET(newnode->hdr.count, ARCH_CONVERT),
1301 dabno, fsbno, cursor->ino);
1302 bad++;
1303 }
1304 if (INT_GET(newnode->hdr.level, ARCH_CONVERT) != this_level) {
1305 do_warn(_("bad level %d in block %u (%llu) "
1306 "for directory inode %llu\n"),
1307 INT_GET(newnode->hdr.level, ARCH_CONVERT),
1308 dabno, fsbno, cursor->ino);
1309 bad++;
1310 }
1311 if (bad) {
1312 #ifdef XR_DIR_TRACE
1313 fprintf(stderr, "verify_da_path returns 1 (bad) #4\n");
1314 #endif
1315 libxfs_putbuf(bp);
1316 return(1);
1317 }
1318 /*
1319 * update cursor, write out the *current* level if
1320 * required. don't write out the descendant level
1321 */
1322 ASSERT(cursor->level[this_level].dirty == 0 ||
1323 (cursor->level[this_level].dirty && !no_modify));
1324
1325 if (cursor->level[this_level].dirty && !no_modify)
1326 libxfs_writebuf(cursor->level[this_level].bp, 0);
1327 else
1328 libxfs_putbuf(cursor->level[this_level].bp);
1329 cursor->level[this_level].bp = bp;
1330 cursor->level[this_level].dirty = 0;
1331 cursor->level[this_level].bno = dabno;
1332 cursor->level[this_level].hashval =
1333 INT_GET(newnode->btree[0].hashval, ARCH_CONVERT);
1334 #ifdef XR_DIR_TRACE
1335 cursor->level[this_level].n = newnode;
1336 #endif
1337 node = newnode;
1338
1339 entry = cursor->level[this_level].index = 0;
1340 }
1341 /*
1342 * ditto for block numbers
1343 */
1344 if (cursor->level[p_level].bno !=
1345 INT_GET(node->btree[entry].before, ARCH_CONVERT)) {
1346 #ifdef XR_DIR_TRACE
1347 fprintf(stderr, "bad directory btree pointer, child bno "
1348 "should be %d, block bno is %d, hashval is %u\n",
1349 INT_GET(node->btree[entry].before, ARCH_CONVERT),
1350 cursor->level[p_level].bno,
1351 cursor->level[p_level].hashval);
1352 fprintf(stderr, "verify_da_path returns 1 (bad) #1a\n");
1353 #endif
1354 return(1);
1355 }
1356 /*
1357 * ok, now validate last hashvalue in the descendant
1358 * block against the hashval in the current entry
1359 */
1360 if (cursor->level[p_level].hashval !=
1361 INT_GET(node->btree[entry].hashval, ARCH_CONVERT)) {
1362 if (!no_modify) {
1363 do_warn(_("correcting bad hashval in interior "
1364 "dir/attr block\n\tin (level %d) in "
1365 "inode %llu.\n"),
1366 this_level, cursor->ino);
1367 INT_SET(node->btree[entry].hashval, ARCH_CONVERT,
1368 cursor->level[p_level].hashval);
1369 cursor->level[this_level].dirty++;
1370 } else {
1371 do_warn(_("would correct bad hashval in interior "
1372 "dir/attr block\n\tin (level %d) in "
1373 "inode %llu.\n"),
1374 this_level, cursor->ino);
1375 }
1376 }
1377 /*
1378 * increment index for this level to point to next entry
1379 * (which should point to the next descendant block)
1380 */
1381 cursor->level[this_level].index++;
1382 #ifdef XR_DIR_TRACE
1383 fprintf(stderr, "verify_da_path returns 0 (ok)\n");
1384 #endif
1385 return(0);
1386 }
1387
1388 #if 0
1389 /*
1390 * handles junking directory leaf block entries that have zero lengths
1391 * buf_dirty is an in/out, set to 1 if the leaf was modified.
1392 * we do NOT initialize it to zero if nothing happened because it
1393 * may be already set by the caller. Assumes that the block
1394 * has been compacted before calling this routine.
1395 */
1396 void
1397 junk_zerolen_dir_leaf_entries(
1398 xfs_mount_t *mp,
1399 xfs_dir_leafblock_t *leaf,
1400 xfs_ino_t ino,
1401 int *buf_dirty)
1402 {
1403 xfs_dir_leaf_entry_t *entry;
1404 xfs_dir_leaf_name_t *namest;
1405 xfs_dir_leaf_hdr_t *hdr;
1406 xfs_dir_leaf_map_t *map;
1407 xfs_ino_t tmp_ino;
1408 int bytes;
1409 int tmp_bytes;
1410 int current_hole = 0;
1411 int i;
1412 int j;
1413 int tmp;
1414 int start;
1415 int before;
1416 int after;
1417 int smallest;
1418 int tablesize;
1419
1420 entry = &leaf->entries[0];
1421 hdr = &leaf->hdr;
1422
1423 /*
1424 * we can convert the entries to one character entries
1425 * as long as we have space. Once we run out, then
1426 * we have to delete really delete (copy over) an entry.
1427 * however, that frees up some space that we could use ...
1428 *
1429 * so the idea is, we'll use up space from all the holes,
1430 * potentially leaving each hole too small to do any good.
1431 * then if need to, we'll delete entries and use that space
1432 * up from the top-most byte down. that may leave a 4th hole
1433 * but we can represent that by correctly setting the value
1434 * of firstused. that leaves any hole between the end of
1435 * the entry list and firstused so it doesn't have to be
1436 * recorded in the hole map.
1437 */
1438
1439 for (bytes = i = 0; i < INT_GET(hdr->count, ARCH_CONVERT); entry++, i++) {
1440 /*
1441 * skip over entries that are good or already converted
1442 */
1443 if (entry->namelen != 0)
1444 continue;
1445
1446 *buf_dirty = 1;
1447 #if 0
1448 /*
1449 * try and use up existing holes first until they get
1450 * too small, then set bytes to the # of bytes between
1451 * the current heap beginning and the last used byte
1452 * in the entry table.
1453 */
1454 if (bytes < sizeof(xfs_dir_leaf_name_t) &&
1455 current_hole < XFS_DIR_LEAF_MAPSIZE) {
1456 /*
1457 * skip over holes that are too small
1458 */
1459 while (current_hole < XFS_DIR_LEAF_MAPSIZE &&
1460 INT_GET(hdr->freemap[current_hole].size, ARCH_CONVERT) <
1461 sizeof(xfs_dir_leaf_name_t)) {
1462 current_hole++;
1463 }
1464
1465 if (current_hole < XFS_DIR_LEAF_MAPSIZE)
1466 bytes = INT_GET(hdr->freemap[current_hole].size, ARCH_CONVERT);
1467 else
1468 bytes = (int) INT_GET(hdr->firstused, ARCH_CONVERT) -
1469 ((__psint_t) &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)] -
1470 (__psint_t) leaf);
1471 }
1472 #endif
1473 current_hole = 0;
1474
1475 for (map = &hdr->freemap[0];
1476 current_hole < XFS_DIR_LEAF_MAPSIZE &&
1477 INT_GET(map->size, ARCH_CONVERT) < sizeof(xfs_dir_leaf_name_t);
1478 map++) {
1479 current_hole++;
1480 }
1481
1482 /*
1483 * if we can use an existing hole, do it. otherwise,
1484 * delete entries until the deletions create a big enough
1485 * hole to convert another entry. then use up those bytes
1486 * bytes until you run low. then delete entries again ...
1487 */
1488 if (current_hole < XFS_DIR_LEAF_MAPSIZE) {
1489 ASSERT(sizeof(xfs_dir_leaf_name_t) <= bytes);
1490
1491 do_warn(_("marking bad entry in directory inode %llu\n"),
1492 ino);
1493
1494 entry->namelen = 1;
1495 INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(hdr->freemap[current_hole].base, ARCH_CONVERT) +
1496 bytes - sizeof(xfs_dir_leaf_name_t));
1497
1498 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
1499 tmp_ino = NULLFSINO;
1500 XFS_DIR_SF_PUT_DIRINO(&tmp_ino, &namest->inumber);
1501 namest->name[0] = '/';
1502
1503 if (INT_GET(entry->nameidx, ARCH_CONVERT) < INT_GET(hdr->firstused, ARCH_CONVERT))
1504 INT_SET(hdr->firstused, ARCH_CONVERT, INT_GET(entry->nameidx, ARCH_CONVERT));
1505 INT_MOD(hdr->freemap[current_hole].size, ARCH_CONVERT, -(sizeof(xfs_dir_leaf_name_t)));
1506 INT_MOD(hdr->namebytes, ARCH_CONVERT, +1);
1507 } else {
1508 /*
1509 * delete the table entry and try and account for the
1510 * space in the holemap. don't have to update namebytes
1511 * or firstused since we're not actually deleting any
1512 * bytes from the heap. following code swiped from
1513 * xfs_dir_leaf_remove() in xfs_dir_leaf.c
1514 */
1515 INT_MOD(hdr->count, ARCH_CONVERT, -1);
1516 do_warn(
1517 _("deleting zero length entry in directory inode %llu\n"),
1518 ino);
1519 /*
1520 * overwrite the bad entry unless it's the
1521 * last entry in the list (highly unlikely).
1522 * zero out the free'd bytes.
1523 */
1524 if (INT_GET(hdr->count, ARCH_CONVERT) - i > 0) {
1525 memmove(entry, entry + 1, (INT_GET(hdr->count, ARCH_CONVERT) - i) *
1526 sizeof(xfs_dir_leaf_entry_t));
1527 }
1528 bzero((void *) ((__psint_t) entry +
1529 (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1) *
1530 sizeof(xfs_dir_leaf_entry_t)),
1531 sizeof(xfs_dir_leaf_entry_t));
1532
1533 start = (__psint_t) &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)] -
1534 (__psint_t) &leaf;
1535 tablesize = sizeof(xfs_dir_leaf_entry_t) *
1536 (INT_GET(hdr->count, ARCH_CONVERT) + 1) + sizeof(xfs_dir_leaf_hdr_t);
1537 map = &hdr->freemap[0];
1538 tmp = INT_GET(map->size, ARCH_CONVERT);
1539 before = after = -1;
1540 smallest = XFS_DIR_LEAF_MAPSIZE - 1;
1541 for (j = 0; j < XFS_DIR_LEAF_MAPSIZE; map++, j++) {
1542 ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp));
1543 ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp));
1544 if (INT_GET(map->base, ARCH_CONVERT) == tablesize) {
1545 INT_MOD(map->base, ARCH_CONVERT, -(sizeof(xfs_dir_leaf_entry_t)));
1546 INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
1547 }
1548
1549 if ((INT_GET(map->base, ARCH_CONVERT) + INT_GET(map->size, ARCH_CONVERT)) == start) {
1550 before = j;
1551 } else if (INT_GET(map->base, ARCH_CONVERT) == start +
1552 sizeof(xfs_dir_leaf_entry_t)) {
1553 after = j;
1554 } else if (INT_GET(map->size, ARCH_CONVERT) < tmp) {
1555 tmp = INT_GET(map->size, ARCH_CONVERT);
1556 smallest = j;
1557 }
1558 }
1559
1560 /*
1561 * Coalesce adjacent freemap regions,
1562 * or replace the smallest region.
1563 */
1564 if ((before >= 0) || (after >= 0)) {
1565 if ((before >= 0) && (after >= 0)) {
1566 map = &hdr->freemap[before];
1567 INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
1568 INT_MOD(map->size, ARCH_CONVERT, INT_GET(hdr->freemap[after].size, ARCH_CONVERT));
1569 hdr->freemap[after].base = 0;
1570 hdr->freemap[after].size = 0;
1571 } else if (before >= 0) {
1572 map = &hdr->freemap[before];
1573 INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
1574 } else {
1575 map = &hdr->freemap[after];
1576 INT_SET(map->base, ARCH_CONVERT, start);
1577 INT_MOD(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
1578 }
1579 } else {
1580 /*
1581 * Replace smallest region
1582 * (if it is smaller than free'd entry)
1583 */
1584 map = &hdr->freemap[smallest];
1585 if (INT_GET(map->size, ARCH_CONVERT) < sizeof(xfs_dir_leaf_entry_t)) {
1586 INT_SET(map->base, ARCH_CONVERT, start);
1587 INT_SET(map->size, ARCH_CONVERT, sizeof(xfs_dir_leaf_entry_t));
1588 }
1589 /*
1590 * mark as needing compaction
1591 */
1592 hdr->holes = 1;
1593 }
1594 #if 0
1595 /*
1596 * do we have to delete stuff or is there
1597 * room for deletions?
1598 */
1599 ASSERT(current_hole == XFS_DIR_LEAF_MAPSIZE);
1600
1601 /*
1602 * here, bytes == number of unused bytes from
1603 * end of list to top (beginning) of heap
1604 * (firstused). It's ok to leave extra
1605 * unused bytes in that region because they
1606 * wind up before firstused (which we reset
1607 * appropriately
1608 */
1609 if (bytes < sizeof(xfs_dir_leaf_name_t)) {
1610 /*
1611 * have to delete an entry because
1612 * we have no room to convert it to
1613 * a bad entry
1614 */
1615 do_warn(
1616 _("deleting entry in directory inode %llu\n"),
1617 ino);
1618 /*
1619 * overwrite the bad entry unless it's the
1620 * last entry in the list (highly unlikely).
1621 */
1622 if (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1> 0) {
1623 memmove(entry, entry + 1,
1624 (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1) *
1625 sizeof(xfs_dir_leaf_entry_t));
1626 }
1627 bzero((void *) ((__psint_t) entry +
1628 (INT_GET(leaf->hdr.count, ARCH_CONVERT) - i - 1) *
1629 sizeof(xfs_dir_leaf_entry_t)),
1630 sizeof(xfs_dir_leaf_entry_t));
1631
1632 /*
1633 * bump up free byte count, drop other
1634 * index vars since the table just
1635 * shrank by one entry and we don't
1636 * want to miss any as we walk the table
1637 */
1638 bytes += sizeof(xfs_dir_leaf_entry_t);
1639 INT_MOD(leaf->hdr.count, ARCH_CONVERT, -1);
1640 entry--;
1641 i--;
1642 } else {
1643 /*
1644 * convert entry using the bytes in between
1645 * the end of the entry table and the heap
1646 */
1647 entry->namelen = 1;
1648 INT_MOD(leaf->hdr.firstused, ARCH_CONVERT, -(sizeof(xfs_dir_leaf_name_t)));
1649 INT_SET(entry->nameidx, ARCH_CONVERT, INT_GET(leaf->hdr.firstused, ARCH_CONVERT));
1650
1651 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf,
1652 INT_GET(entry->nameidx, ARCH_CONVERT));
1653 tmp_ino = NULLFSINO;
1654 XFS_DIR_SF_PUT_DIRINO(&tmp_ino,
1655 &namest->inumber);
1656 namest->name[0] = '/';
1657
1658 bytes -= sizeof(xfs_dir_leaf_entry_t);
1659 }
1660 #endif
1661 }
1662 }
1663
1664 return;
1665 }
1666 #endif
1667
1668 static char dirbuf[64 * 1024];
1669
1670 /*
1671 * called by both node dir and leaf dir processing routines
1672 * validates all contents *but* the sibling pointers (forw/back)
1673 * and the magic number.
1674 *
1675 * returns 0 if the directory is ok or has been brought to the
1676 * stage that it can be fixed up later (in phase 6),
1677 * 1 if it has to be junked.
1678 *
1679 * Right now we fix a lot of things (TBD == to be deleted).
1680 *
1681 * incorrect . entries - inode # is corrected
1682 * entries with mismatched hashvalue/name strings - hashvalue reset
1683 * entries whose hashvalues are out-of-order - entry marked TBD
1684 * .. entries with invalid inode numbers - entry marked TBD
1685 * entries with invalid inode numbers - entry marked TBD
1686 * multiple . entries - all but the first entry are marked TBD
1687 * zero-length entries - entry is deleted
1688 * entries with an out-of-bounds name index ptr - entry is deleted
1689 *
1690 * entries marked TBD have the first character of the name (which
1691 * lives in the heap) have the first character in the name set
1692 * to '/' -- an illegal value.
1693 *
1694 * entries deleted right here are deleted by blowing away the entry
1695 * (but leaving the heap untouched). any space that was used
1696 * by the deleted entry will be reclaimed by the block freespace
1697 * (da_freemap) processing code.
1698 *
1699 * if two entries claim the same space in the heap (say, due to
1700 * bad entry name index pointers), we lose the directory. We could
1701 * try harder to fix this but it'll do for now.
1702 */
1703 /* ARGSUSED */
1704 int
1705 process_leaf_dir_block(
1706 xfs_mount_t *mp,
1707 xfs_dir_leafblock_t *leaf,
1708 xfs_dablk_t da_bno,
1709 xfs_ino_t ino,
1710 xfs_dahash_t last_hashval, /* last hashval encountered */
1711 int ino_discovery,
1712 blkmap_t *blkmap,
1713 int *dot,
1714 int *dotdot,
1715 xfs_ino_t *parent,
1716 int *buf_dirty, /* is buffer dirty? */
1717 xfs_dahash_t *next_hashval) /* greatest hashval in block */
1718 {
1719 xfs_ino_t lino;
1720 xfs_dir_leaf_entry_t *entry;
1721 xfs_dir_leaf_entry_t *s_entry;
1722 xfs_dir_leaf_entry_t *d_entry;
1723 xfs_dir_leafblock_t *new_leaf;
1724 char *first_byte;
1725 xfs_dir_leaf_name_t *namest;
1726 ino_tree_node_t *irec_p;
1727 int num_entries;
1728 xfs_dahash_t hashval;
1729 int i;
1730 int nm_illegal;
1731 int bytes;
1732 int start;
1733 int stop;
1734 int res = 0;
1735 int ino_off;
1736 int first_used;
1737 int bytes_used;
1738 int reset_holes;
1739 int zero_len_entries;
1740 char fname[MAXNAMELEN + 1];
1741 da_hole_map_t holemap;
1742 da_hole_map_t bholemap;
1743 #if 0
1744 unsigned char *dir_freemap;
1745 #endif
1746
1747 #ifdef XR_DIR_TRACE
1748 fprintf(stderr, "\tprocess_leaf_dir_block - ino %llu\n", ino);
1749 #endif
1750
1751 /*
1752 * clear static dir block freespace bitmap
1753 */
1754 init_da_freemap(dir_freemap);
1755
1756 #if 0
1757 /*
1758 * XXX - alternatively, do this for parallel usage.
1759 * set up block freespace map. head part of dir leaf block
1760 * including all entries are packed so we can use sizeof
1761 * and not worry about alignment.
1762 */
1763
1764 if ((dir_freemap = alloc_da_freemap(mp)) == NULL) {
1765 do_error(_("couldn't allocate directory block freemap\n"));
1766 abort();
1767 }
1768 #endif
1769
1770 *buf_dirty = 0;
1771 first_used = mp->m_sb.sb_blocksize;
1772 zero_len_entries = 0;
1773 bytes_used = 0;
1774
1775 i = stop = sizeof(xfs_dir_leaf_hdr_t);
1776 if (set_da_freemap(mp, dir_freemap, 0, stop)) {
1777 do_warn(
1778 _("directory block header conflicts with used space in directory inode %llu\n"),
1779 ino);
1780 return(1);
1781 }
1782
1783 /*
1784 * verify structure: monotonically increasing hash value for
1785 * all leaf entries, indexes for all entries must be within
1786 * this fs block (trivially true for 64K blocks). also track
1787 * used space so we can check the freespace map. check for
1788 * zero-length entries. for now, if anything's wrong, we
1789 * junk the directory and we'll pick up no-longer referenced
1790 * inodes on a later pass.
1791 */
1792 for (i = 0, entry = &leaf->entries[0];
1793 i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
1794 i++, entry++) {
1795 /*
1796 * check that the name index isn't out of bounds
1797 * if it is, delete the entry since we can't
1798 * grab the inode #.
1799 */
1800 if (INT_GET(entry->nameidx, ARCH_CONVERT) >=
1801 mp->m_sb.sb_blocksize) {
1802 if (!no_modify) {
1803 *buf_dirty = 1;
1804
1805 if (INT_GET(leaf->hdr.count, ARCH_CONVERT) > 1) {
1806 do_warn(
1807 _("nameidx %d for entry #%d, bno %d, ino %llu > fs blocksize, deleting entry\n"),
1808 INT_GET(entry->nameidx,
1809 ARCH_CONVERT),
1810 i, da_bno, ino);
1811 ASSERT(INT_GET(leaf->hdr.count,
1812 ARCH_CONVERT) > i);
1813
1814 bytes = (INT_GET(leaf->hdr.count,
1815 ARCH_CONVERT) - i) *
1816 sizeof(xfs_dir_leaf_entry_t);
1817
1818 /*
1819 * compress table unless we're
1820 * only dealing with 1 entry
1821 * (the last one) in which case
1822 * just zero it.
1823 */
1824 if (bytes >
1825 sizeof(xfs_dir_leaf_entry_t)) {
1826 memmove(entry, entry + 1,
1827 bytes);
1828 bzero((void *)
1829 ((__psint_t) entry + bytes),
1830 sizeof(xfs_dir_leaf_entry_t));
1831 } else {
1832 bzero(entry,
1833 sizeof(xfs_dir_leaf_entry_t));
1834 }
1835
1836 /*
1837 * sync vars to match smaller table.
1838 * don't have to worry about freespace
1839 * map since we haven't set it for
1840 * this entry yet.
1841 */
1842 INT_MOD(leaf->hdr.count, ARCH_CONVERT, -1);
1843 i--;
1844 entry--;
1845 } else {
1846 do_warn(
1847 _("nameidx %d, entry #%d, bno %d, ino %llu > fs blocksize, marking entry bad\n"),
1848 INT_GET(entry->nameidx,
1849 ARCH_CONVERT),
1850 i, da_bno, ino);
1851 INT_SET(entry->nameidx, ARCH_CONVERT,
1852 mp->m_sb.sb_blocksize -
1853 sizeof(xfs_dir_leaf_name_t));
1854 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf,
1855 INT_GET(entry->nameidx,
1856 ARCH_CONVERT));
1857 lino = NULLFSINO;
1858 XFS_DIR_SF_PUT_DIRINO(&lino,
1859 &namest->inumber);
1860 namest->name[0] = '/';
1861 }
1862 } else {
1863 do_warn(
1864 _("nameidx %d, entry #%d, bno %d, ino %llu > fs blocksize, would delete entry\n"),
1865 INT_GET(entry->nameidx, ARCH_CONVERT),
1866 i, da_bno, ino);
1867 }
1868 continue;
1869 }
1870 /*
1871 * inode processing -- make sure the inode
1872 * is in our tree or we add it to the uncertain
1873 * list if the inode # is valid. if namelen is 0,
1874 * we can still try for the inode as long as nameidx
1875 * is ok.
1876 */
1877 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf,
1878 INT_GET(entry->nameidx, ARCH_CONVERT));
1879 XFS_DIR_SF_GET_DIRINO(&namest->inumber, &lino);
1880
1881 /*
1882 * we may have to blow out an entry because of bad
1883 * inode numbers. do NOT touch the name until after
1884 * we've computed the hashvalue and done a namecheck()
1885 * on the name.
1886 */
1887 if (!ino_discovery && lino == NULLFSINO) {
1888 /*
1889 * don't do a damned thing. We already
1890 * found this (or did it ourselves) during
1891 * phase 3.
1892 */
1893 } else if (verify_inum(mp, lino)) {
1894 /*
1895 * bad inode number. clear the inode
1896 * number and the entry will get removed
1897 * later. We don't trash the directory
1898 * since it's still structurally intact.
1899 */
1900 do_warn(
1901 _("invalid ino number %llu in dir ino %llu, entry #%d, bno %d\n"),
1902 lino, ino, i, da_bno);
1903 if (!no_modify) {
1904 do_warn(
1905 _("\tclearing ino number in entry %d...\n"),
1906 i);
1907 lino = NULLFSINO;
1908 XFS_DIR_SF_PUT_DIRINO(&lino, &namest->inumber);
1909 *buf_dirty = 1;
1910 } else {
1911 do_warn(
1912 _("\twould clear ino number in entry %d...\n"),
1913 i);
1914 }
1915 } else if (lino == mp->m_sb.sb_rbmino) {
1916 do_warn(
1917 _("entry #%d, bno %d in directory %llu references realtime bitmap inode %llu\n"),
1918 i, da_bno, ino, lino);
1919 if (!no_modify) {
1920 do_warn(
1921 _("\tclearing ino number in entry %d...\n"),
1922 i);
1923
1924 lino = NULLFSINO;
1925 XFS_DIR_SF_PUT_DIRINO(&lino, &namest->inumber);
1926 *buf_dirty = 1;
1927 } else {
1928 do_warn(
1929 _("\twould clear ino number in entry %d...\n"),
1930 i);
1931 }
1932 } else if (lino == mp->m_sb.sb_rsumino) {
1933 do_warn(
1934 _("entry #%d, bno %d in directory %llu references realtime summary inode %llu\n"),
1935 i, da_bno, ino, lino);
1936 if (!no_modify) {
1937 do_warn(
1938 _("\tclearing ino number in entry %d...\n"), i);
1939
1940 lino = NULLFSINO;
1941 XFS_DIR_SF_PUT_DIRINO(&lino, &namest->inumber);
1942 *buf_dirty = 1;
1943 } else {
1944 do_warn(
1945 _("\twould clear ino number in entry %d...\n"),
1946 i);
1947 }
1948 } else if (lino == mp->m_sb.sb_uquotino) {
1949 do_warn(
1950 _("entry #%d, bno %d in directory %llu references user quota inode %llu\n"),
1951 i, da_bno, ino, lino);
1952 if (!no_modify) {
1953 do_warn(
1954 _("\tclearing ino number in entry %d...\n"),
1955 i);
1956
1957 lino = NULLFSINO;
1958 XFS_DIR_SF_PUT_DIRINO(&lino, &namest->inumber);
1959 *buf_dirty = 1;
1960 } else {
1961 do_warn(
1962 _("\twould clear ino number in entry %d...\n"),
1963 i);
1964 }
1965 } else if (lino == mp->m_sb.sb_gquotino) {
1966 do_warn(
1967 _("entry #%d, bno %d in directory %llu references group quota inode %llu\n"),
1968 i, da_bno, ino, lino);
1969 if (!no_modify) {
1970 do_warn(
1971 _("\tclearing ino number in entry %d...\n"),
1972 i);
1973
1974 lino = NULLFSINO;
1975 XFS_DIR_SF_PUT_DIRINO(&lino, &namest->inumber);
1976 *buf_dirty = 1;
1977 } else {
1978 do_warn(
1979 _("\twould clear ino number in entry %d...\n"),
1980 i);
1981 }
1982 } else if (lino == old_orphanage_ino) {
1983 /*
1984 * do nothing, silently ignore it, entry has
1985 * already been marked TBD since old_orphanage_ino
1986 * is set non-zero.
1987 */
1988 } else if ((irec_p = find_inode_rec(
1989 XFS_INO_TO_AGNO(mp, lino),
1990 XFS_INO_TO_AGINO(mp, lino))) != NULL) {
1991 /*
1992 * inode recs should have only confirmed
1993 * inodes in them
1994 */
1995 ino_off = XFS_INO_TO_AGINO(mp, lino) -
1996 irec_p->ino_startnum;
1997 ASSERT(is_inode_confirmed(irec_p, ino_off));
1998 /*
1999 * if inode is marked free and we're in inode
2000 * discovery mode, leave the entry alone for now.
2001 * if the inode turns out to be used, we'll figure
2002 * that out when we scan it. If the inode really
2003 * is free, we'll hit this code again in phase 4
2004 * after we've finished inode discovery and blow
2005 * out the entry then.
2006 */
2007 if (!ino_discovery && is_inode_free(irec_p, ino_off)) {
2008 if (!no_modify) {
2009 do_warn(
2010 _("entry references free inode %llu in directory %llu, will clear entry\n"),
2011 lino, ino);
2012 lino = NULLFSINO;
2013 XFS_DIR_SF_PUT_DIRINO(&lino,
2014 &namest->inumber);
2015 *buf_dirty = 1;
2016 } else {
2017 do_warn(
2018 _("entry references free inode %llu in directory %llu, would clear entry\n"),
2019 lino, ino);
2020 }
2021 }
2022 } else if (ino_discovery) {
2023 add_inode_uncertain(mp, lino, 0);
2024 } else {
2025 do_warn(
2026 _("bad ino number %llu in dir ino %llu, entry #%d, bno %d\n"),
2027 lino, ino, i, da_bno);
2028 if (!no_modify) {
2029 do_warn(_("clearing inode number...\n"));
2030 lino = NULLFSINO;
2031 XFS_DIR_SF_PUT_DIRINO(&lino, &namest->inumber);
2032 *buf_dirty = 1;
2033 } else {
2034 do_warn(_("would clear inode number...\n"));
2035 }
2036 }
2037 /*
2038 * if we have a zero-length entry, trash it.
2039 * we may lose the inode (chunk) if we don't
2040 * finish the repair successfully and the inode
2041 * isn't mentioned anywhere else (like in the inode
2042 * tree) but the alternative is to risk losing the
2043 * entire directory by trying to use the next byte
2044 * to turn the entry into a 1-char entry. That's
2045 * probably a safe bet but if it didn't work, we'd
2046 * lose the entire directory the way we currently do
2047 * things. (Maybe we should change that later :-).
2048 */
2049 if (entry->namelen == 0) {
2050 *buf_dirty = 1;
2051
2052 if (INT_GET(leaf->hdr.count, ARCH_CONVERT) > 1) {
2053 do_warn(
2054 _("entry #%d, dir inode %llu, has zero-len name, deleting entry\n"),
2055 i, ino);
2056 ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT) > i);
2057
2058 bytes = (INT_GET(leaf->hdr.count,
2059 ARCH_CONVERT) - i) *
2060 sizeof(xfs_dir_leaf_entry_t);
2061
2062 /*
2063 * compress table unless we're
2064 * only dealing with 1 entry
2065 * (the last one) in which case
2066 * just zero it.
2067 */
2068 if (bytes > sizeof(xfs_dir_leaf_entry_t)) {
2069 memmove(entry, entry + 1, bytes);
2070 bzero((void *)
2071 ((__psint_t) entry + bytes),
2072 sizeof(xfs_dir_leaf_entry_t));
2073 } else {
2074 bzero(entry,
2075 sizeof(xfs_dir_leaf_entry_t));
2076 }
2077
2078 /*
2079 * sync vars to match smaller table.
2080 * don't have to worry about freespace
2081 * map since we haven't set it for
2082 * this entry yet.
2083 */
2084 INT_MOD(leaf->hdr.count, ARCH_CONVERT, -1);
2085 i--;
2086 entry--;
2087 } else {
2088 /*
2089 * if it's the only entry, preserve the
2090 * inode number for now
2091 */
2092 do_warn(
2093 _("entry #%d, dir inode %llu, has zero-len name, marking entry bad\n"),
2094 i, ino);
2095 INT_SET(entry->nameidx, ARCH_CONVERT,
2096 mp->m_sb.sb_blocksize -
2097 sizeof(xfs_dir_leaf_name_t));
2098 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf,
2099 INT_GET(entry->nameidx,
2100 ARCH_CONVERT));
2101 XFS_DIR_SF_PUT_DIRINO(&lino, &namest->inumber);
2102 namest->name[0] = '/';
2103 }
2104 } else if (INT_GET(entry->nameidx, ARCH_CONVERT) +
2105 entry->namelen > XFS_LBSIZE(mp)) {
2106 do_warn(
2107 _("bad size, entry #%d in dir inode %llu, block %u -- entry overflows block\n"),
2108 i, ino, da_bno);
2109
2110 return(1);
2111 }
2112
2113 start = (__psint_t)&leaf->entries[i] - (__psint_t)leaf;;
2114 stop = start + sizeof(xfs_dir_leaf_entry_t);
2115
2116 if (set_da_freemap(mp, dir_freemap, start, stop)) {
2117 do_warn(
2118 _("dir entry slot %d in block %u conflicts with used space in dir inode %llu\n"),
2119 i, da_bno, ino);
2120 return(1);
2121 }
2122
2123 /*
2124 * check if the name is legal. if so, then
2125 * check that the name and hashvalues match.
2126 *
2127 * if the name is illegal, we don't check the
2128 * hashvalue computed from it. we just make
2129 * sure that the hashvalue in the entry is
2130 * monotonically increasing wrt to the previous
2131 * entry.
2132 *
2133 * Note that we do NOT have to check the length
2134 * because the length is stored in a one-byte
2135 * unsigned int which max's out at MAXNAMELEN
2136 * making it impossible for the stored length
2137 * value to be out of range.
2138 */
2139 bcopy(namest->name, fname, entry->namelen);
2140 fname[entry->namelen] = '\0';
2141 hashval = libxfs_da_hashname(fname, entry->namelen);
2142
2143 /*
2144 * only complain about illegal names in phase 3 (when
2145 * inode discovery is turned on). Otherwise, we'd complain
2146 * a lot during phase 4. If the name is illegal, leave
2147 * the hash value in that entry alone.
2148 */
2149 nm_illegal = namecheck(fname, entry->namelen);
2150
2151 if (ino_discovery && nm_illegal) {
2152 /*
2153 * junk the entry, illegal name
2154 */
2155 if (!no_modify) {
2156 do_warn(
2157 _("illegal name \"%s\" in directory inode %llu, entry will be cleared\n"),
2158 fname, ino);
2159 namest->name[0] = '/';
2160 *buf_dirty = 1;
2161 } else {
2162 do_warn(
2163 _("illegal name \"%s\" in directory inode %llu, entry would be cleared\n"),
2164 fname, ino);
2165 }
2166 } else if (!nm_illegal &&
2167 INT_GET(entry->hashval, ARCH_CONVERT) != hashval) {
2168 /*
2169 * try resetting the hashvalue to the correct
2170 * value for the string, if the string has been
2171 * corrupted, too, that will get picked up next
2172 */
2173 do_warn(_("\tmismatched hash value for entry \"%s\"\n"),
2174 fname);
2175 if (!no_modify) {
2176 do_warn(
2177 _("\t\tin directory inode %llu. resetting hash value.\n"),
2178 ino);
2179 INT_SET(entry->hashval, ARCH_CONVERT, hashval);
2180 *buf_dirty = 1;
2181 } else {
2182 do_warn(
2183 _("\t\tin directory inode %llu. would reset hash value.\n"),
2184 ino);
2185 }
2186 }
2187
2188 /*
2189 * now we can mark entries with NULLFSINO's bad
2190 */
2191 if (!no_modify && lino == NULLFSINO) {
2192 namest->name[0] = '/';
2193 *buf_dirty = 1;
2194 }
2195
2196 /*
2197 * regardless of whether the entry has or hasn't been
2198 * marked for deletion, the hash value ordering must
2199 * be maintained.
2200 */
2201 if (INT_GET(entry->hashval, ARCH_CONVERT) < last_hashval) {
2202 /*
2203 * blow out the entry -- set hashval to sane value
2204 * and set the first character in the string to
2205 * the illegal value '/'. Reset the hash value
2206 * to the last hashvalue so that verify_da_path
2207 * will fix up the interior pointers correctly.
2208 * the entry will be deleted later (by routines
2209 * that need only the entry #). We keep the
2210 * inode number in the entry so we can attach
2211 * the inode to the orphanage later.
2212 */
2213 do_warn(_("\tbad hash ordering for entry \"%s\"\n"),
2214 fname);
2215 if (!no_modify) {
2216 do_warn(
2217 _("\t\tin directory inode %llu. will clear entry\n"),
2218 ino);
2219 INT_SET(entry->hashval, ARCH_CONVERT,
2220 last_hashval);
2221 namest->name[0] = '/';
2222 *buf_dirty = 1;
2223 } else {
2224 do_warn(
2225 _("\t\tin directory inode %llu. would clear entry\n"),
2226 ino);
2227 }
2228 }
2229
2230 *next_hashval = last_hashval = INT_GET(entry->hashval, ARCH_CONVERT);
2231
2232 /*
2233 * if heap data conflicts with something,
2234 * blow it out and skip the rest of the loop
2235 */
2236 if (set_da_freemap(mp, dir_freemap,
2237 INT_GET(entry->nameidx, ARCH_CONVERT),
2238 INT_GET(entry->nameidx, ARCH_CONVERT)
2239 + sizeof(xfs_dir_leaf_name_t)
2240 + entry->namelen - 1)) {
2241 do_warn(
2242 _("name \"%s\" (block %u, slot %d) conflicts with used space in dir inode %llu\n"),
2243 fname, da_bno, i, ino);
2244 if (!no_modify) {
2245 entry->namelen = 0;
2246 *buf_dirty = 1;
2247
2248 do_warn(
2249 _("will clear entry \"%s\" (#%d) in directory inode %llu\n"),
2250 fname, i, ino);
2251 } else {
2252 do_warn(
2253 _("would clear entry \"%s\" (#%d)in directory inode %llu\n"),
2254 fname, i, ino);
2255 }
2256 continue;
2257 }
2258
2259 /*
2260 * keep track of heap stats (first byte used, total bytes used)
2261 */
2262 if (INT_GET(entry->nameidx, ARCH_CONVERT) < first_used)
2263 first_used = INT_GET(entry->nameidx, ARCH_CONVERT);
2264 bytes_used += entry->namelen;
2265
2266 /*
2267 * special . or .. entry processing
2268 */
2269 if (entry->namelen == 2 && namest->name[0] == '.' &&
2270 namest->name[1] == '.') {
2271 /*
2272 * the '..' case
2273 */
2274 if (!*dotdot) {
2275 (*dotdot)++;
2276 *parent = lino;
2277 #ifdef XR_DIR_TRACE
2278 fprintf(stderr, "process_leaf_dir_block found .. entry (parent) = %llu\n", lino);
2279 #endif
2280 /*
2281 * what if .. == .? legal only in
2282 * the root inode. blow out entry
2283 * and set parent to NULLFSINO otherwise.
2284 */
2285 if (ino == lino &&
2286 ino != mp->m_sb.sb_rootino) {
2287 *parent = NULLFSINO;
2288 do_warn(
2289 _("bad .. entry in dir ino %llu, points to self"),
2290 ino);
2291 if (!no_modify) {
2292 do_warn(
2293 _("will clear entry\n"));
2294 namest->name[0] = '/';
2295 *buf_dirty = 1;
2296 } else {
2297 do_warn(
2298 _("would clear entry\n"));
2299 }
2300 } else if (ino != lino &&
2301 ino == mp->m_sb.sb_rootino) {
2302 /*
2303 * we have to make sure that . == ..
2304 * in the root inode
2305 */
2306 if (!no_modify) {
2307 do_warn(
2308 _("correcting .. entry in root inode %llu, was %llu\n"),
2309 ino, *parent);
2310 XFS_DIR_SF_PUT_DIRINO(
2311 &ino, &namest->inumber);
2312 *buf_dirty = 1;
2313 } else {
2314 do_warn(
2315 _("bad .. entry (%llu) in root inode %llu should be %llu\n"),
2316 *parent,
2317 ino, ino);
2318 }
2319 }
2320 } else {
2321 /*
2322 * can't fix the directory unless we know
2323 * which .. entry is the right one. Both
2324 * have valid inode numbers, match the hash
2325 * value and the hash values are ordered
2326 * properly or we wouldn't be here. So
2327 * since both seem equally valid, trash
2328 * this one.
2329 */
2330 if (!no_modify) {
2331 do_warn(
2332 _("multiple .. entries in directory inode %llu, will clear second entry\n"),
2333 ino);
2334 namest->name[0] = '/';
2335 *buf_dirty = 1;
2336 } else {
2337 do_warn(
2338 _("multiple .. entries in directory inode %llu, would clear second entry\n"),
2339 ino);
2340 }
2341 }
2342 } else if (entry->namelen == 1 && namest->name[0] == '.') {
2343 /*
2344 * the '.' case
2345 */
2346 if (!*dot) {
2347 (*dot)++;
2348 if (lino != ino) {
2349 if (!no_modify) {
2350 do_warn(
2351 _(". in directory inode %llu has wrong value (%llu), fixing entry...\n"),
2352 ino, lino);
2353 XFS_DIR_SF_PUT_DIRINO(&ino,
2354 &namest->inumber);
2355 *buf_dirty = 1;
2356 } else {
2357 do_warn(
2358 _(". in directory inode %llu has wrong value (%llu)\n"),
2359 ino, lino);
2360 }
2361 }
2362 } else {
2363 do_warn(
2364 _("multiple . entries in directory inode %llu\n"),
2365 ino);
2366 /*
2367 * mark entry as to be junked.
2368 */
2369 if (!no_modify) {
2370 do_warn(
2371 _("will clear one . entry in directory inode %llu\n"),
2372 ino);
2373 namest->name[0] = '/';
2374 *buf_dirty = 1;
2375 } else {
2376 do_warn(
2377 _("would clear one . entry in directory inode %llu\n"),
2378 ino);
2379 }
2380 }
2381 } else {
2382 /*
2383 * all the rest -- make sure only . references self
2384 */
2385 if (lino == ino) {
2386 do_warn(
2387 _("entry \"%s\" in directory inode %llu points to self, "),
2388 fname, ino);
2389 if (!no_modify) {
2390 do_warn(_("will clear entry\n"));
2391 namest->name[0] = '/';
2392 *buf_dirty = 1;
2393 } else {
2394 do_warn(_("would clear entry\n"));
2395 }
2396 }
2397 }
2398 }
2399
2400 /*
2401 * compare top of heap values and reset as required. if the
2402 * holes flag is set, don't reset first_used unless it's
2403 * pointing to used bytes. we're being conservative here
2404 * since the block will get compacted anyhow by the kernel.
2405 */
2406 if ((leaf->hdr.holes == 0 &&
2407 first_used != INT_GET(leaf->hdr.firstused, ARCH_CONVERT)) ||
2408 INT_GET(leaf->hdr.firstused, ARCH_CONVERT) > first_used) {
2409 if (!no_modify) {
2410 if (verbose)
2411 do_warn(
2412 _("- resetting first used heap value from %d to %d in block %u of dir ino %llu\n"),
2413 (int) INT_GET(leaf->hdr.firstused,
2414 ARCH_CONVERT),
2415 first_used, da_bno, ino);
2416 INT_SET(leaf->hdr.firstused, ARCH_CONVERT, first_used);
2417 *buf_dirty = 1;
2418 } else {
2419 if (verbose)
2420 do_warn(
2421 _("- would reset first used value from %d to %d in block %u of dir ino %llu\n"),
2422 (int) INT_GET(leaf->hdr.firstused,
2423 ARCH_CONVERT),
2424 first_used, da_bno, ino);
2425 }
2426 }
2427
2428 if (bytes_used != INT_GET(leaf->hdr.namebytes, ARCH_CONVERT)) {
2429 if (!no_modify) {
2430 if (verbose)
2431 do_warn(
2432 _("- resetting namebytes cnt from %d to %d in block %u of dir inode %llu\n"),
2433 (int) INT_GET(leaf->hdr.namebytes,
2434 ARCH_CONVERT),
2435 bytes_used, da_bno, ino);
2436 INT_SET(leaf->hdr.namebytes, ARCH_CONVERT, bytes_used);
2437 *buf_dirty = 1;
2438 } else {
2439 if (verbose)
2440 do_warn(
2441 _("- would reset namebytes cnt from %d to %d in block %u of dir inode %llu\n"),
2442 (int) INT_GET(leaf->hdr.namebytes,
2443 ARCH_CONVERT),
2444 bytes_used, da_bno, ino);
2445 }
2446 }
2447
2448 /*
2449 * If the hole flag is not set, then we know that there can
2450 * be no lost holes. If the hole flag is set, then it's ok
2451 * if the on-disk holemap doesn't describe everything as long
2452 * as what it does describe doesn't conflict with reality.
2453 */
2454
2455 reset_holes = 0;
2456
2457 bholemap.lost_holes = leaf->hdr.holes;
2458 for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++) {
2459 bholemap.hentries[i].base = INT_GET(leaf->hdr.freemap[i].base, ARCH_CONVERT);
2460 bholemap.hentries[i].size = INT_GET(leaf->hdr.freemap[i].size, ARCH_CONVERT);
2461 }
2462
2463 /*
2464 * Ok, now set up our own freespace list
2465 * (XFS_DIR_LEAF_MAPSIZE (3) * biggest regions)
2466 * and see if they match what's in the block
2467 */
2468 bzero(&holemap, sizeof(da_hole_map_t));
2469 process_da_freemap(mp, dir_freemap, &holemap);
2470
2471 if (zero_len_entries) {
2472 reset_holes = 1;
2473 } else if (leaf->hdr.holes == 0) {
2474 if (holemap.lost_holes > 0) {
2475 if (verbose)
2476 do_warn(
2477 _("- found unexpected lost holes in block %u, dir inode %llu\n"),
2478 da_bno, ino);
2479
2480 reset_holes = 1;
2481 } else if (compare_da_freemaps(mp, &holemap, &bholemap,
2482 XFS_DIR_LEAF_MAPSIZE, ino, da_bno)) {
2483 if (verbose)
2484 do_warn(
2485 _("- hole info non-optimal in block %u, dir inode %llu\n"),
2486 da_bno, ino);
2487 reset_holes = 1;
2488 }
2489 } else if (verify_da_freemap(mp, dir_freemap, &holemap, ino, da_bno)) {
2490 if (verbose)
2491 do_warn(
2492 _("- hole info incorrect in block %u, dir inode %llu\n"),
2493 da_bno, ino);
2494 reset_holes = 1;
2495 }
2496
2497 if (reset_holes) {
2498 /*
2499 * have to reset block hole info
2500 */
2501 if (verbose) {
2502 do_warn(
2503 _("- existing hole info for block %d, dir inode %llu (base, size) - \n"),
2504 da_bno, ino);
2505 do_warn("- \t");
2506 for (i = 0; i < XFS_DIR_LEAF_MAPSIZE; i++) {
2507 do_warn(
2508 "- (%d, %d) ", bholemap.hentries[i].base,
2509 bholemap.hentries[i].size);
2510 }
2511 do_warn(_("- holes flag = %d\n"), bholemap.lost_holes);
2512 }
2513
2514 if (!no_modify) {
2515 if (verbose)
2516 do_warn(
2517 _("- compacting block %u in dir inode %llu\n"),
2518 da_bno, ino);
2519
2520 new_leaf = (xfs_dir_leafblock_t *) &dirbuf[0];
2521
2522 /*
2523 * copy leaf block header
2524 */
2525 bcopy(&leaf->hdr, &new_leaf->hdr,
2526 sizeof(xfs_dir_leaf_hdr_t));
2527
2528 /*
2529 * reset count in case we have some zero length entries
2530 * that are being junked
2531 */
2532 num_entries = 0;
2533 first_used = XFS_LBSIZE(mp);
2534 first_byte = (char *) new_leaf
2535 + (__psint_t) XFS_LBSIZE(mp);
2536
2537 /*
2538 * copy entry table and pack names starting from the end
2539 * of the block
2540 */
2541 for (i = 0, s_entry = &leaf->entries[0],
2542 d_entry = &new_leaf->entries[0];
2543 i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
2544 i++, s_entry++) {
2545 /*
2546 * skip zero-length entries
2547 */
2548 if (s_entry->namelen == 0)
2549 continue;
2550
2551 bytes = sizeof(xfs_dir_leaf_name_t)
2552 + s_entry->namelen - 1;
2553
2554 if ((__psint_t) first_byte - bytes <
2555 sizeof(xfs_dir_leaf_entry_t)
2556 + (__psint_t) d_entry) {
2557 do_warn(
2558 _("not enough space in block %u of dir inode %llu for all entries\n"),
2559 da_bno, ino);
2560 break;
2561 }
2562
2563 first_used -= bytes;
2564 first_byte -= bytes;
2565
2566 INT_SET(d_entry->nameidx, ARCH_CONVERT, first_used);
2567 INT_SET(d_entry->hashval, ARCH_CONVERT, INT_GET(s_entry->hashval, ARCH_CONVERT));
2568 d_entry->namelen = s_entry->namelen;
2569 d_entry->pad2 = 0;
2570
2571 bcopy((char *) leaf + INT_GET(s_entry->nameidx, ARCH_CONVERT),
2572 first_byte, bytes);
2573
2574 num_entries++;
2575 d_entry++;
2576 }
2577
2578 ASSERT((char *) first_byte >= (char *) d_entry);
2579 ASSERT(first_used <= XFS_LBSIZE(mp));
2580
2581 /*
2582 * zero space between end of table and top of heap
2583 */
2584 bzero(d_entry, (__psint_t) first_byte
2585 - (__psint_t) d_entry);
2586
2587 /*
2588 * reset header info
2589 */
2590 if (num_entries != INT_GET(new_leaf->hdr.count, ARCH_CONVERT))
2591 INT_SET(new_leaf->hdr.count, ARCH_CONVERT, num_entries);
2592
2593 INT_SET(new_leaf->hdr.firstused, ARCH_CONVERT, first_used);
2594 new_leaf->hdr.holes = 0;
2595 new_leaf->hdr.pad1 = 0;
2596
2597 INT_SET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT, (__psint_t) d_entry
2598 - (__psint_t) new_leaf);
2599 INT_SET(new_leaf->hdr.freemap[0].size, ARCH_CONVERT, (__psint_t) first_byte
2600 - (__psint_t) d_entry);
2601
2602 ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) < first_used);
2603 ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) ==
2604 (__psint_t) (&new_leaf->entries[0])
2605 - (__psint_t) new_leaf
2606 + i * sizeof(xfs_dir_leaf_entry_t));
2607 ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) < XFS_LBSIZE(mp));
2608 ASSERT(INT_GET(new_leaf->hdr.freemap[0].size, ARCH_CONVERT) < XFS_LBSIZE(mp));
2609 ASSERT(INT_GET(new_leaf->hdr.freemap[0].base, ARCH_CONVERT) +
2610 INT_GET(new_leaf->hdr.freemap[0].size, ARCH_CONVERT) == first_used);
2611
2612 new_leaf->hdr.freemap[1].base = 0;
2613 new_leaf->hdr.freemap[1].size = 0;
2614 new_leaf->hdr.freemap[2].base = 0;
2615 new_leaf->hdr.freemap[2].size = 0;
2616
2617 /*
2618 * final step, copy block back
2619 */
2620 bcopy(new_leaf, leaf, mp->m_sb.sb_blocksize);
2621
2622 *buf_dirty = 1;
2623 } else {
2624 if (verbose)
2625 do_warn(
2626 _("- would compact block %u in dir inode %llu\n"),
2627 da_bno, ino);
2628 }
2629 }
2630 #if 0
2631 if (!no_modify) {
2632 /*
2633 * now take care of deleting or marking the entries with
2634 * zero-length namelen's
2635 */
2636 junk_zerolen_dir_leaf_entries(mp, leaf, ino, buf_dirty);
2637 }
2638 #endif
2639 #ifdef XR_DIR_TRACE
2640 fprintf(stderr, "process_leaf_dir_block returns %d\n", res);
2641 #endif
2642 return((res > 0) ? 1 : 0);
2643 }
2644
2645 /*
2646 * returns 0 if the directory is ok, 1 if it has to be junked.
2647 */
2648 int
2649 process_leaf_dir_level(xfs_mount_t *mp,
2650 da_bt_cursor_t *da_cursor,
2651 int ino_discovery,
2652 int *repair,
2653 int *dot,
2654 int *dotdot,
2655 xfs_ino_t *parent)
2656 {
2657 xfs_dir_leafblock_t *leaf;
2658 xfs_buf_t *bp;
2659 xfs_ino_t ino;
2660 xfs_dfsbno_t dev_bno;
2661 xfs_dablk_t da_bno;
2662 xfs_dablk_t prev_bno;
2663 int res = 0;
2664 int buf_dirty = 0;
2665 xfs_daddr_t bd_addr;
2666 xfs_dahash_t current_hashval = 0;
2667 xfs_dahash_t greatest_hashval;
2668
2669 #ifdef XR_DIR_TRACE
2670 fprintf(stderr, "process_leaf_dir_level - ino %llu\n", da_cursor->ino);
2671 #endif
2672 *repair = 0;
2673 da_bno = da_cursor->level[0].bno;
2674 ino = da_cursor->ino;
2675 prev_bno = 0;
2676
2677 do {
2678 dev_bno = blkmap_get(da_cursor->blkmap, da_bno);
2679 /*
2680 * directory code uses 0 as the NULL block pointer
2681 * since 0 is the root block and no directory block
2682 * pointer can point to the root block of the btree
2683 */
2684 ASSERT(da_bno != 0);
2685
2686 if (dev_bno == NULLDFSBNO) {
2687 do_warn(
2688 _("can't map block %u for directory inode %llu\n"),
2689 da_bno, ino);
2690 goto error_out;
2691 }
2692
2693 bd_addr = (xfs_daddr_t)XFS_FSB_TO_DADDR(mp, dev_bno);
2694
2695 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno),
2696 XFS_FSB_TO_BB(mp, 1), 0);
2697 if (!bp) {
2698 do_warn(
2699 _("can't read file block %u (fsbno %llu, daddr %lld) "
2700 "for directory inode %llu\n"),
2701 da_bno, dev_bno, (__int64_t) bd_addr, ino);
2702 goto error_out;
2703 }
2704
2705 leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp);
2706
2707 /*
2708 * check magic number for leaf directory btree block
2709 */
2710 if (XFS_DIR_LEAF_MAGIC !=
2711 INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)) {
2712 do_warn(
2713 _("bad directory leaf magic # %#x for dir ino %llu\n"),
2714 INT_GET(leaf->hdr.info.magic, ARCH_CONVERT),
2715 ino);
2716 libxfs_putbuf(bp);
2717 goto error_out;
2718 }
2719 /*
2720 * keep track of greatest block # -- that gets
2721 * us the length of the directory
2722 */
2723 if (da_bno > da_cursor->greatest_bno)
2724 da_cursor->greatest_bno = da_bno;
2725
2726 buf_dirty = 0;
2727 /*
2728 * for each block, process the block, verify it's path,
2729 * then get next block. update cursor values along the way
2730 */
2731 if (process_leaf_dir_block(mp, leaf, da_bno, ino,
2732 current_hashval, ino_discovery,
2733 da_cursor->blkmap, dot, dotdot, parent,
2734 &buf_dirty, &greatest_hashval)) {
2735 libxfs_putbuf(bp);
2736 goto error_out;
2737 }
2738
2739 /*
2740 * index can be set to hdr.count so match the
2741 * indexes of the interior blocks -- which at the
2742 * end of the block will point to 1 after the final
2743 * real entry in the block
2744 */
2745 da_cursor->level[0].hashval = greatest_hashval;
2746 da_cursor->level[0].bp = bp;
2747 da_cursor->level[0].bno = da_bno;
2748 da_cursor->level[0].index = INT_GET(leaf->hdr.count, ARCH_CONVERT);
2749 da_cursor->level[0].dirty = buf_dirty;
2750
2751 if (INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != prev_bno) {
2752 do_warn(_("bad sibling back pointer for directory "
2753 "block %u in directory inode %llu\n"),
2754 da_bno, ino);
2755 libxfs_putbuf(bp);
2756 goto error_out;
2757 }
2758
2759 prev_bno = da_bno;
2760 da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
2761
2762 if (da_bno != 0)
2763 if (verify_da_path(mp, da_cursor, 0)) {
2764 libxfs_putbuf(bp);
2765 goto error_out;
2766 }
2767
2768 current_hashval = greatest_hashval;
2769
2770 ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify));
2771
2772 if (buf_dirty && !no_modify) {
2773 *repair = 1;
2774 libxfs_writebuf(bp, 0);
2775 }
2776 else
2777 libxfs_putbuf(bp);
2778 } while (da_bno != 0 && res == 0);
2779
2780 if (verify_final_da_path(mp, da_cursor, 0)) {
2781 /*
2782 * verify the final path up (right-hand-side) if still ok
2783 */
2784 do_warn(_("bad hash path in directory %llu\n"), da_cursor->ino);
2785 goto error_out;
2786 }
2787
2788 #ifdef XR_DIR_TRACE
2789 fprintf(stderr, "process_leaf_dir_level returns %d (%s)\n",
2790 res, ((res) ? "bad" : "ok"));
2791 #endif
2792 /*
2793 * redundant but just for testing
2794 */
2795 release_da_cursor(mp, da_cursor, 0);
2796
2797 return(res);
2798
2799 error_out:
2800 /*
2801 * release all buffers holding interior btree blocks
2802 */
2803 err_release_da_cursor(mp, da_cursor, 0);
2804
2805 return(1);
2806 }
2807
2808 /*
2809 * a node directory is a true btree directory -- where the directory
2810 * has gotten big enough that it is represented as a non-trivial (e.g.
2811 * has more than just a root block) btree.
2812 *
2813 * Note that if we run into any problems, we trash the
2814 * directory. Even if it's the root directory,
2815 * we'll be able to traverse all the disconnected
2816 * subtrees later (phase 6).
2817 *
2818 * one day, if we actually fix things, we'll set repair to 1 to
2819 * indicate that we have or that we should.
2820 *
2821 * dirname can be set to NULL if the name is unknown (or to
2822 * the string representation of the inode)
2823 *
2824 * returns 0 if things are ok, 1 if bad (directory needs to be junked)
2825 */
2826 /* ARGSUSED */
2827 int
2828 process_node_dir(
2829 xfs_mount_t *mp,
2830 xfs_ino_t ino,
2831 xfs_dinode_t *dip,
2832 int ino_discovery,
2833 blkmap_t *blkmap,
2834 int *dot,
2835 int *dotdot,
2836 xfs_ino_t *parent, /* out - parent ino # or NULLFSINO */
2837 char *dirname,
2838 int *repair)
2839 {
2840 xfs_dablk_t bno;
2841 int error = 0;
2842 da_bt_cursor_t da_cursor;
2843
2844 #ifdef XR_DIR_TRACE
2845 fprintf(stderr, "process_node_dir - ino %llu\n", ino);
2846 #endif
2847 *repair = *dot = *dotdot = 0;
2848 *parent = NULLFSINO;
2849
2850 /*
2851 * try again -- traverse down left-side of tree until we hit
2852 * the left-most leaf block setting up the btree cursor along
2853 * the way. Then walk the leaf blocks left-to-right, calling
2854 * a parent-verification routine each time we traverse a block.
2855 */
2856 bzero(&da_cursor, sizeof(da_bt_cursor_t));
2857
2858 da_cursor.active = 0;
2859 da_cursor.type = 0;
2860 da_cursor.ino = ino;
2861 da_cursor.dip = dip;
2862 da_cursor.greatest_bno = 0;
2863 da_cursor.blkmap = blkmap;
2864
2865 /*
2866 * now process interior node
2867 */
2868
2869 error = traverse_int_dablock(mp, &da_cursor, &bno, XFS_DATA_FORK);
2870
2871 if (error == 0)
2872 return(1);
2873
2874 /*
2875 * now pass cursor and bno into leaf-block processing routine
2876 * the leaf dir level routine checks the interior paths
2877 * up to the root including the final right-most path.
2878 */
2879
2880 error = process_leaf_dir_level(mp, &da_cursor, ino_discovery,
2881 repair, dot, dotdot, parent);
2882
2883 if (error)
2884 return(1);
2885
2886 /*
2887 * sanity check inode size
2888 */
2889 if (INT_GET(dip->di_core.di_size, ARCH_CONVERT) <
2890 (da_cursor.greatest_bno + 1) * mp->m_sb.sb_blocksize) {
2891 if ((xfs_fsize_t) da_cursor.greatest_bno
2892 * mp->m_sb.sb_blocksize > UINT_MAX) {
2893 do_warn(
2894 _("out of range internal directory block numbers (inode %llu)\n"),
2895 ino);
2896 return(1);
2897 }
2898
2899 do_warn(
2900 _("setting directory inode (%llu) size to %llu bytes, was %lld bytes\n"),
2901 ino,
2902 (xfs_dfiloff_t) (da_cursor.greatest_bno + 1)
2903 * mp->m_sb.sb_blocksize,
2904 INT_GET(dip->di_core.di_size, ARCH_CONVERT));
2905
2906 INT_SET(dip->di_core.di_size, ARCH_CONVERT, (xfs_fsize_t)
2907 (da_cursor.greatest_bno + 1) * mp->m_sb.sb_blocksize);
2908 }
2909 return(0);
2910 }
2911
2912 /*
2913 * a leaf directory is one where the directory is too big for
2914 * the inode data fork but is small enough to fit into one
2915 * directory btree block (filesystem block) outside the inode
2916 *
2917 * returns NULLFSINO if the directory is cannot be salvaged
2918 * and the .. ino if things are ok (even if the directory had
2919 * to be altered to make it ok).
2920 *
2921 * dirname can be set to NULL if the name is unknown (or to
2922 * the string representation of the inode)
2923 *
2924 * returns 0 if things are ok, 1 if bad (directory needs to be junked)
2925 */
2926 /* ARGSUSED */
2927 int
2928 process_leaf_dir(
2929 xfs_mount_t *mp,
2930 xfs_ino_t ino,
2931 xfs_dinode_t *dip,
2932 int ino_discovery,
2933 int *dino_dirty,
2934 blkmap_t *blkmap,
2935 int *dot, /* out - 1 if there is a dot, else 0 */
2936 int *dotdot, /* out - 1 if there's a dotdot, else 0 */
2937 xfs_ino_t *parent, /* out - parent ino # or NULLFSINO */
2938 char *dirname, /* in - directory pathname */
2939 int *repair) /* out - 1 if something was fixed */
2940 {
2941 xfs_dir_leafblock_t *leaf;
2942 xfs_dahash_t next_hashval;
2943 xfs_dfsbno_t bno;
2944 xfs_buf_t *bp;
2945 int buf_dirty = 0;
2946
2947 #ifdef XR_DIR_TRACE
2948 fprintf(stderr, "process_leaf_dir - ino %llu\n", ino);
2949 #endif
2950 *repair = *dot = *dotdot = 0;
2951 *parent = NULLFSINO;
2952
2953 bno = blkmap_get(blkmap, 0);
2954 if (bno == NULLDFSBNO) {
2955 do_warn(_("block 0 for directory inode %llu is missing\n"),
2956 ino);
2957 return(1);
2958 }
2959 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
2960 XFS_FSB_TO_BB(mp, 1), 0);
2961 if (!bp) {
2962 do_warn(_("can't read block 0 for directory inode %llu\n"),
2963 ino);
2964 return(1);
2965 }
2966 /*
2967 * verify leaf block
2968 */
2969 leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp);
2970
2971 /*
2972 * check magic number for leaf directory btree block
2973 */
2974 if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) {
2975 do_warn(_("bad directory leaf magic # %#x for dir ino %llu\n"),
2976 INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), ino);
2977 libxfs_putbuf(bp);
2978 return(1);
2979 }
2980
2981 if (process_leaf_dir_block(mp, leaf, 0, ino, 0, ino_discovery, blkmap,
2982 dot, dotdot, parent, &buf_dirty, &next_hashval)) {
2983 /*
2984 * the block is bad. lose the directory.
2985 * XXX - later, we should try and just lose
2986 * the block without losing the entire directory
2987 */
2988 ASSERT(*dotdot == 0 || (*dotdot == 1 && *parent != NULLFSINO));
2989 libxfs_putbuf(bp);
2990 return(1);
2991 }
2992
2993 /*
2994 * check sibling pointers in leaf block (above doesn't do it)
2995 */
2996 if (INT_GET(leaf->hdr.info.forw, ARCH_CONVERT) != 0 ||
2997 INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != 0) {
2998 if (!no_modify) {
2999 do_warn(_("clearing forw/back pointers for "
3000 "directory inode %llu\n"), ino);
3001 buf_dirty = 1;
3002 leaf->hdr.info.forw = 0;
3003 leaf->hdr.info.back = 0;
3004 } else {
3005 do_warn(_("would clear forw/back pointers for "
3006 "directory inode %llu\n"), ino);
3007 }
3008 }
3009
3010 ASSERT(buf_dirty == 0 || (buf_dirty && !no_modify));
3011
3012 if (buf_dirty && !no_modify)
3013 libxfs_writebuf(bp, 0);
3014 else
3015 libxfs_putbuf(bp);
3016
3017 return(0);
3018 }
3019
3020 /*
3021 * returns 1 if things are bad (directory needs to be junked)
3022 * and 0 if things are ok. If ino_discovery is 1, add unknown
3023 * inodes to uncertain inode list.
3024 */
3025 int
3026 process_dir(
3027 xfs_mount_t *mp,
3028 xfs_ino_t ino,
3029 xfs_dinode_t *dip,
3030 int ino_discovery,
3031 int *dino_dirty,
3032 char *dirname,
3033 xfs_ino_t *parent,
3034 blkmap_t *blkmap)
3035 {
3036 int dot;
3037 int dotdot;
3038 int repair = 0;
3039 int res = 0;
3040
3041 *parent = NULLFSINO;
3042 dot = dotdot = 0;
3043
3044 /*
3045 * branch off depending on the type of inode. This routine
3046 * is only called ONCE so all the subordinate routines will
3047 * fix '.' and junk '..' if they're bogus.
3048 */
3049 if (INT_GET(dip->di_core.di_size, ARCH_CONVERT) <=
3050 XFS_DFORK_DSIZE(dip, mp)) {
3051 dot = 1;
3052 dotdot = 1;
3053 if (process_shortform_dir(mp, ino, dip, ino_discovery,
3054 dino_dirty, parent, dirname, &repair)) {
3055 res = 1;
3056 }
3057 } else if (INT_GET(dip->di_core.di_size, ARCH_CONVERT) <=
3058 XFS_LBSIZE(mp)) {
3059 if (process_leaf_dir(mp, ino, dip, ino_discovery,
3060 dino_dirty, blkmap, &dot, &dotdot,
3061 parent, dirname, &repair)) {
3062 res = 1;
3063 }
3064 } else {
3065 if (process_node_dir(mp, ino, dip, ino_discovery,
3066 blkmap, &dot, &dotdot,
3067 parent, dirname, &repair)) {
3068 res = 1;
3069 }
3070 }
3071 /*
3072 * bad . entries in all directories will be fixed up in phase 6
3073 */
3074 if (dot == 0) {
3075 do_warn(_("no . entry for directory %llu\n"), ino);
3076 }
3077
3078 /*
3079 * shortform dirs always have a .. entry. .. for all longform
3080 * directories will get fixed in phase 6. .. for other shortform
3081 * dirs also get fixed there. .. for a shortform root was
3082 * fixed in place since we know what it should be
3083 */
3084 if (dotdot == 0 && ino != mp->m_sb.sb_rootino) {
3085 do_warn(_("no .. entry for directory %llu\n"), ino);
3086 } else if (dotdot == 0 && ino == mp->m_sb.sb_rootino) {
3087 do_warn(_("no .. entry for root directory %llu\n"), ino);
3088 need_root_dotdot = 1;
3089 }
3090
3091 #ifdef XR_DIR_TRACE
3092 fprintf(stderr, "(process_dir), parent of %llu is %llu\n", ino, parent);
3093 #endif
3094 return(res);
3095 }