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