]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/phase6.c
Minor I18N cleanups, add in xfsprogs.pot message file.
[thirdparty/xfsprogs-dev.git] / repair / phase6.c
CommitLineData
2bd0ea18 1/*
0d3e0b37 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
2bd0ea18
NS
33#include <libxfs.h>
34#include "avl.h"
35#include "globals.h"
36#include "agheader.h"
37#include "incore.h"
38#include "dir.h"
39#include "dir2.h"
40#include "dir_stack.h"
41#include "protos.h"
42#include "err_protos.h"
43#include "dinode.h"
44#include "versions.h"
45
46static cred_t zerocr;
47static int orphanage_entered;
48
49/*
50 * Data structures and routines to keep track of directory entries
51 * and whether their leaf entry has been seen
52 */
53typedef struct dir_hash_ent {
54 struct dir_hash_ent *next; /* pointer to next entry */
55 xfs_dir2_leaf_entry_t ent; /* address and hash value */
56 short junkit; /* name starts with / */
57 short seen; /* have seen leaf entry */
58} dir_hash_ent_t;
59
60typedef struct dir_hash_tab {
61 int size; /* size of hash table */
62 dir_hash_ent_t *tab[1];/* actual hash table, variable size */
63} dir_hash_tab_t;
64#define DIR_HASH_TAB_SIZE(n) \
65 (offsetof(dir_hash_tab_t, tab) + (sizeof(dir_hash_ent_t *) * (n)))
66#define DIR_HASH_FUNC(t,a) ((a) % (t)->size)
67
68/*
69 * Track the contents of the freespace table in a directory.
70 */
71typedef struct freetab {
72 int naents;
73 int nents;
74 struct freetab_ent {
75 xfs_dir2_data_off_t v;
76 short s;
77 } ents[1];
78} freetab_t;
79#define FREETAB_SIZE(n) \
80 (offsetof(freetab_t, ents) + (sizeof(struct freetab_ent) * (n)))
81
82#define DIR_HASH_CK_OK 0
83#define DIR_HASH_CK_DUPLEAF 1
84#define DIR_HASH_CK_BADHASH 2
85#define DIR_HASH_CK_NODATA 3
86#define DIR_HASH_CK_NOLEAF 4
87#define DIR_HASH_CK_BADSTALE 5
88
89static void
90dir_hash_add(
91 dir_hash_tab_t *hashtab,
92 xfs_dahash_t hash,
93 xfs_dir2_dataptr_t addr,
94 int junk)
95{
96 int i;
97 dir_hash_ent_t *p;
98
99 i = DIR_HASH_FUNC(hashtab, addr);
100 if ((p = malloc(sizeof(*p))) == NULL) {
101 do_error("malloc failed in dir_hash_add (%u bytes)\n",
102 sizeof(*p));
103 exit(1);
104 }
105 p->next = hashtab->tab[i];
106 hashtab->tab[i] = p;
107 if (!(p->junkit = junk))
108 p->ent.hashval = hash;
109 p->ent.address = addr;
110 p->seen = 0;
111}
112
113static int
114dir_hash_unseen(
115 dir_hash_tab_t *hashtab)
116{
117 int i;
118 dir_hash_ent_t *p;
119
120 for (i = 0; i < hashtab->size; i++) {
121 for (p = hashtab->tab[i]; p; p = p->next) {
122 if (p->seen == 0)
123 return 1;
124 }
125 }
126 return 0;
127}
128
129static int
130dir_hash_check(
131 dir_hash_tab_t *hashtab,
132 xfs_inode_t *ip,
133 int seeval)
134{
135 static char *seevalstr[] = {
136 "ok",
137 "duplicate leaf",
138 "hash value mismatch",
139 "no data entry",
140 "no leaf entry",
141 "bad stale count",
142 };
143
144 if (seeval == DIR_HASH_CK_OK && dir_hash_unseen(hashtab))
145 seeval = DIR_HASH_CK_NOLEAF;
146 if (seeval == DIR_HASH_CK_OK)
147 return 0;
148 do_warn("bad hash table for directory inode %llu (%s): ", ip->i_ino,
149 seevalstr[seeval]);
150 if (!no_modify)
151 do_warn("rebuilding\n");
152 else
153 do_warn("would rebuild\n");
154 return 1;
155}
156
157static void
158dir_hash_done(
159 dir_hash_tab_t *hashtab)
160{
161 int i;
162 dir_hash_ent_t *n;
163 dir_hash_ent_t *p;
164
165 for (i = 0; i < hashtab->size; i++) {
166 for (p = hashtab->tab[i]; p; p = n) {
167 n = p->next;
168 free(p);
169 }
170 }
171 free(hashtab);
172}
173
174static dir_hash_tab_t *
175dir_hash_init(
176 xfs_fsize_t size)
177{
178 dir_hash_tab_t *hashtab;
179 int hsize;
180
181 hsize = size / (16 * 4);
182 if (hsize > 1024)
183 hsize = 1024;
184 else if (hsize < 16)
185 hsize = 16;
186 if ((hashtab = calloc(DIR_HASH_TAB_SIZE(hsize), 1)) == NULL) {
187 do_error("calloc failed in dir_hash_init\n");
188 exit(1);
189 }
190 hashtab->size = hsize;
191 return hashtab;
192}
193
194static int
195dir_hash_see(
196 dir_hash_tab_t *hashtab,
197 xfs_dahash_t hash,
198 xfs_dir2_dataptr_t addr)
199{
200 int i;
201 dir_hash_ent_t *p;
202
203 i = DIR_HASH_FUNC(hashtab, addr);
204 for (p = hashtab->tab[i]; p; p = p->next) {
205 if (p->ent.address != addr)
206 continue;
207 if (p->seen)
208 return DIR_HASH_CK_DUPLEAF;
209 if (p->junkit == 0 && p->ent.hashval != hash)
210 return DIR_HASH_CK_BADHASH;
211 p->seen = 1;
212 return DIR_HASH_CK_OK;
213 }
214 return DIR_HASH_CK_NODATA;
215}
216
217static int
218dir_hash_see_all(
219 dir_hash_tab_t *hashtab,
220 xfs_dir2_leaf_entry_t *ents,
221 int count,
222 int stale)
223{
224 int i;
225 int j;
226 int rval;
227
228 for (i = j = 0; i < count; i++) {
229 if (INT_GET(ents[i].address, ARCH_CONVERT) == XFS_DIR2_NULL_DATAPTR) {
230 j++;
231 continue;
232 }
233 rval = dir_hash_see(hashtab, INT_GET(ents[i].hashval, ARCH_CONVERT), INT_GET(ents[i].address, ARCH_CONVERT));
234 if (rval != DIR_HASH_CK_OK)
235 return rval;
236 }
237 return j == stale ? DIR_HASH_CK_OK : DIR_HASH_CK_BADSTALE;
238}
239
240
241/*
242 * Version 1 or 2 directory routine wrappers
243*/
244static void
245dir_init(xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *dp, xfs_inode_t *pdp)
246{
247 if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb))
248 libxfs_dir2_init(tp, dp, pdp);
249 else
250 libxfs_dir_init(tp, dp, pdp);
251}
252
253static int
254dir_createname(xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *pip,
255 char *name, int namelen, xfs_ino_t inum, xfs_fsblock_t *first,
256 xfs_bmap_free_t *flist, xfs_extlen_t total)
257{
258 if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb))
259 return libxfs_dir2_createname(tp, pip, name, namelen,
260 inum, first, flist, total);
261 else
262 return libxfs_dir_createname(tp, pip, name, namelen,
263 inum, first, flist, total);
264}
265
266static int
267dir_lookup(xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *dp, char *name,
268 int namelen, xfs_ino_t *inum)
269{
270 if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb))
271 return libxfs_dir2_lookup(tp, dp, name, namelen, inum);
272 else
273 return libxfs_dir_lookup(tp, dp, name, namelen, inum);
274}
275
276static int
277dir_replace(xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *dp, char *name,
278 int namelen, xfs_ino_t inum, xfs_fsblock_t *firstblock,
279 xfs_bmap_free_t *flist, xfs_extlen_t total)
280{
281 if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb))
282 return libxfs_dir2_replace(tp, dp, name, namelen, inum,
283 firstblock, flist, total);
284 else
285 return libxfs_dir_replace(tp, dp, name, namelen, inum,
286 firstblock, flist, total);
287}
288
289static int
290dir_removename(xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *dp, char *name,
291 int namelen, xfs_ino_t inum, xfs_fsblock_t *firstblock,
292 xfs_bmap_free_t *flist, xfs_extlen_t total)
293{
294 if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb))
295 return libxfs_dir2_removename(tp, dp, name, namelen, inum,
296 firstblock, flist, total);
297 else
298 return libxfs_dir_removename(tp, dp, name, namelen, inum,
299 firstblock, flist, total);
300}
301
302static int
303dir_bogus_removename(xfs_mount_t *mp, xfs_trans_t *tp, xfs_inode_t *dp,
304 char *name, xfs_fsblock_t *firstblock, xfs_bmap_free_t *flist,
305 xfs_extlen_t total, xfs_dahash_t hashval, int namelen)
306{
307 if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb))
308 return libxfs_dir2_bogus_removename(tp, dp, name, firstblock,
309 flist, total, hashval, namelen);
310 else
311 return libxfs_dir_bogus_removename(tp, dp, name, firstblock,
312 flist, total, hashval, namelen);
313}
314
315
316static void
317res_failed(
318 int err)
319{
320 if (err == ENOSPC) {
321 do_error("ran out of disk space!\n");
322 } else
323 do_error("xfs_trans_reserve returned %d\n", err);
324}
325
326void
327mk_rbmino(xfs_mount_t *mp)
328{
329 xfs_trans_t *tp;
330 xfs_inode_t *ip;
331 xfs_bmbt_irec_t *ep;
332 xfs_fsblock_t first;
333 int i;
334 int nmap;
335 int committed;
336 int error;
337 xfs_bmap_free_t flist;
338 xfs_dfiloff_t bno;
339 xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP];
340
341 /*
342 * first set up inode
343 */
344 tp = libxfs_trans_alloc(mp, 0);
345
27527004 346 if ((i = libxfs_trans_reserve(tp, 10, 0, 0, 0, 0)))
2bd0ea18
NS
347 res_failed(i);
348
349 error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, &ip);
350 if (error) {
351 do_error("couldn't iget realtime bitmap inode -- error - %d\n",
352 error);
353 }
354
355 bzero(&ip->i_d, sizeof(xfs_dinode_core_t));
356
357 ip->i_d.di_magic = XFS_DINODE_MAGIC;
358 ip->i_d.di_mode = IFREG;
359 ip->i_d.di_version = XFS_DINODE_VERSION_1;
360 ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
361 ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
362
363 ip->i_d.di_nlink = 1; /* account for sb ptr */
364
365 /*
366 * now the ifork
367 */
368 ip->i_df.if_flags = XFS_IFEXTENTS;
369 ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0;
370 ip->i_df.if_u1.if_extents = NULL;
371
372 ip->i_d.di_size = mp->m_sb.sb_rbmblocks * mp->m_sb.sb_blocksize;
373
374 /*
375 * commit changes
376 */
377 libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
378 libxfs_trans_ihold(tp, ip);
379 libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, NULL);
380
381 /*
382 * then allocate blocks for file and fill with zeroes (stolen
383 * from mkfs)
384 */
385 tp = libxfs_trans_alloc(mp, 0);
27527004
NS
386 if ((error = libxfs_trans_reserve(tp, mp->m_sb.sb_rbmblocks +
387 (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1), 0, 0, 0, 0)))
2bd0ea18
NS
388 res_failed(error);
389
390 libxfs_trans_ijoin(tp, ip, 0);
391 bno = 0;
392 XFS_BMAP_INIT(&flist, &first);
393 while (bno < mp->m_sb.sb_rbmblocks) {
394 nmap = XFS_BMAP_MAX_NMAP;
395 error = libxfs_bmapi(tp, ip, bno,
396 (xfs_extlen_t)(mp->m_sb.sb_rbmblocks - bno),
397 XFS_BMAPI_WRITE, &first, mp->m_sb.sb_rbmblocks,
398 map, &nmap, &flist);
399 if (error) {
400 do_error("couldn't allocate realtime bitmap - err %d\n",
401 error);
402 }
403 for (i = 0, ep = map; i < nmap; i++, ep++) {
404 libxfs_device_zero(mp->m_dev,
405 XFS_FSB_TO_DADDR(mp, ep->br_startblock),
406 XFS_FSB_TO_BB(mp, ep->br_blockcount));
407 bno += ep->br_blockcount;
408 }
409 }
410 error = libxfs_bmap_finish(&tp, &flist, first, &committed);
411 if (error) {
412 do_error(
413 "allocation of the realtime bitmap failed, error = %d\n",
414 error);
415 }
416 libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0);
417}
418
419int
420fill_rbmino(xfs_mount_t *mp)
421{
422 xfs_buf_t *bp;
423 xfs_trans_t *tp;
424 xfs_inode_t *ip;
425 xfs_rtword_t *bmp;
426 xfs_fsblock_t first;
427 int nmap;
428 int error;
429 xfs_dfiloff_t bno;
430 xfs_bmbt_irec_t map;
431
432 bmp = btmcompute;
433 bno = 0;
434
435 tp = libxfs_trans_alloc(mp, 0);
436
27527004 437 if ((error = libxfs_trans_reserve(tp, 10, 0, 0, 0, 0)))
2bd0ea18
NS
438 res_failed(error);
439
440 error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, &ip);
441 if (error) {
442 do_error("couldn't iget realtime bitmap inode -- error - %d\n",
443 error);
444 }
445
446 while (bno < mp->m_sb.sb_rbmblocks) {
447 /*
448 * fill the file one block at a time
449 */
450 nmap = 1;
451 error = libxfs_bmapi(tp, ip, bno, 1, XFS_BMAPI_WRITE,
452 &first, 1, &map, &nmap, NULL);
453 if (error || nmap != 1) {
454 do_error(
455 "couldn't map realtime bitmap block %llu - err %d\n",
456 bno, error);
457 }
458
459 ASSERT(map.br_startblock != HOLESTARTBLOCK);
460
461 error = libxfs_trans_read_buf(
462 mp, tp, mp->m_dev,
463 XFS_FSB_TO_DADDR(mp, map.br_startblock),
464 XFS_FSB_TO_BB(mp, 1), 1, &bp);
465
466 if (error) {
467 do_warn(
468 "can't access block %llu (fsbno %llu) of realtime bitmap inode %llu\n",
469 bno, map.br_startblock, mp->m_sb.sb_rbmino);
470 return(1);
471 }
472
473 bcopy(bmp, XFS_BUF_PTR(bp), mp->m_sb.sb_blocksize);
474
475 libxfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
476
477 bmp = (xfs_rtword_t *)((__psint_t) bmp + mp->m_sb.sb_blocksize);
478 bno++;
479 }
480
481 libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0);
482
483 return(0);
484}
485
486int
487fill_rsumino(xfs_mount_t *mp)
488{
489 xfs_buf_t *bp;
490 xfs_trans_t *tp;
491 xfs_inode_t *ip;
492 xfs_suminfo_t *smp;
493 xfs_fsblock_t first;
494 int nmap;
495 int error;
496 xfs_dfiloff_t bno;
497 xfs_dfiloff_t end_bno;
498 xfs_bmbt_irec_t map;
499
500 smp = sumcompute;
501 bno = 0;
502 end_bno = mp->m_rsumsize >> mp->m_sb.sb_blocklog;
503
504 tp = libxfs_trans_alloc(mp, 0);
505
27527004 506 if ((error = libxfs_trans_reserve(tp, 10, 0, 0, 0, 0)))
2bd0ea18
NS
507 res_failed(error);
508
509 error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0, &ip);
510 if (error) {
511 do_error("couldn't iget realtime summary inode -- error - %d\n",
512 error);
513 }
514
515 while (bno < end_bno) {
516 /*
517 * fill the file one block at a time
518 */
519 nmap = 1;
520 error = libxfs_bmapi(tp, ip, bno, 1, XFS_BMAPI_WRITE,
521 &first, 1, &map, &nmap, NULL);
522 if (error || nmap != 1) {
523 do_error(
524 "couldn't map realtime summary inode block %llu - err %d\n",
525 bno, error);
526 }
527
528 ASSERT(map.br_startblock != HOLESTARTBLOCK);
529
530 error = libxfs_trans_read_buf(
531 mp, tp, mp->m_dev,
532 XFS_FSB_TO_DADDR(mp, map.br_startblock),
533 XFS_FSB_TO_BB(mp, 1), 1, &bp);
534
535 if (error) {
536 do_warn(
537 "can't access block %llu (fsbno %llu) of realtime summary inode %llu\n",
538 bno, map.br_startblock, mp->m_sb.sb_rsumino);
539 return(1);
540 }
541
542 bcopy(smp, XFS_BUF_PTR(bp), mp->m_sb.sb_blocksize);
543
544 libxfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
545
546 smp = (xfs_suminfo_t *)((__psint_t)smp + mp->m_sb.sb_blocksize);
547 bno++;
548 }
549
550 libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0);
551
552 return(0);
553}
554
555void
556mk_rsumino(xfs_mount_t *mp)
557{
558 xfs_trans_t *tp;
559 xfs_inode_t *ip;
560 xfs_bmbt_irec_t *ep;
561 xfs_fsblock_t first;
562 int i;
563 int nmap;
564 int committed;
565 int error;
566 int nsumblocks;
567 xfs_bmap_free_t flist;
568 xfs_dfiloff_t bno;
569 xfs_bmbt_irec_t map[XFS_BMAP_MAX_NMAP];
570
571 /*
572 * first set up inode
573 */
574 tp = libxfs_trans_alloc(mp, 0);
575
27527004
NS
576 if ((i = libxfs_trans_reserve(tp, 10, XFS_ICHANGE_LOG_RES(mp), 0,
577 XFS_TRANS_PERM_LOG_RES, XFS_MKDIR_LOG_COUNT)))
2bd0ea18
NS
578 res_failed(i);
579
580 error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0, &ip);
581 if (error) {
582 do_error("couldn't iget realtime summary inode -- error - %d\n",
583 error);
584 }
585
586 bzero(&ip->i_d, sizeof(xfs_dinode_core_t));
587
588 ip->i_d.di_magic = XFS_DINODE_MAGIC;
589 ip->i_d.di_mode = IFREG;
590 ip->i_d.di_version = XFS_DINODE_VERSION_1;
591 ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
592 ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
593
594 ip->i_d.di_nlink = 1; /* account for sb ptr */
595
596 /*
597 * now the ifork
598 */
599 ip->i_df.if_flags = XFS_IFEXTENTS;
600 ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0;
601 ip->i_df.if_u1.if_extents = NULL;
602
603 ip->i_d.di_size = mp->m_rsumsize;
604
605 /*
606 * commit changes
607 */
608 libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
609 libxfs_trans_ihold(tp, ip);
610 libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0);
611
612 /*
613 * then allocate blocks for file and fill with zeroes (stolen
614 * from mkfs)
615 */
616 tp = libxfs_trans_alloc(mp, 0);
617 XFS_BMAP_INIT(&flist, &first);
618
619 nsumblocks = mp->m_rsumsize >> mp->m_sb.sb_blocklog;
27527004 620 if ((error = libxfs_trans_reserve(tp,
2bd0ea18
NS
621 mp->m_sb.sb_rbmblocks +
622 (XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1),
623 BBTOB(128), 0, XFS_TRANS_PERM_LOG_RES,
27527004 624 XFS_DEFAULT_PERM_LOG_COUNT)))
2bd0ea18
NS
625 res_failed(error);
626
627 libxfs_trans_ijoin(tp, ip, 0);
628 bno = 0;
629 XFS_BMAP_INIT(&flist, &first);
630 while (bno < nsumblocks) {
631 nmap = XFS_BMAP_MAX_NMAP;
632 error = libxfs_bmapi(tp, ip, bno,
633 (xfs_extlen_t)(nsumblocks - bno),
634 XFS_BMAPI_WRITE, &first, nsumblocks,
635 map, &nmap, &flist);
636 if (error) {
637 do_error(
638 "couldn't allocate realtime summary inode - err %d\n",
639 error);
640 }
641 for (i = 0, ep = map; i < nmap; i++, ep++) {
642 libxfs_device_zero(mp->m_dev,
643 XFS_FSB_TO_DADDR(mp, ep->br_startblock),
644 XFS_FSB_TO_BB(mp, ep->br_blockcount));
645 do_error("dev_zero of rtbitmap failed\n");
646 bno += ep->br_blockcount;
647 }
648 }
649 error = libxfs_bmap_finish(&tp, &flist, first, &committed);
650 if (error) {
651 do_error(
652 "allocation of the realtime summary ino failed, err = %d\n",
653 error);
654 }
655 libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0);
656}
657
658/*
659 * makes a new root directory.
660 */
661void
662mk_root_dir(xfs_mount_t *mp)
663{
664 xfs_trans_t *tp;
665 xfs_inode_t *ip;
666 int i;
667 int error;
668 const mode_t mode = 0755;
669
670 tp = libxfs_trans_alloc(mp, 0);
671 ip = NULL;
672
27527004
NS
673 if ((i = libxfs_trans_reserve(tp, 10, XFS_ICHANGE_LOG_RES(mp), 0,
674 XFS_TRANS_PERM_LOG_RES, XFS_MKDIR_LOG_COUNT)))
2bd0ea18
NS
675 res_failed(i);
676
677 error = libxfs_trans_iget(mp, tp, mp->m_sb.sb_rootino, 0, &ip);
678 if (error) {
679 do_error("could not iget root inode -- error - %d\n", error);
680 }
681
682 /*
683 * take care of the core -- initialization from xfs_ialloc()
684 */
685 bzero(&ip->i_d, sizeof(xfs_dinode_core_t));
686
687 ip->i_d.di_magic = XFS_DINODE_MAGIC;
688 ip->i_d.di_mode = (__uint16_t) mode|IFDIR;
689 ip->i_d.di_version = XFS_DINODE_VERSION_1;
690 ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS;
691 ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
692
693 ip->i_d.di_nlink = 1; /* account for . */
694
695 libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
696
697 /*
698 * now the ifork
699 */
700 ip->i_df.if_flags = XFS_IFEXTENTS;
701 ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0;
702 ip->i_df.if_u1.if_extents = NULL;
703
704 mp->m_rootip = ip;
705
706 /*
707 * initialize the directory
708 */
709 dir_init(mp, tp, ip, ip);
710
711 libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0);
712}
713
714/*
715 * orphanage name == lost+found
716 */
717xfs_ino_t
718mk_orphanage(xfs_mount_t *mp)
719{
720 xfs_ino_t ino;
721 xfs_trans_t *tp;
722 xfs_inode_t *ip;
723 xfs_inode_t *pip;
724 xfs_fsblock_t first;
725 int i;
726 int committed;
727 int error;
728 xfs_bmap_free_t flist;
729 const int mode = 0755;
730 const int uid = 0;
731 const int gid = 0;
732 int nres;
733
734 tp = libxfs_trans_alloc(mp, 0);
735 XFS_BMAP_INIT(&flist, &first);
736
737 nres = XFS_MKDIR_SPACE_RES(mp, strlen(ORPHANAGE));
27527004
NS
738 if ((i = libxfs_trans_reserve(tp, nres, XFS_MKDIR_LOG_RES(mp), 0,
739 XFS_TRANS_PERM_LOG_RES, XFS_MKDIR_LOG_COUNT)))
2bd0ea18
NS
740 res_failed(i);
741
742 /*
743 * use iget/ijoin instead of trans_iget because the ialloc
744 * wrapper can commit the transaction and start a new one
745 */
27527004 746 if ((i = libxfs_iget(mp, NULL, mp->m_sb.sb_rootino, 0, &pip, 0)))
2bd0ea18
NS
747 do_error("%d - couldn't iget root inode to make %s\n",
748 i, ORPHANAGE);
749
750 error = libxfs_inode_alloc(&tp, pip, mode|IFDIR,
751 1, mp->m_dev, &zerocr, &ip);
752
753 if (error) {
754 do_error("%s inode allocation failed %d\n",
755 ORPHANAGE, error);
756 }
757
758 ip->i_d.di_uid = uid;
759 ip->i_d.di_gid = gid;
760 ip->i_d.di_nlink++; /* account for . */
761
762 /*
763 * now that we know the transaction will stay around,
764 * add the root inode to it
765 */
766 libxfs_trans_ijoin(tp, pip, 0);
767
768 /*
769 * create the actual entry
770 */
27527004
NS
771 if ((error = dir_createname(mp, tp, pip, ORPHANAGE,
772 strlen(ORPHANAGE), ip->i_ino, &first, &flist, nres))) {
2bd0ea18
NS
773 do_warn("can't make %s, createname error %d, will try later\n",
774 ORPHANAGE, error);
775 orphanage_entered = 0;
776 } else
777 orphanage_entered = 1;
778
779 /*
780 * bump up the link count in the root directory to account
781 * for .. in the new directory
782 */
783 pip->i_d.di_nlink++;
784
785 libxfs_trans_log_inode(tp, pip, XFS_ILOG_CORE);
786 dir_init(mp, tp, ip, pip);
787 libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
788
789 error = libxfs_bmap_finish(&tp, &flist, first, &committed);
790 if (error) {
791 do_error("%s directory creation failed -- bmapf error %d\n",
792 ORPHANAGE, error);
793 }
794
795 ino = ip->i_ino;
796
797 libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0);
798
799 /* need libxfs_iput here? - nathans TODO - possible memory leak? */
800
801 return(ino);
802}
803
804/*
805 * move a file to the orphange. the orphanage is guaranteed
806 * at this point to only have file in it whose name == file inode #
807 */
808void
809mv_orphanage(xfs_mount_t *mp,
810 xfs_ino_t dir_ino, /* orphange inode # */
811 xfs_ino_t ino, /* inode # to be moved */
812 int isa_dir) /* 1 if inode is a directory */
813{
814 xfs_ino_t entry_ino_num;
815 xfs_inode_t *dir_ino_p;
816 xfs_inode_t *ino_p;
817 xfs_trans_t *tp;
818 xfs_fsblock_t first;
819 xfs_bmap_free_t flist;
820 int err;
821 int committed;
822 char fname[MAXPATHLEN + 1];
823 int nres;
824
2d9475a4 825 snprintf(fname, sizeof(fname), "%llu", (unsigned long long)ino);
2bd0ea18 826
27527004 827 if ((err = libxfs_iget(mp, NULL, dir_ino, 0, &dir_ino_p, 0)))
2bd0ea18
NS
828 do_error("%d - couldn't iget orphanage inode\n", err);
829
830 tp = libxfs_trans_alloc(mp, 0);
831
27527004 832 if ((err = libxfs_iget(mp, NULL, ino, 0, &ino_p, 0)))
2bd0ea18
NS
833 do_error("%d - couldn't iget disconnected inode\n", err);
834
835 if (isa_dir) {
836 nres = XFS_DIRENTER_SPACE_RES(mp, strlen(fname)) +
837 XFS_DIRENTER_SPACE_RES(mp, 2);
27527004
NS
838 if ((err = dir_lookup(mp, tp, ino_p, "..", 2,
839 &entry_ino_num))) {
2bd0ea18
NS
840 ASSERT(err == ENOENT);
841
27527004 842 if ((err = libxfs_trans_reserve(tp, nres,
2bd0ea18
NS
843 XFS_RENAME_LOG_RES(mp), 0,
844 XFS_TRANS_PERM_LOG_RES,
27527004 845 XFS_RENAME_LOG_COUNT)))
2bd0ea18
NS
846 do_error(
847 "space reservation failed (%d), filesystem may be out of space\n",
848 err);
849
850 libxfs_trans_ijoin(tp, dir_ino_p, 0);
851 libxfs_trans_ijoin(tp, ino_p, 0);
852
853 XFS_BMAP_INIT(&flist, &first);
27527004 854 if ((err = dir_createname(mp, tp, dir_ino_p, fname,
2bd0ea18 855 strlen(fname), ino, &first,
27527004 856 &flist, nres)))
2bd0ea18
NS
857 do_error(
858 "name create failed in %s (%d), filesystem may be out of space\n",
859 ORPHANAGE, err);
860
861 dir_ino_p->i_d.di_nlink++;
862 libxfs_trans_log_inode(tp, dir_ino_p, XFS_ILOG_CORE);
863
27527004
NS
864 if ((err = dir_createname(mp, tp, ino_p, "..", 2,
865 dir_ino, &first, &flist, nres)))
2bd0ea18
NS
866 do_error(
867 "creation of .. entry failed (%d), filesystem may be out of space\n",
868 err);
869
870 ino_p->i_d.di_nlink++;
871 libxfs_trans_log_inode(tp, ino_p, XFS_ILOG_CORE);
872
27527004 873 if ((err = libxfs_bmap_finish(&tp, &flist, first, &committed)))
2bd0ea18
NS
874 do_error(
875 "bmap finish failed (err - %d), filesystem may be out of space\n",
876 err);
877
878 libxfs_trans_commit(tp,
879 XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0);
880 } else {
27527004 881 if ((err = libxfs_trans_reserve(tp, nres,
2bd0ea18
NS
882 XFS_RENAME_LOG_RES(mp), 0,
883 XFS_TRANS_PERM_LOG_RES,
27527004 884 XFS_RENAME_LOG_COUNT)))
2bd0ea18
NS
885 do_error(
886 "space reservation failed (%d), filesystem may be out of space\n",
887 err);
888
889 libxfs_trans_ijoin(tp, dir_ino_p, 0);
890 libxfs_trans_ijoin(tp, ino_p, 0);
891
892 XFS_BMAP_INIT(&flist, &first);
893
27527004 894 if ((err = dir_createname(mp, tp, dir_ino_p, fname,
2bd0ea18 895 strlen(fname), ino, &first,
27527004 896 &flist, nres)))
2bd0ea18
NS
897 do_error(
898 "name create failed in %s (%d), filesystem may be out of space\n",
899 ORPHANAGE, err);
900
901 dir_ino_p->i_d.di_nlink++;
902 libxfs_trans_log_inode(tp, dir_ino_p, XFS_ILOG_CORE);
903
904 /*
905 * don't replace .. value if it already points
906 * to us. that'll pop a libxfs/kernel ASSERT.
907 */
908 if (entry_ino_num != dir_ino) {
27527004 909 if ((err = dir_replace(mp, tp, ino_p, "..",
2bd0ea18 910 2, dir_ino, &first,
27527004 911 &flist, nres)))
2bd0ea18
NS
912 do_error(
913 "name replace op failed (%d), filesystem may be out of space\n",
914 err);
915 }
916
27527004
NS
917 if ((err = libxfs_bmap_finish(&tp, &flist, first,
918 &committed)))
2bd0ea18
NS
919 do_error(
920 "bmap finish failed (%d), filesystem may be out of space\n",
921 err);
922
923 libxfs_trans_commit(tp,
924 XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0);
925 }
926 } else {
927 /*
928 * use the remove log reservation as that's
929 * more accurate. we're only creating the
930 * links, we're not doing the inode allocation
931 * also accounted for in the create
932 */
933 nres = XFS_DIRENTER_SPACE_RES(mp, strlen(fname));
27527004
NS
934 if ((err = libxfs_trans_reserve(tp, nres, XFS_REMOVE_LOG_RES(mp), 0,
935 XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT)))
2bd0ea18
NS
936 do_error(
937 "space reservation failed (%d), filesystem may be out of space\n",
938 err);
939
940 libxfs_trans_ijoin(tp, dir_ino_p, 0);
941 libxfs_trans_ijoin(tp, ino_p, 0);
942
943 XFS_BMAP_INIT(&flist, &first);
27527004
NS
944 if ((err = dir_createname(mp, tp, dir_ino_p, fname,
945 strlen(fname), ino, &first, &flist, nres)))
2bd0ea18
NS
946 do_error(
947 "name create failed in %s (%d), filesystem may be out of space\n",
948 ORPHANAGE, err);
949 ASSERT(err == 0);
950
951 ino_p->i_d.di_nlink = 1;
952 libxfs_trans_log_inode(tp, ino_p, XFS_ILOG_CORE);
953
27527004 954 if ((err = libxfs_bmap_finish(&tp, &flist, first, &committed)))
2bd0ea18
NS
955 do_error(
956 "bmap finish failed (%d), filesystem may be out of space\n",
957 err);
958
959 libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0);
960 }
961}
962
963/*
964 * like get_first_dblock_fsbno only it uses the simulation code instead
965 * of raw I/O.
966 *
967 * Returns the fsbno of the first (leftmost) block in the directory leaf.
968 * sets *bno to the directory block # corresponding to the returned fsbno.
969 */
970xfs_dfsbno_t
971map_first_dblock_fsbno(xfs_mount_t *mp,
972 xfs_ino_t ino,
973 xfs_inode_t *ip,
974 xfs_dablk_t *bno)
975{
976 xfs_fsblock_t fblock;
977 xfs_da_intnode_t *node;
978 xfs_buf_t *bp;
979 xfs_dablk_t da_bno;
980 xfs_dfsbno_t fsbno;
981 xfs_bmbt_irec_t map;
982 int nmap;
983 int i;
984 int error;
985 char *ftype;
986
987 /*
988 * traverse down left-side of tree until we hit the
989 * left-most leaf block setting up the btree cursor along
990 * the way.
991 */
992 da_bno = 0;
993 *bno = 0;
994 i = -1;
995 node = NULL;
996 fblock = NULLFSBLOCK;
997 ftype = "dir";
998
999 nmap = 1;
1000 error = libxfs_bmapi(NULL, ip, (xfs_fileoff_t) da_bno, 1,
1001 XFS_BMAPI_METADATA, &fblock, 0,
1002 &map, &nmap, NULL);
1003 if (error || nmap != 1) {
1004 if (!no_modify)
1005 do_error(
1006"can't map block %d in %s inode %llu, xfs_bmapi returns %d, nmap = %d\n",
1007 da_bno, ftype, ino, error, nmap);
1008 else {
1009 do_warn(
1010"can't map block %d in %s inode %llu, xfs_bmapi returns %d, nmap = %d\n",
1011 da_bno, ftype, ino, error, nmap);
1012 return(NULLDFSBNO);
1013 }
1014 }
1015
1016 if ((fsbno = map.br_startblock) == HOLESTARTBLOCK) {
1017 if (!no_modify)
1018 do_error("block %d in %s ino %llu doesn't exist\n",
1019 da_bno, ftype, ino);
1020 else {
1021 do_warn("block %d in %s ino %llu doesn't exist\n",
1022 da_bno, ftype, ino);
1023 return(NULLDFSBNO);
1024 }
1025 }
1026
1027 if (ip->i_d.di_size <= XFS_LBSIZE(mp))
1028 return(fsbno);
1029
1030 if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb))
1031 return(fsbno);
1032
1033 do {
1034 /*
1035 * walk down left side of btree, release buffers as you
1036 * go. if the root block is a leaf (single-level btree),
1037 * just return it.
1038 *
1039 */
1040
1041 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
1042 XFS_FSB_TO_BB(mp, 1), 0);
1043
1044 if (!bp) {
1045 do_warn(
1046 "can't read block %u (fsbno %llu) for directory inode %llu\n",
1047 da_bno, fsbno, ino);
1048 return(NULLDFSBNO);
1049 }
1050
1051 node = (xfs_da_intnode_t *)XFS_BUF_PTR(bp);
1052
1053 if (INT_GET(node->hdr.info.magic, ARCH_CONVERT) != XFS_DA_NODE_MAGIC) {
1054 libxfs_putbuf(bp);
1055 do_warn(
1056"bad dir/attr magic number in inode %llu, file bno = %u, fsbno = %llu\n",
1057 ino, da_bno, fsbno);
1058 return(NULLDFSBNO);
1059 }
1060
1061 if (i == -1)
1062 i = INT_GET(node->hdr.level, ARCH_CONVERT);
1063
1064 da_bno = INT_GET(node->btree[0].before, ARCH_CONVERT);
1065
1066 libxfs_putbuf(bp);
1067 bp = NULL;
1068
1069 nmap = 1;
1070 error = libxfs_bmapi(NULL, ip, (xfs_fileoff_t) da_bno, 1,
1071 XFS_BMAPI_METADATA, &fblock, 0,
1072 &map, &nmap, NULL);
1073 if (error || nmap != 1) {
1074 if (!no_modify)
1075 do_error(
1076 "can't map block %d in %s ino %llu, xfs_bmapi returns %d, nmap = %d\n",
1077 da_bno, ftype, ino, error, nmap);
1078 else {
1079 do_warn(
1080 "can't map block %d in %s ino %llu, xfs_bmapi returns %d, nmap = %d\n",
1081 da_bno, ftype, ino, error, nmap);
1082 return(NULLDFSBNO);
1083 }
1084 }
1085 if ((fsbno = map.br_startblock) == HOLESTARTBLOCK) {
1086 if (!no_modify)
1087 do_error(
1088 "block %d in %s inode %llu doesn't exist\n",
1089 da_bno, ftype, ino);
1090 else {
1091 do_warn(
1092 "block %d in %s inode %llu doesn't exist\n",
1093 da_bno, ftype, ino);
1094 return(NULLDFSBNO);
1095 }
1096 }
1097
1098 i--;
1099 } while(i > 0);
1100
1101 *bno = da_bno;
1102 return(fsbno);
1103}
1104
1105/*
1106 * scan longform directory and prune first bad entry. returns 1 if
1107 * it had to remove something, 0 if it made it all the way through
1108 * the directory. prune_lf_dir_entry does all the necessary bmap calls.
1109 *
1110 * hashval is an in/out -- starting hashvalue in, hashvalue of the
1111 * deleted entry (if there was one) out
1112 *
1113 * this routine can NOT be called if running in no modify mode
1114 */
1115int
1116prune_lf_dir_entry(xfs_mount_t *mp, xfs_ino_t ino, xfs_inode_t *ip,
1117 xfs_dahash_t *hashval)
1118{
1119 xfs_dfsbno_t fsbno;
1120 int i;
1121 int index;
1122 int error;
1123 int namelen;
1124 xfs_bmap_free_t free_list;
1125 xfs_fsblock_t first_block;
1126 xfs_buf_t *bp;
1127 xfs_dir_leaf_name_t *namest;
1128 xfs_dir_leafblock_t *leaf;
1129 xfs_dir_leaf_entry_t *entry;
1130 xfs_trans_t *tp;
1131 xfs_dablk_t da_bno;
1132 xfs_fsblock_t fblock;
1133 int committed;
1134 int nmap;
1135 xfs_bmbt_irec_t map;
1136 char fname[MAXNAMELEN + 1];
1137 char *ftype;
1138 int nres;
1139
1140 /*
1141 * ok, this is kind of a schizoid routine. we use our
1142 * internal bmapi routines to walk the directory. when
1143 * we find a bogus entry, we release the buffer so
1144 * the simulation code doesn't deadlock and use the
1145 * sim code to remove the entry. That will cause an
1146 * extra bmap traversal to map the block but I think
1147 * that's preferable to hacking the bogus removename
1148 * function to be really different and then trying to
1149 * maintain both versions as time goes on.
1150 *
1151 * first, grab the dinode and find the right leaf block.
1152 */
1153
1154 ftype = "dir";
1155 da_bno = 0;
1156 bp = NULL;
1157 namest = NULL;
1158 fblock = NULLFSBLOCK;
1159
1160 fsbno = map_first_dblock_fsbno(mp, ino, ip, &da_bno);
1161
1162 /*
1163 * now go foward along the leaves of the btree looking
1164 * for an entry beginning with '/'
1165 */
1166 do {
1167 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
1168 XFS_FSB_TO_BB(mp, 1), 0);
1169
1170 if (!bp) {
1171 do_error(
1172 "can't read directory inode %llu (leaf) block %u (fsbno %llu)\n",
1173 ino, da_bno, fsbno);
1174 /* NOTREACHED */
1175 }
1176
1177 leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp);
1178 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DIR_LEAF_MAGIC);
1179 entry = &leaf->entries[0];
1180
1181 for (index = -1, i = 0;
1182 i < INT_GET(leaf->hdr.count, ARCH_CONVERT) && index == -1;
1183 i++) {
1184 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
1185 if (namest->name[0] != '/')
1186 entry++;
1187 else
1188 index = i;
1189 }
1190
1191 /*
1192 * if we got a bogus entry, exit loop with a pointer to
1193 * the leaf block buffer. otherwise, keep trying blocks
1194 */
1195 da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
1196
1197 if (index == -1) {
1198 if (bp != NULL) {
1199 libxfs_putbuf(bp);
1200 bp = NULL;
1201 }
1202
1203 /*
1204 * map next leaf block unless we've run out
1205 */
1206 if (da_bno != 0) {
1207 nmap = 1;
1208 error = libxfs_bmapi(NULL, ip,
1209 (xfs_fileoff_t) da_bno, 1,
1210 XFS_BMAPI_METADATA, &fblock, 0,
1211 &map, &nmap, NULL);
1212 if (error || nmap != 1)
1213 do_error(
1214"can't map block %d in directory %llu, xfs_bmapi returns %d, nmap = %d\n",
1215 da_bno, ino, error, nmap);
1216 if ((fsbno = map.br_startblock)
1217 == HOLESTARTBLOCK) {
1218 do_error(
1219 "%s ino %llu block %d doesn't exist\n",
1220 ftype, ino, da_bno);
1221 }
1222 }
1223 }
1224 } while (da_bno != 0 && index == -1);
1225
1226 /*
1227 * if we hit the edge of the tree with no bad entries, we're done
1228 * and the buffer was released.
1229 */
1230 if (da_bno == 0 && index == -1)
1231 return(0);
1232
1233 ASSERT(index >= 0);
1234 ASSERT(entry == &leaf->entries[index]);
1235 ASSERT(namest == XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT)));
1236
1237 /*
1238 * snag the info we need out of the directory then release all buffers
1239 */
1240 bcopy(namest->name, fname, entry->namelen);
1241 fname[entry->namelen] = '\0';
1242 *hashval = INT_GET(entry->hashval, ARCH_CONVERT);
1243 namelen = entry->namelen;
1244
1245 libxfs_putbuf(bp);
1246
1247 /*
1248 * ok, now the hard part, blow away the index'th entry in this block
1249 *
1250 * allocate a remove transaction for it. that's not quite true since
1251 * we're only messing with one inode, not two but...
1252 */
1253
1254 tp = libxfs_trans_alloc(mp, XFS_TRANS_REMOVE);
1255
1256 nres = XFS_REMOVE_SPACE_RES(mp);
1257 error = libxfs_trans_reserve(tp, nres, XFS_REMOVE_LOG_RES(mp),
1258 0, XFS_TRANS_PERM_LOG_RES,
1259 XFS_REMOVE_LOG_COUNT);
1260 if (error)
1261 res_failed(error);
1262
1263 libxfs_trans_ijoin(tp, ip, 0);
1264 libxfs_trans_ihold(tp, ip);
1265
1266 XFS_BMAP_INIT(&free_list, &first_block);
1267
1268 error = dir_bogus_removename(mp, tp, ip, fname,
1269 &first_block, &free_list, nres, *hashval, namelen);
1270
1271 if (error) {
1272 do_error(
1273"couldn't remove bogus entry \"%s\" in\n\tdirectory inode %llu, errno = %d\n",
1274 fname, ino, error);
1275 /* NOTREACHED */
1276 }
1277
1278 error = libxfs_bmap_finish(&tp, &free_list, first_block, &committed);
1279
1280 ASSERT(error == 0);
1281
1282 libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_SYNC, 0);
1283
1284 return(1);
1285}
1286
1287/*
1288 * process a leaf block, also checks for .. entry
1289 * and corrects it to match what we think .. should be
1290 */
1291void
1292lf_block_dir_entry_check(xfs_mount_t *mp,
1293 xfs_ino_t ino,
1294 xfs_dir_leafblock_t *leaf,
1295 int *dirty,
1296 int *num_illegal,
1297 int *need_dot,
1298 dir_stack_t *stack,
1299 ino_tree_node_t *current_irec,
1300 int current_ino_offset)
1301{
1302 xfs_dir_leaf_entry_t *entry;
1303 ino_tree_node_t *irec;
1304 xfs_ino_t lino;
1305 xfs_ino_t parent;
1306 xfs_dir_leaf_name_t *namest;
1307 int i;
1308 int junkit;
1309 int ino_offset;
1310 int nbad;
1311 char fname[MAXNAMELEN + 1];
1312
1313 entry = &leaf->entries[0];
1314 *dirty = 0;
1315 nbad = 0;
1316
1317 /*
1318 * look at each entry. reference inode pointed to by each
1319 * entry in the incore inode tree.
1320 * if not a directory, set reached flag, increment link count
1321 * if a directory and reached, mark entry as to be deleted.
1322 * if a directory, check to see if recorded parent
1323 * matches current inode #,
1324 * if so, then set reached flag, increment link count
1325 * of current and child dir inodes, push the child
1326 * directory inode onto the directory stack.
1327 * if current inode != parent, then mark entry to be deleted.
1328 *
1329 * return
1330 */
1331 for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) {
1332 /*
1333 * snag inode #, update link counts, and make sure
1334 * this isn't a loop if the child is a directory
1335 */
1336 namest = XFS_DIR_LEAF_NAMESTRUCT(leaf, INT_GET(entry->nameidx, ARCH_CONVERT));
1337
1338 /*
1339 * skip bogus entries (leading '/'). they'll be deleted
1340 * later
1341 */
1342 if (namest->name[0] == '/') {
1343 nbad++;
1344 continue;
1345 }
1346
1347 junkit = 0;
1348
1349 XFS_DIR_SF_GET_DIRINO_ARCH(&namest->inumber, &lino, ARCH_CONVERT);
1350 bcopy(namest->name, fname, entry->namelen);
1351 fname[entry->namelen] = '\0';
1352
1353 ASSERT(lino != NULLFSINO);
1354
1355 /*
1356 * skip the '..' entry since it's checked when the
1357 * directory is reached by something else. if it never
1358 * gets reached, it'll be moved to the orphanage and we'll
1359 * take care of it then.
1360 */
1361 if (entry->namelen == 2 && namest->name[0] == '.' &&
1362 namest->name[1] == '.') {
1363 continue;
1364 }
1365 ASSERT(no_modify || !verify_inum(mp, lino));
1366
1367 /*
1368 * special case the . entry. we know there's only one
1369 * '.' and only '.' points to itself because bogus entries
1370 * got trashed in phase 3 if there were > 1.
1371 * bump up link count for '.' but don't set reached
1372 * until we're actually reached by another directory
1373 * '..' is already accounted for or will be taken care
1374 * of when directory is moved to orphanage.
1375 */
1376 if (ino == lino) {
1377 ASSERT(namest->name[0] == '.' && entry->namelen == 1);
1378 add_inode_ref(current_irec, current_ino_offset);
1379 *need_dot = 0;
1380 continue;
1381 }
1382
1383 /*
1384 * special case the "lost+found" entry if pointing
1385 * to where we think lost+found should be. if that's
1386 * the case, that's the one we created in phase 6.
1387 * just skip it. no need to process it and it's ..
1388 * link is already accounted for.
1389 */
1390
1391 if (lino == orphanage_ino && strcmp(fname, ORPHANAGE) == 0)
1392 continue;
1393
1394 /*
1395 * skip entries with bogus inumbers if we're in no modify mode
1396 */
1397 if (no_modify && verify_inum(mp, lino))
1398 continue;
1399
1400 /*
1401 * ok, now handle the rest of the cases besides '.' and '..'
1402 */
1403 irec = find_inode_rec(XFS_INO_TO_AGNO(mp, lino),
1404 XFS_INO_TO_AGINO(mp, lino));
1405
1406 if (irec == NULL) {
1407 nbad++;
1408 do_warn(
1409 "entry \"%s\" in dir inode %llu points to non-existent inode, ",
1410 fname, ino);
1411
1412 if (!no_modify) {
1413 namest->name[0] = '/';
1414 *dirty = 1;
1415 do_warn("marking entry to be junked\n");
1416 } else {
1417 do_warn("would junk entry\n");
1418 }
1419
1420 continue;
1421 }
1422
1423 ino_offset = XFS_INO_TO_AGINO(mp, lino) - irec->ino_startnum;
1424
1425 /*
1426 * if it's a free inode, blow out the entry.
1427 * by now, any inode that we think is free
1428 * really is free.
1429 */
1430 if (is_inode_free(irec, ino_offset)) {
1431 /*
1432 * don't complain if this entry points to the old
1433 * and now-free lost+found inode
1434 */
1435 if (verbose || no_modify || lino != old_orphanage_ino)
1436 do_warn(
1437 "entry \"%s\" in dir inode %llu points to free inode %llu",
1438 fname, ino, lino);
1439 nbad++;
1440
1441 if (!no_modify) {
1442 if (verbose || lino != old_orphanage_ino)
1443 do_warn(", marking entry to be junked\n");
1444
1445 else
1446 do_warn("\n");
1447 namest->name[0] = '/';
1448 *dirty = 1;
1449 } else {
1450 do_warn(", would junk entry\n");
1451 }
1452
1453 continue;
1454 }
1455
1456 /*
1457 * check easy case first, regular inode, just bump
1458 * the link count and continue
1459 */
1460 if (!inode_isadir(irec, ino_offset)) {
1461 add_inode_reached(irec, ino_offset);
1462 continue;
1463 }
1464
1465 parent = get_inode_parent(irec, ino_offset);
1466 ASSERT(parent != 0);
1467
1468 /*
1469 * bump up the link counts in parent and child
1470 * directory but if the link doesn't agree with
1471 * the .. in the child, blow out the entry.
1472 * if the directory has already been reached,
1473 * blow away the entry also.
1474 */
1475 if (is_inode_reached(irec, ino_offset)) {
1476 junkit = 1;
1477 do_warn(
1478"entry \"%s\" in dir %llu points to an already connected dir inode %llu,\n",
1479 fname, ino, lino);
1480 } else if (parent == ino) {
1481 add_inode_reached(irec, ino_offset);
1482 add_inode_ref(current_irec, current_ino_offset);
1483
1484 if (!is_inode_refchecked(lino, irec, ino_offset))
1485 push_dir(stack, lino);
1486 } else {
1487 junkit = 1;
1488 do_warn(
1489"entry \"%s\" in dir ino %llu not consistent with .. value (%llu) in ino %llu,\n",
1490 fname, ino, parent, lino);
1491 }
1492
1493 if (junkit) {
1494 junkit = 0;
1495 nbad++;
1496
1497 if (!no_modify) {
1498 namest->name[0] = '/';
1499 *dirty = 1;
1500 if (verbose || lino != old_orphanage_ino)
1501 do_warn("\twill clear entry \"%s\"\n",
1502 fname);
1503 } else {
1504 do_warn("\twould clear entry \"%s\"\n", fname);
1505 }
1506 }
1507 }
1508
1509 *num_illegal += nbad;
1510}
1511
1512/*
1513 * succeeds or dies, inode never gets dirtied since all changes
1514 * happen in file blocks. the inode size and other core info
1515 * is already correct, it's just the leaf entries that get altered.
1516 */
1517void
1518longform_dir_entry_check(xfs_mount_t *mp,
1519 xfs_ino_t ino,
1520 xfs_inode_t *ip,
1521 int *num_illegal,
1522 int *need_dot,
1523 dir_stack_t *stack,
1524 ino_tree_node_t *irec,
1525 int ino_offset)
1526{
1527 xfs_dir_leafblock_t *leaf;
1528 xfs_buf_t *bp;
1529 xfs_dfsbno_t fsbno;
1530 xfs_fsblock_t fblock;
1531 xfs_dablk_t da_bno;
1532 int dirty;
1533 int nmap;
1534 int error;
1535 int skipit;
1536 xfs_bmbt_irec_t map;
1537 char *ftype;
1538
1539 da_bno = 0;
1540 fblock = NULLFSBLOCK;
1541 *need_dot = 1;
1542 ftype = "dir";
1543
1544 fsbno = map_first_dblock_fsbno(mp, ino, ip, &da_bno);
1545
1546 if (fsbno == NULLDFSBNO && no_modify) {
1547 do_warn("cannot map block 0 of directory inode %llu\n", ino);
1548 return;
1549 }
1550
1551 do {
1552 ASSERT(fsbno != NULLDFSBNO);
1553 skipit = 0;
1554
1555 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, fsbno),
1556 XFS_FSB_TO_BB(mp, 1), 0);
1557
1558 if (!bp) {
1559 do_error(
1560 "can't read block %u (fsbno %llu) for directory inode %llu\n",
1561 da_bno, fsbno, ino);
1562 /* NOTREACHED */
1563 }
1564
1565 leaf = (xfs_dir_leafblock_t *)XFS_BUF_PTR(bp);
1566
1567 da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
1568
1569 if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR_LEAF_MAGIC) {
1570 if (!no_modify) {
1571 do_error(
1572 "bad magic # (0x%x) for dir ino %llu leaf block (bno %u fsbno %llu)\n",
1573 INT_GET(leaf->hdr.info.magic, ARCH_CONVERT),
1574 ino, da_bno, fsbno);
1575 /* NOTREACHED */
1576 } else {
1577 /*
1578 * this block's bad but maybe the
1579 * forward pointer is good...
1580 */
1581 skipit = 1;
1582 dirty = 0;
1583 }
1584 }
1585
1586 if (!skipit)
1587 lf_block_dir_entry_check(mp, ino, leaf, &dirty,
1588 num_illegal, need_dot, stack,
1589 irec, ino_offset);
1590
27527004 1591 ASSERT(dirty == 0 || (dirty && !no_modify));
2bd0ea18
NS
1592
1593 if (dirty && !no_modify)
1594 libxfs_writebuf(bp, 0);
1595 else
1596 libxfs_putbuf(bp);
1597 bp = NULL;
1598
1599 if (da_bno != 0) {
1600 nmap = 1;
1601 error = libxfs_bmapi(NULL, ip, (xfs_fileoff_t)da_bno, 1,
1602 XFS_BMAPI_METADATA, &fblock, 0,
1603 &map, &nmap, NULL);
1604 if (error || nmap != 1) {
1605 if (!no_modify)
1606 do_error(
1607"can't map leaf block %d in dir %llu, xfs_bmapi returns %d, nmap = %d\n",
1608 da_bno, ino, error, nmap);
1609 else {
1610 do_warn(
1611"can't map leaf block %d in dir %llu, xfs_bmapi returns %d, nmap = %d\n",
1612 da_bno, ino, error, nmap);
1613 return;
1614 }
1615 }
1616 if ((fsbno = map.br_startblock) == HOLESTARTBLOCK) {
1617 if (!no_modify)
1618 do_error(
1619 "block %d in %s ino %llu doesn't exist\n",
1620 da_bno, ftype, ino);
1621 else {
1622 do_warn(
1623 "block %d in %s ino %llu doesn't exist\n",
1624 da_bno, ftype, ino);
1625 return;
1626 }
1627 }
1628 }
1629 } while (da_bno != 0);
1630}
1631
1632/*
1633 * Kill a block in a version 2 inode.
1634 * Makes its own transaction.
1635 */
1636static void
1637dir2_kill_block(
1638 xfs_mount_t *mp,
1639 xfs_inode_t *ip,
1640 xfs_dablk_t da_bno,
1641 xfs_dabuf_t *bp)
1642{
1643 xfs_da_args_t args;
1644 int committed;
1645 int error;
1646 xfs_fsblock_t firstblock;
1647 xfs_bmap_free_t flist;
1648 int nres;
1649 xfs_trans_t *tp;
1650
1651 tp = libxfs_trans_alloc(mp, 0);
1652 nres = XFS_REMOVE_SPACE_RES(mp);
1653 error = libxfs_trans_reserve(tp, nres, XFS_REMOVE_LOG_RES(mp), 0,
1654 XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT);
1655 if (error)
1656 res_failed(error);
1657 libxfs_trans_ijoin(tp, ip, 0);
1658 libxfs_trans_ihold(tp, ip);
1659 libxfs_da_bjoin(tp, bp);
1660 bzero(&args, sizeof(args));
1661 XFS_BMAP_INIT(&flist, &firstblock);
1662 args.dp = ip;
1663 args.trans = tp;
1664 args.firstblock = &firstblock;
1665 args.flist = &flist;
1666 args.whichfork = XFS_DATA_FORK;
1667 if (da_bno >= mp->m_dirleafblk && da_bno < mp->m_dirfreeblk)
1668 error = libxfs_da_shrink_inode(&args, da_bno, bp);
1669 else
1670 error = libxfs_dir2_shrink_inode(&args,
1671 XFS_DIR2_DA_TO_DB(mp, da_bno), bp);
1672 if (error)
1673 do_error("shrink_inode failed inode %llu block %u\n",
1674 ip->i_ino, da_bno);
1675 libxfs_bmap_finish(&tp, &flist, firstblock, &committed);
1676 libxfs_trans_commit(tp, 0, 0);
1677}
1678
1679/*
1680 * process a data block, also checks for .. entry
1681 * and corrects it to match what we think .. should be
1682 */
1683static void
1684longform_dir2_entry_check_data(
1685 xfs_mount_t *mp,
1686 xfs_inode_t *ip,
1687 int *num_illegal,
1688 int *need_dot,
1689 dir_stack_t *stack,
1690 ino_tree_node_t *current_irec,
1691 int current_ino_offset,
1692 xfs_dabuf_t **bpp,
1693 dir_hash_tab_t *hashtab,
1694 freetab_t **freetabp,
1695 xfs_dablk_t da_bno,
1696 int isblock)
1697{
1698 xfs_dir2_dataptr_t addr;
1699 xfs_dir2_leaf_entry_t *blp;
1700 xfs_dabuf_t *bp;
1701 xfs_dir2_block_tail_t *btp;
1702 int committed;
1703 xfs_dir2_data_t *d;
1704 xfs_dir2_db_t db;
1705 xfs_dir2_data_entry_t *dep;
1706 xfs_dir2_data_unused_t *dup;
1707 char *endptr;
1708 int error;
1709 xfs_fsblock_t firstblock;
1710 xfs_bmap_free_t flist;
1711 char fname[MAXNAMELEN + 1];
1712 freetab_t *freetab;
1713 int i;
1714 int ino_offset;
1715 ino_tree_node_t *irec;
1716 int junkit;
1717 int lastfree;
1718 int len;
1719 int nbad;
1720 int needlog;
1721 int needscan;
1722 xfs_ino_t parent;
1723 char *ptr;
1724 xfs_trans_t *tp;
1725 int wantmagic;
1726
1727 bp = *bpp;
1728 d = bp->data;
1729 ptr = (char *)d->u;
1730 nbad = 0;
1731 needscan = needlog = 0;
1732 freetab = *freetabp;
1733 if (isblock) {
1734 btp = XFS_DIR2_BLOCK_TAIL_P(mp, d);
1735 blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
1736 endptr = (char *)blp;
1737 if (endptr > (char *)btp)
1738 endptr = (char *)btp;
1739 wantmagic = XFS_DIR2_BLOCK_MAGIC;
1740 } else {
1741 endptr = (char *)d + mp->m_dirblksize;
1742 wantmagic = XFS_DIR2_DATA_MAGIC;
1743 }
1744 db = XFS_DIR2_DA_TO_DB(mp, da_bno);
1745 if (freetab->naents <= db) {
1746 struct freetab_ent e;
1747
1748 *freetabp = freetab = realloc(freetab, FREETAB_SIZE(db + 1));
1749 if (!freetab) {
1750 do_error(
1751 "realloc failed in longform_dir2_entry_check_data (%u bytes)\n",
1752 FREETAB_SIZE(db + 1));
1753 exit(1);
1754 }
1755 e.v = NULLDATAOFF;
1756 e.s = 0;
1757 for (i = freetab->naents; i < db; i++)
1758 freetab->ents[i] = e;
1759 freetab->naents = db + 1;
1760 }
1761 if (freetab->nents < db + 1)
1762 freetab->nents = db + 1;
1763 while (ptr < endptr) {
1764 dup = (xfs_dir2_data_unused_t *)ptr;
1765 if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
1766 if (ptr + INT_GET(dup->length, ARCH_CONVERT) > endptr || INT_GET(dup->length, ARCH_CONVERT) == 0 ||
1767 (INT_GET(dup->length, ARCH_CONVERT) & (XFS_DIR2_DATA_ALIGN - 1)))
1768 break;
1769 if (INT_GET(*XFS_DIR2_DATA_UNUSED_TAG_P_ARCH(dup, ARCH_CONVERT), ARCH_CONVERT) !=
1770 (char *)dup - (char *)d)
1771 break;
1772 ptr += INT_GET(dup->length, ARCH_CONVERT);
1773 if (ptr >= endptr)
1774 break;
1775 }
1776 dep = (xfs_dir2_data_entry_t *)ptr;
1777 if (ptr + XFS_DIR2_DATA_ENTSIZE(dep->namelen) > endptr)
1778 break;
1779 if (INT_GET(*XFS_DIR2_DATA_ENTRY_TAG_P(dep), ARCH_CONVERT) != (char *)dep - (char *)d)
1780 break;
1781 ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
1782 }
1783 if (ptr != endptr) {
1784 do_warn("corrupt block %u in directory inode %llu: ",
1785 da_bno, ip->i_ino);
1786 if (!no_modify) {
1787 do_warn("junking block\n");
1788 dir2_kill_block(mp, ip, da_bno, bp);
1789 } else {
1790 do_warn("would junk block\n");
1791 libxfs_da_brelse(NULL, bp);
1792 }
1793 freetab->ents[db].v = NULLDATAOFF;
1794 *bpp = NULL;
1795 return;
1796 }
1797 tp = libxfs_trans_alloc(mp, 0);
1798 error = libxfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0,
1799 XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT);
1800 if (error)
1801 res_failed(error);
1802 libxfs_trans_ijoin(tp, ip, 0);
1803 libxfs_trans_ihold(tp, ip);
1804 libxfs_da_bjoin(tp, bp);
1805 if (isblock)
1806 libxfs_da_bhold(tp, bp);
1807 XFS_BMAP_INIT(&flist, &firstblock);
1808 if (INT_GET(d->hdr.magic, ARCH_CONVERT) != wantmagic) {
1809 do_warn("bad directory block magic # %#x for directory inode "
1810 "%llu block %d: ",
1811 INT_GET(d->hdr.magic, ARCH_CONVERT), ip->i_ino, da_bno);
1812 if (!no_modify) {
1813 do_warn("fixing magic # to %#x\n", wantmagic);
1814 INT_SET(d->hdr.magic, ARCH_CONVERT, wantmagic);
1815 needlog = 1;
1816 } else
1817 do_warn("would fix magic # to %#x\n", wantmagic);
1818 }
1819 lastfree = 0;
1820 ptr = (char *)d->u;
1821 /*
1822 * look at each entry. reference inode pointed to by each
1823 * entry in the incore inode tree.
1824 * if not a directory, set reached flag, increment link count
1825 * if a directory and reached, mark entry as to be deleted.
1826 * if a directory, check to see if recorded parent
1827 * matches current inode #,
1828 * if so, then set reached flag, increment link count
1829 * of current and child dir inodes, push the child
1830 * directory inode onto the directory stack.
1831 * if current inode != parent, then mark entry to be deleted.
1832 */
1833 while (ptr < endptr) {
1834 dup = (xfs_dir2_data_unused_t *)ptr;
1835 if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
1836 if (lastfree) {
1837 do_warn("directory inode %llu block %u has "
1838 "consecutive free entries: ",
1839 ip->i_ino, da_bno);
1840 if (!no_modify) {
1841 do_warn("joining together\n");
1842 len = INT_GET(dup->length, ARCH_CONVERT);
1843 libxfs_dir2_data_use_free(tp, bp, dup,
1844 ptr - (char *)d, len, &needlog,
1845 &needscan);
1846 libxfs_dir2_data_make_free(tp, bp,
1847 ptr - (char *)d, len, &needlog,
1848 &needscan);
1849 } else
1850 do_warn("would join together\n");
1851 }
1852 ptr += INT_GET(dup->length, ARCH_CONVERT);
1853 lastfree = 1;
1854 continue;
1855 }
1856 addr = XFS_DIR2_DB_OFF_TO_DATAPTR(mp, db, ptr - (char *)d);
1857 dep = (xfs_dir2_data_entry_t *)ptr;
1858 ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
1859 lastfree = 0;
1860 dir_hash_add(hashtab,
1861 libxfs_da_hashname((char *)dep->name, dep->namelen),
1862 addr, dep->name[0] == '/');
1863 /*
1864 * skip bogus entries (leading '/'). they'll be deleted
1865 * later
1866 */
1867 if (dep->name[0] == '/') {
1868 nbad++;
1869 continue;
1870 }
1871 junkit = 0;
1872 bcopy(dep->name, fname, dep->namelen);
1873 fname[dep->namelen] = '\0';
1874 ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) != NULLFSINO);
1875 /*
1876 * skip the '..' entry since it's checked when the
1877 * directory is reached by something else. if it never
1878 * gets reached, it'll be moved to the orphanage and we'll
1879 * take care of it then.
1880 */
1881 if (dep->namelen == 2 && dep->name[0] == '.' &&
1882 dep->name[1] == '.')
1883 continue;
1884 ASSERT(no_modify || !verify_inum(mp, INT_GET(dep->inumber, ARCH_CONVERT)));
1885 /*
1886 * special case the . entry. we know there's only one
1887 * '.' and only '.' points to itself because bogus entries
1888 * got trashed in phase 3 if there were > 1.
1889 * bump up link count for '.' but don't set reached
1890 * until we're actually reached by another directory
1891 * '..' is already accounted for or will be taken care
1892 * of when directory is moved to orphanage.
1893 */
1894 if (ip->i_ino == INT_GET(dep->inumber, ARCH_CONVERT)) {
1895 ASSERT(dep->name[0] == '.' && dep->namelen == 1);
1896 add_inode_ref(current_irec, current_ino_offset);
1897 *need_dot = 0;
1898 continue;
1899 }
1900 /*
1901 * special case the "lost+found" entry if pointing
1902 * to where we think lost+found should be. if that's
1903 * the case, that's the one we created in phase 6.
1904 * just skip it. no need to process it and it's ..
1905 * link is already accounted for.
1906 */
1907 if (INT_GET(dep->inumber, ARCH_CONVERT) == orphanage_ino &&
1908 strcmp(fname, ORPHANAGE) == 0)
1909 continue;
1910 /*
1911 * skip entries with bogus inumbers if we're in no modify mode
1912 */
1913 if (no_modify && verify_inum(mp, INT_GET(dep->inumber, ARCH_CONVERT)))
1914 continue;
1915 /*
1916 * ok, now handle the rest of the cases besides '.' and '..'
1917 */
1918 irec = find_inode_rec(XFS_INO_TO_AGNO(mp, INT_GET(dep->inumber, ARCH_CONVERT)),
1919 XFS_INO_TO_AGINO(mp, INT_GET(dep->inumber, ARCH_CONVERT)));
1920 if (irec == NULL) {
1921 nbad++;
1922 do_warn("entry \"%s\" in directory inode %llu points "
1923 "to non-existent inode, ",
1924 fname, ip->i_ino);
1925 if (!no_modify) {
1926 dep->name[0] = '/';
1927 libxfs_dir2_data_log_entry(tp, bp, dep);
1928 do_warn("marking entry to be junked\n");
1929 } else {
1930 do_warn("would junk entry\n");
1931 }
1932 continue;
1933 }
1934 ino_offset =
1935 XFS_INO_TO_AGINO(mp, INT_GET(dep->inumber, ARCH_CONVERT)) - irec->ino_startnum;
1936 /*
1937 * if it's a free inode, blow out the entry.
1938 * by now, any inode that we think is free
1939 * really is free.
1940 */
1941 if (is_inode_free(irec, ino_offset)) {
1942 /*
1943 * don't complain if this entry points to the old
1944 * and now-free lost+found inode
1945 */
1946 if (verbose || no_modify ||
1947 INT_GET(dep->inumber, ARCH_CONVERT) != old_orphanage_ino)
1948 do_warn("entry \"%s\" in directory inode %llu "
1949 "points to free inode %llu",
1950 fname, ip->i_ino, INT_GET(dep->inumber, ARCH_CONVERT));
1951 nbad++;
1952 if (!no_modify) {
1953 if (verbose ||
1954 INT_GET(dep->inumber, ARCH_CONVERT) != old_orphanage_ino)
1955 do_warn(", marking entry to be "
1956 "junked\n");
1957 else
1958 do_warn("\n");
1959 dep->name[0] = '/';
1960 libxfs_dir2_data_log_entry(tp, bp, dep);
1961 } else {
1962 do_warn(", would junk entry\n");
1963 }
1964 continue;
1965 }
1966 /*
1967 * check easy case first, regular inode, just bump
1968 * the link count and continue
1969 */
1970 if (!inode_isadir(irec, ino_offset)) {
1971 add_inode_reached(irec, ino_offset);
1972 continue;
1973 }
1974 parent = get_inode_parent(irec, ino_offset);
1975 ASSERT(parent != 0);
1976 /*
1977 * bump up the link counts in parent and child
1978 * directory but if the link doesn't agree with
1979 * the .. in the child, blow out the entry.
1980 * if the directory has already been reached,
1981 * blow away the entry also.
1982 */
1983 if (is_inode_reached(irec, ino_offset)) {
1984 junkit = 1;
1985 do_warn("entry \"%s\" in dir %llu points to an already "
1986 "connected directory inode %llu,\n", fname,
1987 ip->i_ino, INT_GET(dep->inumber, ARCH_CONVERT));
1988 } else if (parent == ip->i_ino) {
1989 add_inode_reached(irec, ino_offset);
1990 add_inode_ref(current_irec, current_ino_offset);
1991 if (!is_inode_refchecked(INT_GET(dep->inumber, ARCH_CONVERT), irec,
1992 ino_offset))
1993 push_dir(stack, INT_GET(dep->inumber, ARCH_CONVERT));
1994 } else {
1995 junkit = 1;
1996 do_warn("entry \"%s\" in directory inode %llu not "
1997 "consistent with .. value (%llu) in ino "
1998 "%llu,\n",
1999 fname, ip->i_ino, parent, INT_GET(dep->inumber, ARCH_CONVERT));
2000 }
2001 if (junkit) {
2002 junkit = 0;
2003 nbad++;
2004 if (!no_modify) {
2005 dep->name[0] = '/';
2006 libxfs_dir2_data_log_entry(tp, bp, dep);
2007 if (verbose ||
2008 INT_GET(dep->inumber, ARCH_CONVERT) != old_orphanage_ino)
2009 do_warn("\twill clear entry \"%s\"\n",
2010 fname);
2011 } else {
2012 do_warn("\twould clear entry \"%s\"\n", fname);
2013 }
2014 }
2015 }
2016 *num_illegal += nbad;
2017 if (needscan)
2018 libxfs_dir2_data_freescan(mp, d, &needlog, NULL);
2019 if (needlog)
2020 libxfs_dir2_data_log_header(tp, bp);
2021 libxfs_bmap_finish(&tp, &flist, firstblock, &committed);
2022 libxfs_trans_commit(tp, 0, 0);
2023 freetab->ents[db].v = INT_GET(d->hdr.bestfree[0].length, ARCH_CONVERT);
2024 freetab->ents[db].s = 0;
2025}
2026
2027/*
2028 * Check contents of leaf-form block.
2029 */
2030int
2031longform_dir2_check_leaf(
2032 xfs_mount_t *mp,
2033 xfs_inode_t *ip,
2034 dir_hash_tab_t *hashtab,
2035 freetab_t *freetab)
2036{
2037 int badtail;
2038 xfs_dir2_data_off_t *bestsp;
2039 xfs_dabuf_t *bp;
2040 xfs_dablk_t da_bno;
2041 int i;
2042 xfs_dir2_leaf_t *leaf;
2043 xfs_dir2_leaf_tail_t *ltp;
2044 int seeval;
2045
2046 da_bno = mp->m_dirleafblk;
2047 if (libxfs_da_read_bufr(NULL, ip, da_bno, -1, &bp, XFS_DATA_FORK)) {
2048 do_error("can't read block %u for directory inode %llu\n",
2049 da_bno, ip->i_ino);
2050 /* NOTREACHED */
2051 }
2052 leaf = bp->data;
2053 ltp = XFS_DIR2_LEAF_TAIL_P(mp, leaf);
2054 bestsp = XFS_DIR2_LEAF_BESTS_P_ARCH(ltp, ARCH_CONVERT);
2055 if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR2_LEAF1_MAGIC ||
2056 INT_GET(leaf->hdr.info.forw, ARCH_CONVERT) || INT_GET(leaf->hdr.info.back, ARCH_CONVERT) ||
2057 INT_GET(leaf->hdr.count, ARCH_CONVERT) < INT_GET(leaf->hdr.stale, ARCH_CONVERT) ||
2058 INT_GET(leaf->hdr.count, ARCH_CONVERT) > XFS_DIR2_MAX_LEAF_ENTS(mp) ||
2059 (char *)&leaf->ents[INT_GET(leaf->hdr.count, ARCH_CONVERT)] > (char *)bestsp) {
2060 do_warn("leaf block %u for directory inode %llu bad header\n",
2061 da_bno, ip->i_ino);
2062 libxfs_da_brelse(NULL, bp);
2063 return 1;
2064 }
2065 seeval = dir_hash_see_all(hashtab, leaf->ents, INT_GET(leaf->hdr.count, ARCH_CONVERT),
2066 INT_GET(leaf->hdr.stale, ARCH_CONVERT));
2067 if (dir_hash_check(hashtab, ip, seeval)) {
2068 libxfs_da_brelse(NULL, bp);
2069 return 1;
2070 }
2071 badtail = freetab->nents != INT_GET(ltp->bestcount, ARCH_CONVERT);
2072 for (i = 0; !badtail && i < INT_GET(ltp->bestcount, ARCH_CONVERT); i++) {
2073 freetab->ents[i].s = 1;
2074 badtail = freetab->ents[i].v != INT_GET(bestsp[i], ARCH_CONVERT);
2075 }
2076 if (badtail) {
2077 do_warn("leaf block %u for directory inode %llu bad tail\n",
2078 da_bno, ip->i_ino);
2079 libxfs_da_brelse(NULL, bp);
2080 return 1;
2081 }
2082 libxfs_da_brelse(NULL, bp);
2083 return 0;
2084}
2085
2086/*
2087 * Check contents of the node blocks (leaves)
2088 * Looks for matching hash values for the data entries.
2089 */
2090int
2091longform_dir2_check_node(
2092 xfs_mount_t *mp,
2093 xfs_inode_t *ip,
2094 dir_hash_tab_t *hashtab,
2095 freetab_t *freetab)
2096{
2097 xfs_dabuf_t *bp;
2098 xfs_dablk_t da_bno;
2099 xfs_dir2_db_t fdb;
2100 xfs_dir2_free_t *free;
2101 int i;
2102 xfs_dir2_leaf_t *leaf;
2103 xfs_fileoff_t next_da_bno;
2104 int seeval = 0;
2105 int used;
2106
2107 for (da_bno = mp->m_dirleafblk, next_da_bno = 0;
2108 next_da_bno != NULLFILEOFF && da_bno < mp->m_dirfreeblk;
2109 da_bno = (xfs_dablk_t)next_da_bno) {
2110 next_da_bno = da_bno + mp->m_dirblkfsbs - 1;
2111 if (libxfs_bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK))
2112 break;
2113 if (libxfs_da_read_bufr(NULL, ip, da_bno, -1, &bp,
2114 XFS_DATA_FORK)) {
2115 do_error("can't read block %u for directory inode "
2116 "%llu\n",
2117 da_bno, ip->i_ino);
2118 /* NOTREACHED */
2119 }
2120 leaf = bp->data;
2121 if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) != XFS_DIR2_LEAFN_MAGIC) {
2122 if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) {
2123 libxfs_da_brelse(NULL, bp);
2124 continue;
2125 }
2126 do_warn("unknown magic number %#x for block %u in "
2127 "directory inode %llu\n",
2128 INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), da_bno, ip->i_ino);
2129 libxfs_da_brelse(NULL, bp);
2130 return 1;
2131 }
2132 if (INT_GET(leaf->hdr.count, ARCH_CONVERT) < INT_GET(leaf->hdr.stale, ARCH_CONVERT) ||
2133 INT_GET(leaf->hdr.count, ARCH_CONVERT) > XFS_DIR2_MAX_LEAF_ENTS(mp)) {
2134 do_warn("leaf block %u for directory inode %llu bad "
2135 "header\n",
2136 da_bno, ip->i_ino);
2137 libxfs_da_brelse(NULL, bp);
2138 return 1;
2139 }
2140 seeval = dir_hash_see_all(hashtab, leaf->ents, INT_GET(leaf->hdr.count, ARCH_CONVERT),
2141 INT_GET(leaf->hdr.stale, ARCH_CONVERT));
2142 libxfs_da_brelse(NULL, bp);
2143 if (seeval != DIR_HASH_CK_OK)
2144 return 1;
2145 }
2146 if (dir_hash_check(hashtab, ip, seeval))
2147 return 1;
2148 for (da_bno = mp->m_dirfreeblk, next_da_bno = 0;
2149 next_da_bno != NULLFILEOFF;
2150 da_bno = (xfs_dablk_t)next_da_bno) {
2151 next_da_bno = da_bno + mp->m_dirblkfsbs - 1;
2152 if (libxfs_bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK))
2153 break;
2154 if (libxfs_da_read_bufr(NULL, ip, da_bno, -1, &bp,
2155 XFS_DATA_FORK)) {
2156 do_error("can't read block %u for directory inode "
2157 "%llu\n",
2158 da_bno, ip->i_ino);
2159 /* NOTREACHED */
2160 }
2161 free = bp->data;
2162 fdb = XFS_DIR2_DA_TO_DB(mp, da_bno);
2163 if (INT_GET(free->hdr.magic, ARCH_CONVERT) != XFS_DIR2_FREE_MAGIC ||
2164 INT_GET(free->hdr.firstdb, ARCH_CONVERT) !=
2165 (fdb - XFS_DIR2_FREE_FIRSTDB(mp)) *
2166 XFS_DIR2_MAX_FREE_BESTS(mp) ||
2167 INT_GET(free->hdr.nvalid, ARCH_CONVERT) < INT_GET(free->hdr.nused, ARCH_CONVERT)) {
2168 do_warn("free block %u for directory inode %llu bad "
2169 "header\n",
2170 da_bno, ip->i_ino);
2171 libxfs_da_brelse(NULL, bp);
2172 return 1;
2173 }
2174 for (i = used = 0; i < INT_GET(free->hdr.nvalid, ARCH_CONVERT); i++) {
2175 if (i + INT_GET(free->hdr.firstdb, ARCH_CONVERT) >= freetab->nents ||
2176 freetab->ents[i + INT_GET(free->hdr.firstdb, ARCH_CONVERT)].v !=
2177 INT_GET(free->bests[i], ARCH_CONVERT)) {
2178 do_warn("free block %u entry %i for directory "
2179 "ino %llu bad\n",
2180 da_bno, i, ip->i_ino);
2181 libxfs_da_brelse(NULL, bp);
2182 return 1;
2183 }
2184 used += INT_GET(free->bests[i], ARCH_CONVERT) != NULLDATAOFF;
2185 freetab->ents[i + INT_GET(free->hdr.firstdb, ARCH_CONVERT)].s = 1;
2186 }
2187 if (used != INT_GET(free->hdr.nused, ARCH_CONVERT)) {
2188 do_warn("free block %u for directory inode %llu bad "
2189 "nused\n",
2190 da_bno, ip->i_ino);
2191 libxfs_da_brelse(NULL, bp);
2192 return 1;
2193 }
2194 libxfs_da_brelse(NULL, bp);
2195 }
2196 for (i = 0; i < freetab->nents; i++) {
2197 if (freetab->ents[i].s == 0) {
2198 do_warn("missing freetab entry %u for directory inode "
2199 "%llu\n",
2200 i, ip->i_ino);
2201 return 1;
2202 }
2203 }
2204 return 0;
2205}
2206
2207/*
2208 * Rebuild a directory: set up.
2209 * Turn it into a node-format directory with no contents in the
2210 * upper area. Also has correct freespace blocks.
2211 */
2212void
2213longform_dir2_rebuild_setup(
2214 xfs_mount_t *mp,
2215 xfs_ino_t ino,
2216 xfs_inode_t *ip,
2217 freetab_t *freetab)
2218{
2219 xfs_da_args_t args;
2220 int committed;
2221 xfs_dir2_data_t *data;
2222 xfs_dabuf_t *dbp;
2223 int error;
2224 xfs_dir2_db_t fbno;
2225 xfs_dabuf_t *fbp;
2226 xfs_fsblock_t firstblock;
2227 xfs_bmap_free_t flist;
2228 xfs_dir2_free_t *free;
2229 int i;
2230 int j;
2231 xfs_dablk_t lblkno;
2232 xfs_dabuf_t *lbp;
2233 xfs_dir2_leaf_t *leaf;
2234 int nres;
2235 xfs_trans_t *tp;
2236
2237 tp = libxfs_trans_alloc(mp, 0);
2238 nres = XFS_DAENTER_SPACE_RES(mp, XFS_DATA_FORK);
2239 error = libxfs_trans_reserve(tp,
2240 nres, XFS_CREATE_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES,
2241 XFS_CREATE_LOG_COUNT);
2242 if (error)
2243 res_failed(error);
2244 libxfs_trans_ijoin(tp, ip, 0);
2245 libxfs_trans_ihold(tp, ip);
2246 XFS_BMAP_INIT(&flist, &firstblock);
2247 if (libxfs_da_read_buf(tp, ip, mp->m_dirdatablk, -2, &dbp,
2248 XFS_DATA_FORK)) {
2249 do_error("can't read block %u for directory inode %llu\n",
2250 mp->m_dirdatablk, ino);
2251 /* NOTREACHED */
2252 }
2253 if (dbp && (data = dbp->data)->hdr.magic == XFS_DIR2_BLOCK_MAGIC) {
2254 xfs_dir2_block_t *block;
2255 xfs_dir2_leaf_entry_t *blp;
2256 xfs_dir2_block_tail_t *btp;
2257 int needlog;
2258 int needscan;
2259
2260 INT_SET(data->hdr.magic, ARCH_CONVERT, XFS_DIR2_DATA_MAGIC);
2261 block = (xfs_dir2_block_t *)data;
2262 btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
2263 blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
2264 needlog = needscan = 0;
2265 libxfs_dir2_data_make_free(tp, dbp, (char *)blp - (char *)block,
2266 (char *)block + mp->m_dirblksize - (char *)blp,
2267 &needlog, &needscan);
2268 if (needscan)
2269 libxfs_dir2_data_freescan(mp, data, &needlog, NULL);
2270 libxfs_da_log_buf(tp, dbp, 0, mp->m_dirblksize - 1);
2271 }
2272 bzero(&args, sizeof(args));
2273 args.trans = tp;
2274 args.dp = ip;
2275 args.whichfork = XFS_DATA_FORK;
2276 args.firstblock = &firstblock;
2277 args.flist = &flist;
2278 args.total = nres;
2279 if ((error = libxfs_da_grow_inode(&args, &lblkno)) ||
2280 (error = libxfs_da_get_buf(tp, ip, lblkno, -1, &lbp, XFS_DATA_FORK))) {
2281 do_error("can't add btree block to directory inode %llu\n",
2282 ino);
2283 /* NOTREACHED */
2284 }
2285 leaf = lbp->data;
2286 bzero(leaf, mp->m_dirblksize);
2287 INT_SET(leaf->hdr.info.magic, ARCH_CONVERT, XFS_DIR2_LEAFN_MAGIC);
2288 libxfs_da_log_buf(tp, lbp, 0, mp->m_dirblksize - 1);
2289 libxfs_bmap_finish(&tp, &flist, firstblock, &committed);
2290 libxfs_trans_commit(tp, 0, 0);
2291
2292 for (i = 0; i < freetab->nents; i += XFS_DIR2_MAX_FREE_BESTS(mp)) {
2293 tp = libxfs_trans_alloc(mp, 0);
2294 nres = XFS_DAENTER_SPACE_RES(mp, XFS_DATA_FORK);
2295 error = libxfs_trans_reserve(tp,
2296 nres, XFS_CREATE_LOG_RES(mp), 0, XFS_TRANS_PERM_LOG_RES,
2297 XFS_CREATE_LOG_COUNT);
2298 if (error)
2299 res_failed(error);
2300 libxfs_trans_ijoin(tp, ip, 0);
2301 libxfs_trans_ihold(tp, ip);
2302 XFS_BMAP_INIT(&flist, &firstblock);
2303 bzero(&args, sizeof(args));
2304 args.trans = tp;
2305 args.dp = ip;
2306 args.whichfork = XFS_DATA_FORK;
2307 args.firstblock = &firstblock;
2308 args.flist = &flist;
2309 args.total = nres;
2310 if ((error = libxfs_dir2_grow_inode(&args, XFS_DIR2_FREE_SPACE,
2311 &fbno)) ||
2312 (error = libxfs_da_get_buf(tp, ip, XFS_DIR2_DB_TO_DA(mp, fbno),
2313 -1, &fbp, XFS_DATA_FORK))) {
2314 do_error("can't add free block to directory inode "
2315 "%llu\n",
2316 ino);
2317 /* NOTREACHED */
2318 }
2319 free = fbp->data;
2320 bzero(free, mp->m_dirblksize);
2321 INT_SET(free->hdr.magic, ARCH_CONVERT, XFS_DIR2_FREE_MAGIC);
2322 INT_SET(free->hdr.firstdb, ARCH_CONVERT, i);
2323 INT_SET(free->hdr.nvalid, ARCH_CONVERT, XFS_DIR2_MAX_FREE_BESTS(mp));
2324 if (i + INT_GET(free->hdr.nvalid, ARCH_CONVERT) > freetab->nents)
2325 INT_SET(free->hdr.nvalid, ARCH_CONVERT, freetab->nents - i);
2326 for (j = 0; j < INT_GET(free->hdr.nvalid, ARCH_CONVERT); j++) {
2327 INT_SET(free->bests[j], ARCH_CONVERT, freetab->ents[i + j].v);
2328 if (INT_GET(free->bests[j], ARCH_CONVERT) != NULLDATAOFF)
2329 INT_MOD(free->hdr.nused, ARCH_CONVERT, +1);
2330 }
2331 libxfs_da_log_buf(tp, fbp, 0, mp->m_dirblksize - 1);
2332 libxfs_bmap_finish(&tp, &flist, firstblock, &committed);
2333 libxfs_trans_commit(tp, 0, 0);
2334 }
2335}
2336
2337/*
2338 * Rebuild the entries from a single data block.
2339 */
2340void
2341longform_dir2_rebuild_data(
2342 xfs_mount_t *mp,
2343 xfs_ino_t ino,
2344 xfs_inode_t *ip,
2345 xfs_dablk_t da_bno)
2346{
2347 xfs_dabuf_t *bp;
2348 xfs_dir2_block_tail_t *btp;
2349 int committed;
2350 xfs_dir2_data_t *data;
2351 xfs_dir2_db_t dbno;
2352 xfs_dir2_data_entry_t *dep;
2353 xfs_dir2_data_unused_t *dup;
2354 char *endptr;
2355 int error;
2356 xfs_dir2_free_t *fblock;
2357 xfs_dabuf_t *fbp;
2358 xfs_dir2_db_t fdb;
2359 int fi;
2360 xfs_fsblock_t firstblock;
2361 xfs_bmap_free_t flist;
2362 int needlog;
2363 int needscan;
2364 int nres;
2365 char *ptr;
2366 xfs_trans_t *tp;
2367
2368 if (libxfs_da_read_buf(NULL, ip, da_bno, da_bno == 0 ? -2 : -1, &bp,
2369 XFS_DATA_FORK)) {
2370 do_error("can't read block %u for directory inode %llu\n",
2371 da_bno, ino);
2372 /* NOTREACHED */
2373 }
2374 if (da_bno == 0 && bp == NULL)
2375 /*
2376 * The block was punched out.
2377 */
2378 return;
2379 ASSERT(bp);
2380 dbno = XFS_DIR2_DA_TO_DB(mp, da_bno);
2381 fdb = XFS_DIR2_DB_TO_FDB(mp, dbno);
2382 if (libxfs_da_read_buf(NULL, ip, XFS_DIR2_DB_TO_DA(mp, fdb), -1, &fbp,
2383 XFS_DATA_FORK)) {
2384 do_error("can't read block %u for directory inode %llu\n",
2385 XFS_DIR2_DB_TO_DA(mp, fdb), ino);
2386 /* NOTREACHED */
2387 }
2388 data = malloc(mp->m_dirblksize);
2389 if (!data) {
2390 do_error(
2391 "malloc failed in longform_dir2_rebuild_data (%u bytes)\n",
2392 mp->m_dirblksize);
2393 exit(1);
2394 }
2395 bcopy(bp->data, data, mp->m_dirblksize);
2396 ptr = (char *)data->u;
2397 if (INT_GET(data->hdr.magic, ARCH_CONVERT) == XFS_DIR2_BLOCK_MAGIC) {
2398 btp = XFS_DIR2_BLOCK_TAIL_P(mp, (xfs_dir2_block_t *)data);
2399 endptr = (char *)XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
2400 } else
2401 endptr = (char *)data + mp->m_dirblksize;
2402 fblock = fbp->data;
2403 fi = XFS_DIR2_DB_TO_FDINDEX(mp, dbno);
2404 tp = libxfs_trans_alloc(mp, 0);
2405 error = libxfs_trans_reserve(tp, 0, XFS_CREATE_LOG_RES(mp), 0,
2406 XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT);
2407 if (error)
2408 res_failed(error);
2409 libxfs_trans_ijoin(tp, ip, 0);
2410 libxfs_trans_ihold(tp, ip);
2411 libxfs_da_bjoin(tp, bp);
2412 libxfs_da_bhold(tp, bp);
2413 libxfs_da_bjoin(tp, fbp);
2414 libxfs_da_bhold(tp, fbp);
2415 XFS_BMAP_INIT(&flist, &firstblock);
2416 needlog = needscan = 0;
2417 bzero(((xfs_dir2_data_t *)(bp->data))->hdr.bestfree,
2418 sizeof(data->hdr.bestfree));
2419 libxfs_dir2_data_make_free(tp, bp, (xfs_dir2_data_aoff_t)sizeof(data->hdr),
2420 mp->m_dirblksize - sizeof(data->hdr), &needlog, &needscan);
2421 ASSERT(needscan == 0);
2422 libxfs_dir2_data_log_header(tp, bp);
2423 INT_SET(fblock->bests[fi], ARCH_CONVERT,
2424 INT_GET(((xfs_dir2_data_t *)(bp->data))->hdr.bestfree[0].length, ARCH_CONVERT));
2425 libxfs_dir2_free_log_bests(tp, fbp, fi, fi);
2426 libxfs_bmap_finish(&tp, &flist, firstblock, &committed);
2427 libxfs_trans_commit(tp, 0, 0);
2428
2429 while (ptr < endptr) {
2430 dup = (xfs_dir2_data_unused_t *)ptr;
2431 if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
2432 ptr += INT_GET(dup->length, ARCH_CONVERT);
2433 continue;
2434 }
2435 dep = (xfs_dir2_data_entry_t *)ptr;
2436 ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
2437 if (dep->name[0] == '/')
2438 continue;
2439 tp = libxfs_trans_alloc(mp, 0);
2440 nres = XFS_CREATE_SPACE_RES(mp, dep->namelen);
2441 error = libxfs_trans_reserve(tp, nres, XFS_CREATE_LOG_RES(mp), 0,
2442 XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT);
2443 if (error)
2444 res_failed(error);
2445 libxfs_trans_ijoin(tp, ip, 0);
2446 libxfs_trans_ihold(tp, ip);
2447 libxfs_da_bjoin(tp, bp);
2448 libxfs_da_bhold(tp, bp);
2449 libxfs_da_bjoin(tp, fbp);
2450 libxfs_da_bhold(tp, fbp);
2451 XFS_BMAP_INIT(&flist, &firstblock);
2452 error = dir_createname(mp, tp, ip, (char *)dep->name,
2453 dep->namelen, INT_GET(dep->inumber, ARCH_CONVERT),
2454 &firstblock, &flist, nres);
2455 ASSERT(error == 0);
2456 libxfs_bmap_finish(&tp, &flist, firstblock, &committed);
2457 libxfs_trans_commit(tp, 0, 0);
2458 }
2459 libxfs_da_brelse(NULL, bp);
2460 libxfs_da_brelse(NULL, fbp);
2461 free(data);
2462}
2463
2464/*
2465 * Finish the rebuild of a directory.
2466 * Stuff / in and then remove it, this forces the directory to end
2467 * up in the right format.
2468 */
2469void
2470longform_dir2_rebuild_finish(
2471 xfs_mount_t *mp,
2472 xfs_ino_t ino,
2473 xfs_inode_t *ip)
2474{
2475 int committed;
2476 int error;
2477 xfs_fsblock_t firstblock;
2478 xfs_bmap_free_t flist;
2479 int nres;
2480 xfs_trans_t *tp;
2481
2482 tp = libxfs_trans_alloc(mp, 0);
2483 nres = XFS_CREATE_SPACE_RES(mp, 1);
2484 error = libxfs_trans_reserve(tp, nres, XFS_CREATE_LOG_RES(mp), 0,
2485 XFS_TRANS_PERM_LOG_RES, XFS_CREATE_LOG_COUNT);
2486 if (error)
2487 res_failed(error);
2488 libxfs_trans_ijoin(tp, ip, 0);
2489 libxfs_trans_ihold(tp, ip);
2490 XFS_BMAP_INIT(&flist, &firstblock);
2491 error = dir_createname(mp, tp, ip, "/", 1, ino,
2492 &firstblock, &flist, nres);
2493 ASSERT(error == 0);
2494 libxfs_bmap_finish(&tp, &flist, firstblock, &committed);
2495 libxfs_trans_commit(tp, 0, 0);
2496
2497 /* could kill trailing empty data blocks here */
2498
2499 tp = libxfs_trans_alloc(mp, 0);
2500 nres = XFS_REMOVE_SPACE_RES(mp);
2501 error = libxfs_trans_reserve(tp, nres, XFS_REMOVE_LOG_RES(mp), 0,
2502 XFS_TRANS_PERM_LOG_RES, XFS_REMOVE_LOG_COUNT);
2503 if (error)
2504 res_failed(error);
2505 libxfs_trans_ijoin(tp, ip, 0);
2506 libxfs_trans_ihold(tp, ip);
2507 XFS_BMAP_INIT(&flist, &firstblock);
2508 error = dir_removename(mp, tp, ip, "/", 1, ino,
2509 &firstblock, &flist, nres);
2510 ASSERT(error == 0);
2511 libxfs_bmap_finish(&tp, &flist, firstblock, &committed);
2512 libxfs_trans_commit(tp, 0, 0);
2513}
2514
2515/*
2516 * Rebuild a directory.
2517 * Remove all the non-data blocks.
2518 * Re-initialize to (empty) node form.
2519 * Loop over the data blocks reinserting each entry.
2520 * Force the directory into the right format.
2521 */
2522void
2523longform_dir2_rebuild(
2524 xfs_mount_t *mp,
2525 xfs_ino_t ino,
2526 xfs_inode_t *ip,
2527 int *num_illegal,
2528 freetab_t *freetab,
2529 int isblock)
2530{
2531 xfs_dabuf_t *bp;
2532 xfs_dablk_t da_bno;
2533 xfs_fileoff_t next_da_bno;
2534
2535 do_warn("rebuilding directory inode %llu\n", ino);
2536 for (da_bno = mp->m_dirleafblk, next_da_bno = isblock ? NULLFILEOFF : 0;
2537 next_da_bno != NULLFILEOFF;
2538 da_bno = (xfs_dablk_t)next_da_bno) {
2539 next_da_bno = da_bno + mp->m_dirblkfsbs - 1;
2540 if (libxfs_bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK))
2541 break;
2542 if (libxfs_da_get_buf(NULL, ip, da_bno, -1, &bp, XFS_DATA_FORK)) {
2543 do_error("can't get block %u for directory inode "
2544 "%llu\n",
2545 da_bno, ino);
2546 /* NOTREACHED */
2547 }
2548 dir2_kill_block(mp, ip, da_bno, bp);
2549 }
2550 longform_dir2_rebuild_setup(mp, ino, ip, freetab);
2551 for (da_bno = mp->m_dirdatablk, next_da_bno = 0;
2552 da_bno < mp->m_dirleafblk && next_da_bno != NULLFILEOFF;
2553 da_bno = (xfs_dablk_t)next_da_bno) {
2554 next_da_bno = da_bno + mp->m_dirblkfsbs - 1;
2555 if (libxfs_bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK))
2556 break;
2557 longform_dir2_rebuild_data(mp, ino, ip, da_bno);
2558 }
2559 longform_dir2_rebuild_finish(mp, ino, ip);
2560 *num_illegal = 0;
2561}
2562
2563/*
2564 * succeeds or dies, inode never gets dirtied since all changes
2565 * happen in file blocks. the inode size and other core info
2566 * is already correct, it's just the leaf entries that get altered.
2567 * XXX above comment is wrong for v2 - need to see why it matters
2568 */
2569void
2570longform_dir2_entry_check(xfs_mount_t *mp,
2571 xfs_ino_t ino,
2572 xfs_inode_t *ip,
2573 int *num_illegal,
2574 int *need_dot,
2575 dir_stack_t *stack,
2576 ino_tree_node_t *irec,
2577 int ino_offset)
2578{
2579 xfs_dir2_block_t *block;
2580 xfs_dir2_leaf_entry_t *blp;
2581 xfs_dabuf_t *bp;
2582 xfs_dir2_block_tail_t *btp;
2583 xfs_dablk_t da_bno;
2584 freetab_t *freetab;
2585 dir_hash_tab_t *hashtab;
2586 int i;
2587 int isblock;
2588 int isleaf;
2589 xfs_fileoff_t next_da_bno;
2590 int seeval;
2591 int fixit;
2592
2593 *need_dot = 1;
2594 freetab = malloc(FREETAB_SIZE(ip->i_d.di_size / mp->m_dirblksize));
2595 if (!freetab) {
2596 do_error(
2597 "malloc failed in longform_dir2_entry_check (%u bytes)\n",
2598 FREETAB_SIZE(ip->i_d.di_size / mp->m_dirblksize));
2599 exit(1);
2600 }
2601 freetab->naents = ip->i_d.di_size / mp->m_dirblksize;
2602 freetab->nents = 0;
2603 for (i = 0; i < freetab->naents; i++) {
2604 freetab->ents[i].v = NULLDATAOFF;
2605 freetab->ents[i].s = 0;
2606 }
2607 libxfs_dir2_isblock(NULL, ip, &isblock);
2608 libxfs_dir2_isleaf(NULL, ip, &isleaf);
2609 hashtab = dir_hash_init(ip->i_d.di_size);
2610 for (da_bno = 0, next_da_bno = 0;
2611 next_da_bno != NULLFILEOFF && da_bno < mp->m_dirleafblk;
2612 da_bno = (xfs_dablk_t)next_da_bno) {
2613 next_da_bno = da_bno + mp->m_dirblkfsbs - 1;
2614 if (libxfs_bmap_next_offset(NULL, ip, &next_da_bno, XFS_DATA_FORK))
2615 break;
2616 if (libxfs_da_read_bufr(NULL, ip, da_bno, -1, &bp,
2617 XFS_DATA_FORK)) {
2618 do_error("can't read block %u for directory inode "
2619 "%llu\n",
2620 da_bno, ino);
2621 /* NOTREACHED */
2622 }
2623 longform_dir2_entry_check_data(mp, ip, num_illegal, need_dot,
2624 stack, irec, ino_offset, &bp, hashtab, &freetab, da_bno,
2625 isblock);
2626 /* it releases the buffer unless isblock is set */
2627 }
2628 fixit = (*num_illegal != 0) || dir2_is_badino(ino);
2629 if (isblock) {
2630 ASSERT(bp);
2631 block = bp->data;
2632 btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
2633 blp = XFS_DIR2_BLOCK_LEAF_P_ARCH(btp, ARCH_CONVERT);
2634 seeval = dir_hash_see_all(hashtab, blp, INT_GET(btp->count, ARCH_CONVERT), INT_GET(btp->stale, ARCH_CONVERT));
2635 if (dir_hash_check(hashtab, ip, seeval))
2636 fixit |= 1;
2637 libxfs_da_brelse(NULL, bp);
2638 } else if (isleaf) {
2639 fixit |= longform_dir2_check_leaf(mp, ip, hashtab, freetab);
2640 } else {
2641 fixit |= longform_dir2_check_node(mp, ip, hashtab, freetab);
2642 }
2643 dir_hash_done(hashtab);
2644 if (!no_modify && fixit)
2645 longform_dir2_rebuild(mp, ino, ip, num_illegal, freetab,
2646 isblock);
2647 free(freetab);
2648}
2649
2650/*
2651 * shortform directory processing routines -- entry verification and
2652 * bad entry deletion (pruning).
2653 */
2654void
2655shortform_dir_entry_check(xfs_mount_t *mp,
2656 xfs_ino_t ino,
2657 xfs_inode_t *ip,
2658 int *ino_dirty,
2659 dir_stack_t *stack,
2660 ino_tree_node_t *current_irec,
2661 int current_ino_offset)
2662{
2663 xfs_ino_t lino;
2664 xfs_ino_t parent;
2665 xfs_dir_shortform_t *sf;
2666 xfs_dir_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe;
2667 xfs_ifork_t *ifp;
2668 ino_tree_node_t *irec;
2669 int max_size;
2670 int ino_offset;
2671 int i;
2672 int junkit;
2673 int tmp_len;
2674 int tmp_elen;
2675 int bad_sfnamelen;
2676 int namelen;
2677 int bytes_deleted;
2678 char fname[MAXNAMELEN + 1];
2679
2680 ifp = &ip->i_df;
2681 sf = (xfs_dir_shortform_t *) ifp->if_u1.if_data;
2682 *ino_dirty = 0;
2683 bytes_deleted = 0;
2684
2685 max_size = ifp->if_bytes;
2686 ASSERT(ip->i_d.di_size <= ifp->if_bytes);
2687
2688 /*
2689 * no '.' entry in shortform dirs, just bump up ref count by 1
2690 * '..' was already (or will be) accounted for and checked when
2691 * the directory is reached or will be taken care of when the
2692 * directory is moved to orphanage.
2693 */
2694 add_inode_ref(current_irec, current_ino_offset);
2695
2696 /*
2697 * now run through entries, stop at first bad entry, don't need
2698 * to skip over '..' since that's encoded in its own field and
2699 * no need to worry about '.' since it doesn't exist.
2700 */
2701 sf_entry = next_sfe = &sf->list[0];
2702 if (sf == NULL) {
2703 junkit = 1;
2704 do_warn("shortform dir inode %llu has null data entries \n", ino);
2705
2706 }
2707 else {
2708 for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT) && max_size >
2709 (__psint_t)next_sfe - (__psint_t)sf;
2710 sf_entry = next_sfe, i++) {
2711 junkit = 0;
2712 bad_sfnamelen = 0;
2713 tmp_sfe = NULL;
2714
2715 XFS_DIR_SF_GET_DIRINO_ARCH(&sf_entry->inumber, &lino, ARCH_CONVERT);
2716
2717 namelen = sf_entry->namelen;
2718
2719 ASSERT(no_modify || namelen > 0);
2720
2721 if (no_modify && namelen == 0) {
2722 /*
2723 * if we're really lucky, this is
2724 * the last entry in which case we
2725 * can use the dir size to set the
2726 * namelen value. otherwise, forget
2727 * it because we're not going to be
2728 * able to find the next entry.
2729 */
2730 bad_sfnamelen = 1;
2731
2732 if (i == INT_GET(sf->hdr.count, ARCH_CONVERT) - 1) {
2733 namelen = ip->i_d.di_size -
2734 ((__psint_t) &sf_entry->name[0] -
2735 (__psint_t) sf);
2736 } else {
2737 /*
2738 * don't process the rest of the directory,
2739 * break out of processing looop
2740 */
2741 break;
2742 }
2743 } else if (no_modify && (__psint_t) sf_entry - (__psint_t) sf +
2744 + XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry)
2745 > ip->i_d.di_size) {
2746 bad_sfnamelen = 1;
2747
2748 if (i == INT_GET(sf->hdr.count, ARCH_CONVERT) - 1) {
2749 namelen = ip->i_d.di_size -
2750 ((__psint_t) &sf_entry->name[0] -
2751 (__psint_t) sf);
2752 } else {
2753 /*
2754 * don't process the rest of the directory,
2755 * break out of processing looop
2756 */
2757 break;
2758 }
2759 }
2760
2761 bcopy(sf_entry->name, fname, sf_entry->namelen);
2762 fname[sf_entry->namelen] = '\0';
2763
2764 ASSERT(no_modify || lino != NULLFSINO);
2765 ASSERT(no_modify || !verify_inum(mp, lino));
2766
2767 /*
2768 * special case the "lost+found" entry if it's pointing
2769 * to where we think lost+found should be. if that's
2770 * the case, that's the one we created in phase 6.
2771 * just skip it. no need to process it and its ..
2772 * link is already accounted for. Also skip entries
2773 * with bogus inode numbers if we're in no modify mode.
2774 */
2775
27527004
NS
2776 if ((lino == orphanage_ino && strcmp(fname, ORPHANAGE) == 0)
2777 || (no_modify && verify_inum(mp, lino))) {
2bd0ea18
NS
2778 next_sfe = (xfs_dir_sf_entry_t *)
2779 ((__psint_t) sf_entry +
2780 XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry));
2781 continue;
2782 }
2783
2784 irec = find_inode_rec(XFS_INO_TO_AGNO(mp, lino),
2785 XFS_INO_TO_AGINO(mp, lino));
2786
2787 if (irec == NULL && no_modify) {
2788 do_warn(
2789"entry \"%s\" in shortform dir %llu references non-existent ino %llu\n",
2790 fname, ino, lino);
2791 do_warn("would junk entry\n");
2792 continue;
2793 }
2794
2795 ASSERT(irec != NULL);
2796
2797 ino_offset = XFS_INO_TO_AGINO(mp, lino) - irec->ino_startnum;
2798
2799 /*
2800 * if it's a free inode, blow out the entry.
2801 * by now, any inode that we think is free
2802 * really is free.
2803 */
2804 if (is_inode_free(irec, ino_offset)) {
2805 /*
2806 * don't complain if this entry points to the old
2807 * and now-free lost+found inode
2808 */
2809 if (verbose || no_modify || lino != old_orphanage_ino)
2810 do_warn(
2811 "entry \"%s\" in shortform dir inode %llu points to free inode %llu\n",
2812 fname, ino, lino);
2813
2814 if (!no_modify) {
2815 junkit = 1;
2816 } else {
2817 do_warn("would junk entry \"%s\"\n",
2818 fname);
2819 }
2820 } else if (!inode_isadir(irec, ino_offset)) {
2821 /*
2822 * check easy case first, regular inode, just bump
2823 * the link count and continue
2824 */
2825 add_inode_reached(irec, ino_offset);
2826
2827 next_sfe = (xfs_dir_sf_entry_t *)
2828 ((__psint_t) sf_entry +
2829 XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry));
2830 continue;
2831 } else {
2832 parent = get_inode_parent(irec, ino_offset);
2833
2834 /*
2835 * bump up the link counts in parent and child.
2836 * directory but if the link doesn't agree with
2837 * the .. in the child, blow out the entry
2838 */
2839 if (is_inode_reached(irec, ino_offset)) {
2840 junkit = 1;
2841 do_warn(
2842 "entry \"%s\" in dir %llu references already connected dir ino %llu,\n",
2843 fname, ino, lino);
2844 } else if (parent == ino) {
2845 add_inode_reached(irec, ino_offset);
2846 add_inode_ref(current_irec, current_ino_offset);
2847
2848 if (!is_inode_refchecked(lino, irec,
2849 ino_offset))
2850 push_dir(stack, lino);
2851 } else {
2852 junkit = 1;
2853 do_warn(
2854"entry \"%s\" in dir %llu not consistent with .. value (%llu) in dir ino %llu,\n",
2855 fname, ino, parent, lino);
2856 }
2857 }
2858
2859 if (junkit) {
2860 if (!no_modify) {
2861 tmp_elen = XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry);
2862 tmp_sfe = (xfs_dir_sf_entry_t *)
2863 ((__psint_t) sf_entry + tmp_elen);
2864 tmp_len = max_size - ((__psint_t) tmp_sfe
2865 - (__psint_t) sf);
2866 max_size -= tmp_elen;
2867 bytes_deleted += tmp_elen;
2868
2869 memmove(sf_entry, tmp_sfe, tmp_len);
2870
2871 INT_MOD(sf->hdr.count, ARCH_CONVERT, -1);
2872 bzero((void *) ((__psint_t) sf_entry + tmp_len),
2873 tmp_elen);
2874
2875 /*
2876 * set the tmp value to the current
2877 * pointer so we'll process the entry
2878 * we just moved up
2879 */
2880 tmp_sfe = sf_entry;
2881
2882 /*
2883 * WARNING: drop the index i by one
2884 * so it matches the decremented count for
2885 * accurate comparisons in the loop test
2886 */
2887 i--;
2888
2889 *ino_dirty = 1;
2890
2891 if (verbose || lino != old_orphanage_ino)
2892 do_warn(
2893 "junking entry \"%s\" in directory inode %llu\n",
2894 fname, lino);
2895 } else {
2896 do_warn("would junk entry \"%s\"\n", fname);
2897 }
2898 }
2899
2900 /*
2901 * go onto next entry unless we've just junked an
2902 * entry in which the current entry pointer points
2903 * to an unprocessed entry. have to take into entries
2904 * with bad namelen into account in no modify mode since we
2905 * calculate size based on next_sfe.
2906 */
2907 ASSERT(no_modify || bad_sfnamelen == 0);
2908
2909 next_sfe = (tmp_sfe == NULL)
2910 ? (xfs_dir_sf_entry_t *) ((__psint_t) sf_entry
2911 + ((!bad_sfnamelen)
2912 ? XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry)
2913 : sizeof(xfs_dir_sf_entry_t) - 1
2914 + namelen))
2915 : tmp_sfe;
2916 }
2917 }
2918
2919 /*
2920 * sync up sizes if required
2921 */
2922 if (*ino_dirty) {
2923 ASSERT(bytes_deleted > 0);
2924 ASSERT(!no_modify);
2925 libxfs_idata_realloc(ip, -bytes_deleted, XFS_DATA_FORK);
2926 ip->i_d.di_size -= bytes_deleted;
2927 }
2928
2929 if (ip->i_d.di_size != ip->i_df.if_bytes) {
2930 ASSERT(ip->i_df.if_bytes == (xfs_fsize_t)
2931 ((__psint_t) next_sfe - (__psint_t) sf));
2932 ip->i_d.di_size = (xfs_fsize_t)
2933 ((__psint_t) next_sfe - (__psint_t) sf);
2934 do_warn(
2935 "setting size to %lld bytes to reflect junked entries\n",
2936 ip->i_d.di_size);
2937 *ino_dirty = 1;
2938 }
2939}
2940
2941/* ARGSUSED */
2942void
2943prune_sf_dir_entry(xfs_mount_t *mp, xfs_ino_t ino, xfs_inode_t *ip)
2944{
2945 /* REFERENCED */
2946 xfs_ino_t lino;
2947 xfs_dir_shortform_t *sf;
2948 xfs_dir_sf_entry_t *sf_entry, *next_sfe, *tmp_sfe;
2949 xfs_ifork_t *ifp;
2950 int max_size;
2951 int i;
2952 int tmp_len;
2953 int tmp_elen;
2954 int bytes_deleted;
2955 char fname[MAXNAMELEN + 1];
2956
2957 ifp = &ip->i_df;
2958 sf = (xfs_dir_shortform_t *) ifp->if_u1.if_data;
2959 bytes_deleted = 0;
2960
2961 max_size = ifp->if_bytes;
2962 ASSERT(ip->i_d.di_size <= ifp->if_bytes);
2963
2964 /*
2965 * now run through entries and delete every bad entry
2966 */
2967 sf_entry = next_sfe = &sf->list[0];
2968
2969 for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT) && max_size >
2970 (__psint_t)next_sfe - (__psint_t)sf;
2971 sf_entry = next_sfe, i++) {
2972 tmp_sfe = NULL;
2973
2974 XFS_DIR_SF_GET_DIRINO_ARCH(&sf_entry->inumber, &lino, ARCH_CONVERT);
2975
2976 bcopy(sf_entry->name, fname, sf_entry->namelen);
2977 fname[sf_entry->namelen] = '\0';
2978
2979 if (sf_entry->name[0] == '/') {
2980 if (!no_modify) {
2981 tmp_elen = XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry);
2982 tmp_sfe = (xfs_dir_sf_entry_t *)
2983 ((__psint_t) sf_entry + tmp_elen);
2984 tmp_len = max_size - ((__psint_t) tmp_sfe
2985 - (__psint_t) sf);
2986 max_size -= tmp_elen;
2987 bytes_deleted += tmp_elen;
2988
2989 memmove(sf_entry, tmp_sfe, tmp_len);
2990
2991 INT_MOD(sf->hdr.count, ARCH_CONVERT, -1);
2992 bzero((void *) ((__psint_t) sf_entry + tmp_len),
2993 tmp_elen);
2994
2995 /*
2996 * set the tmp value to the current
2997 * pointer so we'll process the entry
2998 * we just moved up
2999 */
3000 tmp_sfe = sf_entry;
3001
3002 /*
3003 * WARNING: drop the index i by one
3004 * so it matches the decremented count for
3005 * accurate comparisons in the loop test
3006 */
3007 i--;
3008 }
3009 }
3010 next_sfe = (tmp_sfe == NULL)
3011 ? (xfs_dir_sf_entry_t *) ((__psint_t) sf_entry +
3012 XFS_DIR_SF_ENTSIZE_BYENTRY(sf_entry))
3013 : tmp_sfe;
3014 }
3015
3016 /*
3017 * sync up sizes if required
3018 */
3019 if (bytes_deleted > 0) {
3020 libxfs_idata_realloc(ip, -bytes_deleted, XFS_DATA_FORK);
3021 ip->i_d.di_size -= bytes_deleted;
3022 }
3023
3024 if (ip->i_d.di_size != ip->i_df.if_bytes) {
3025 ASSERT(ip->i_df.if_bytes == (xfs_fsize_t)
3026 ((__psint_t) next_sfe - (__psint_t) sf));
3027 ip->i_d.di_size = (xfs_fsize_t)
3028 ((__psint_t) next_sfe - (__psint_t) sf);
3029 do_warn(
3030 "setting size to %lld bytes to reflect junked entries\n",
3031 ip->i_d.di_size);
3032 }
3033}
3034
3035/*
3036 * shortform directory v2 processing routines -- entry verification and
3037 * bad entry deletion (pruning).
3038 */
3039void
3040shortform_dir2_entry_check(xfs_mount_t *mp,
3041 xfs_ino_t ino,
3042 xfs_inode_t *ip,
3043 int *ino_dirty,
3044 dir_stack_t *stack,
3045 ino_tree_node_t *current_irec,
3046 int current_ino_offset)
3047{
3048 xfs_ino_t lino;
3049 xfs_ino_t parent;
3050 xfs_dir2_sf_t *sfp;
3051 xfs_dir2_sf_entry_t *sfep, *next_sfep, *tmp_sfep;
3052 xfs_ifork_t *ifp;
3053 ino_tree_node_t *irec;
3054 int max_size;
3055 int ino_offset;
3056 int i;
3057 int junkit;
3058 int tmp_len;
3059 int tmp_elen;
3060 int bad_sfnamelen;
3061 int namelen;
3062 int bytes_deleted;
3063 char fname[MAXNAMELEN + 1];
3064 int i8;
3065
3066 ifp = &ip->i_df;
3067 sfp = (xfs_dir2_sf_t *) ifp->if_u1.if_data;
3068 *ino_dirty = 0;
e55d768a 3069 bytes_deleted = 0;
2bd0ea18
NS
3070
3071 max_size = ifp->if_bytes;
3072 ASSERT(ip->i_d.di_size <= ifp->if_bytes);
3073
3074 /*
3075 * no '.' entry in shortform dirs, just bump up ref count by 1
3076 * '..' was already (or will be) accounted for and checked when
3077 * the directory is reached or will be taken care of when the
3078 * directory is moved to orphanage.
3079 */
3080 add_inode_ref(current_irec, current_ino_offset);
3081
e55d768a
NS
3082 /*
3083 * Initialise i8 counter -- the parent inode number counts as well.
3084 */
3085 i8 = (XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, &sfp->hdr.parent, ARCH_CONVERT) > XFS_DIR2_MAX_SHORT_INUM);
3086
2bd0ea18
NS
3087 /*
3088 * now run through entries, stop at first bad entry, don't need
3089 * to skip over '..' since that's encoded in its own field and
3090 * no need to worry about '.' since it doesn't exist.
3091 */
3092 sfep = next_sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
3093
3094 for (i = 0; i < INT_GET(sfp->hdr.count, ARCH_CONVERT) && max_size >
3095 (__psint_t)next_sfep - (__psint_t)sfp;
3096 sfep = next_sfep, i++) {
3097 junkit = 0;
3098 bad_sfnamelen = 0;
3099 tmp_sfep = NULL;
3100
3101 lino = XFS_DIR2_SF_GET_INUMBER_ARCH(sfp, XFS_DIR2_SF_INUMBERP(sfep), ARCH_CONVERT);
3102
3103 namelen = sfep->namelen;
3104
3105 ASSERT(no_modify || namelen > 0);
3106
3107 if (no_modify && namelen == 0) {
3108 /*
3109 * if we're really lucky, this is
3110 * the last entry in which case we
3111 * can use the dir size to set the
3112 * namelen value. otherwise, forget
3113 * it because we're not going to be
3114 * able to find the next entry.
3115 */
3116 bad_sfnamelen = 1;
3117
3118 if (i == INT_GET(sfp->hdr.count, ARCH_CONVERT) - 1) {
3119 namelen = ip->i_d.di_size -
3120 ((__psint_t) &sfep->name[0] -
3121 (__psint_t) sfp);
3122 } else {
3123 /*
3124 * don't process the rest of the directory,
3125 * break out of processing loop
3126 */
3127 break;
3128 }
3129 } else if (no_modify && (__psint_t) sfep - (__psint_t) sfp +
3130 + XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep)
3131 > ip->i_d.di_size) {
3132 bad_sfnamelen = 1;
3133
3134 if (i == INT_GET(sfp->hdr.count, ARCH_CONVERT) - 1) {
3135 namelen = ip->i_d.di_size -
3136 ((__psint_t) &sfep->name[0] -
3137 (__psint_t) sfp);
3138 } else {
3139 /*
3140 * don't process the rest of the directory,
3141 * break out of processing loop
3142 */
3143 break;
3144 }
3145 }
3146
3147 bcopy(sfep->name, fname, sfep->namelen);
3148 fname[sfep->namelen] = '\0';
3149
3150 ASSERT(no_modify || (lino != NULLFSINO && lino != 0));
3151 ASSERT(no_modify || !verify_inum(mp, lino));
3152
3153 /*
3154 * special case the "lost+found" entry if it's pointing
3155 * to where we think lost+found should be. if that's
3156 * the case, that's the one we created in phase 6.
3157 * just skip it. no need to process it and its ..
e55d768a 3158 * link is already accounted for.
2bd0ea18
NS
3159 */
3160
e55d768a
NS
3161 if (lino == orphanage_ino && strcmp(fname, ORPHANAGE) == 0) {
3162 if (lino > XFS_DIR2_MAX_SHORT_INUM)
3163 i8++;
3164 next_sfep = (xfs_dir2_sf_entry_t *)
3165 ((__psint_t) sfep +
3166 XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep));
3167 continue;
3168 }
3169
3170 /*
3171 * Also skip entries with bogus inode numbers if we're
3172 * in no modify mode.
3173 */
3174
3175 if (no_modify && verify_inum(mp, lino)) {
2bd0ea18
NS
3176 next_sfep = (xfs_dir2_sf_entry_t *)
3177 ((__psint_t) sfep +
3178 XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep));
3179 continue;
3180 }
3181
3182 irec = find_inode_rec(XFS_INO_TO_AGNO(mp, lino),
3183 XFS_INO_TO_AGINO(mp, lino));
3184
3185 if (irec == NULL && no_modify) {
3186 do_warn("entry \"%s\" in shortform directory %llu "
3187 "references non-existent inode %llu\n",
3188 fname, ino, lino);
3189 do_warn("would junk entry\n");
3190 continue;
3191 }
3192
3193 ASSERT(irec != NULL);
3194
3195 ino_offset = XFS_INO_TO_AGINO(mp, lino) - irec->ino_startnum;
3196
3197 /*
3198 * if it's a free inode, blow out the entry.
3199 * by now, any inode that we think is free
3200 * really is free.
3201 */
3202 if (is_inode_free(irec, ino_offset)) {
3203 /*
3204 * don't complain if this entry points to the old
3205 * and now-free lost+found inode
3206 */
3207 if (verbose || no_modify || lino != old_orphanage_ino)
3208 do_warn("entry \"%s\" in shortform directory "
3209 "inode %llu points to free inode "
3210 "%llu\n",
3211 fname, ino, lino);
3212
3213 if (!no_modify) {
3214 junkit = 1;
3215 } else {
3216 do_warn("would junk entry \"%s\"\n",
3217 fname);
3218 }
3219 } else if (!inode_isadir(irec, ino_offset)) {
3220 /*
3221 * check easy case first, regular inode, just bump
e55d768a 3222 * the link count
2bd0ea18
NS
3223 */
3224 add_inode_reached(irec, ino_offset);
2bd0ea18
NS
3225 } else {
3226 parent = get_inode_parent(irec, ino_offset);
3227
3228 /*
3229 * bump up the link counts in parent and child.
3230 * directory but if the link doesn't agree with
3231 * the .. in the child, blow out the entry
3232 */
3233 if (is_inode_reached(irec, ino_offset)) {
3234 junkit = 1;
3235 do_warn("entry \"%s\" in directory inode %llu "
3236 "references already connected inode "
3237 "%llu,\n",
3238 fname, ino, lino);
3239 } else if (parent == ino) {
3240 add_inode_reached(irec, ino_offset);
3241 add_inode_ref(current_irec, current_ino_offset);
3242
3243 if (!is_inode_refchecked(lino, irec,
3244 ino_offset))
3245 push_dir(stack, lino);
3246 } else {
3247 junkit = 1;
3248 do_warn("entry \"%s\" in directory inode %llu "
3249 "not consistent with .. value (%llu) "
3250 "in inode %llu,\n",
3251 fname, ino, parent, lino);
3252 }
3253 }
3254
3255 if (junkit) {
3256 if (!no_modify) {
3257 tmp_elen = XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep);
3258 tmp_sfep = (xfs_dir2_sf_entry_t *)
3259 ((__psint_t) sfep + tmp_elen);
3260 tmp_len = max_size - ((__psint_t) tmp_sfep
3261 - (__psint_t) sfp);
3262 max_size -= tmp_elen;
3263 bytes_deleted += tmp_elen;
3264
3265 memmove(sfep, tmp_sfep, tmp_len);
3266
3267 INT_MOD(sfp->hdr.count, ARCH_CONVERT, -1);
3268 bzero((void *) ((__psint_t) sfep + tmp_len),
3269 tmp_elen);
3270
3271 /*
3272 * set the tmp value to the current
3273 * pointer so we'll process the entry
3274 * we just moved up
3275 */
3276 tmp_sfep = sfep;
3277
3278 /*
3279 * WARNING: drop the index i by one
3280 * so it matches the decremented count for
3281 * accurate comparisons in the loop test
3282 */
3283 i--;
3284
3285 *ino_dirty = 1;
3286
3287 if (verbose || lino != old_orphanage_ino)
3288 do_warn("junking entry \"%s\" in "
3289 "directory inode %llu\n",
3290 fname, lino);
3291 } else {
3292 do_warn("would junk entry \"%s\"\n", fname);
3293 }
3294 } else if (lino > XFS_DIR2_MAX_SHORT_INUM)
3295 i8++;
3296
3297 /*
3298 * go onto next entry unless we've just junked an
3299 * entry in which the current entry pointer points
3300 * to an unprocessed entry. have to take into entries
3301 * with bad namelen into account in no modify mode since we
3302 * calculate size based on next_sfep.
3303 */
3304 ASSERT(no_modify || bad_sfnamelen == 0);
3305
3306 next_sfep = (tmp_sfep == NULL)
3307 ? (xfs_dir2_sf_entry_t *) ((__psint_t) sfep
3308 + ((!bad_sfnamelen)
3309 ? XFS_DIR2_SF_ENTSIZE_BYENTRY(sfp, sfep)
3310 : XFS_DIR2_SF_ENTSIZE_BYNAME(sfp, namelen)))
3311 : tmp_sfep;
3312 }
3313
3314 if (sfp->hdr.i8count != i8) {
3315 if (no_modify) {
3316 do_warn("would fix i8count in inode %llu\n", ino);
3317 } else {
3318 if (i8 == 0) {
3319 tmp_sfep = next_sfep;
3320 process_sf_dir2_fixi8(sfp, &tmp_sfep);
3321 bytes_deleted +=
3322 (__psint_t)next_sfep -
3323 (__psint_t)tmp_sfep;
3324 next_sfep = tmp_sfep;
3325 } else
3326 sfp->hdr.i8count = i8;
3327 *ino_dirty = 1;
3328 do_warn("fixing i8count in inode %llu\n", ino);
3329 }
3330 }
3331
3332 /*
3333 * sync up sizes if required
3334 */
3335 if (*ino_dirty) {
3336 ASSERT(bytes_deleted > 0);
3337 ASSERT(!no_modify);
3338 libxfs_idata_realloc(ip, -bytes_deleted, XFS_DATA_FORK);
3339 ip->i_d.di_size -= bytes_deleted;
3340 }
3341
3342 if (ip->i_d.di_size != ip->i_df.if_bytes) {
3343 ASSERT(ip->i_df.if_bytes == (xfs_fsize_t)
3344 ((__psint_t) next_sfep - (__psint_t) sfp));
3345 ip->i_d.di_size = (xfs_fsize_t)
3346 ((__psint_t) next_sfep - (__psint_t) sfp);
3347 do_warn("setting size to %lld bytes to reflect junked "
3348 "entries\n",
3349 ip->i_d.di_size);
3350 *ino_dirty = 1;
3351 }
3352}
3353
3354/*
3355 * processes all directories reachable via the inodes on the stack
3356 * returns 0 if things are good, 1 if there's a problem
3357 */
3358void
3359process_dirstack(xfs_mount_t *mp, dir_stack_t *stack)
3360{
3361 xfs_bmap_free_t flist;
3362 xfs_fsblock_t first;
3363 xfs_ino_t ino;
3364 xfs_inode_t *ip;
3365 xfs_trans_t *tp;
3366 xfs_dahash_t hashval;
3367 ino_tree_node_t *irec;
3368 int ino_offset, need_dot, committed;
3369 int dirty, num_illegal, error, nres;
3370
3371 /*
3372 * pull directory inode # off directory stack
3373 *
3374 * open up directory inode, check all entries,
3375 * then call prune_dir_entries to remove all
3376 * remaining illegal directory entries.
3377 */
3378
3379 while ((ino = pop_dir(stack)) != NULLFSINO) {
3380 irec = find_inode_rec(XFS_INO_TO_AGNO(mp, ino),
3381 XFS_INO_TO_AGINO(mp, ino));
3382 ASSERT(irec != NULL);
3383
3384 ino_offset = XFS_INO_TO_AGINO(mp, ino) - irec->ino_startnum;
3385
3386 ASSERT(!is_inode_refchecked(ino, irec, ino_offset));
3387
27527004 3388 if ((error = libxfs_iget(mp, NULL, ino, 0, &ip, 0))) {
2bd0ea18
NS
3389 if (!no_modify)
3390 do_error("couldn't map inode %llu, err = %d\n",
3391 ino, error);
3392 else {
3393 do_warn("couldn't map inode %llu, err = %d\n",
3394 ino, error);
3395 /*
3396 * see below for what we're doing if this
3397 * is root. Why do we need to do this here?
3398 * to ensure that the root doesn't show up
3399 * as being disconnected in the no_modify case.
3400 */
3401 if (mp->m_sb.sb_rootino == ino) {
3402 add_inode_reached(irec, 0);
3403 add_inode_ref(irec, 0);
3404 }
3405 }
3406
3407 add_inode_refchecked(ino, irec, 0);
3408 continue;
3409 }
3410
3411 need_dot = dirty = num_illegal = 0;
3412
3413 if (mp->m_sb.sb_rootino == ino) {
3414 /*
3415 * mark root inode reached and bump up
3416 * link count for root inode to account
3417 * for '..' entry since the root inode is
3418 * never reached by a parent. we know
3419 * that root's '..' is always good --
3420 * guaranteed by phase 3 and/or below.
3421 */
3422 add_inode_reached(irec, ino_offset);
3423 /*
3424 * account for link for the orphanage
3425 * "lost+found". if we're running in
3426 * modify mode and it already existed,
3427 * we deleted it so it's '..' reference
3428 * never got counted. so add it here if
3429 * we're going to create lost+found.
3430 *
3431 * if we're running in no_modify mode,
3432 * we never deleted lost+found and we're
3433 * not going to create it so do nothing.
3434 *
3435 * either way, the counts will match when
3436 * we look at the root inode's nlinks
3437 * field and compare that to our incore
3438 * count in phase 7.
3439 */
3440 if (!no_modify)
3441 add_inode_ref(irec, ino_offset);
3442 }
3443
3444 add_inode_refchecked(ino, irec, ino_offset);
3445
3446 /*
3447 * look for bogus entries
3448 */
3449 switch (ip->i_d.di_format) {
3450 case XFS_DINODE_FMT_EXTENTS:
3451 case XFS_DINODE_FMT_BTREE:
3452 /*
3453 * also check for missing '.' in longform dirs.
3454 * missing .. entries are added if required when
3455 * the directory is connected to lost+found. but
3456 * we need to create '.' entries here.
3457 */
3458 if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb))
3459 longform_dir2_entry_check(mp, ino, ip,
3460 &num_illegal, &need_dot,
3461 stack, irec,
3462 ino_offset);
3463 else
3464 longform_dir_entry_check(mp, ino, ip,
3465 &num_illegal, &need_dot,
3466 stack, irec,
3467 ino_offset);
3468 break;
3469 case XFS_DINODE_FMT_LOCAL:
3470 tp = libxfs_trans_alloc(mp, 0);
3471 /*
3472 * using the remove reservation is overkill
3473 * since at most we'll only need to log the
3474 * inode but it's easier than wedging a
3475 * new define in ourselves.
3476 */
3477 nres = no_modify ? 0 : XFS_REMOVE_SPACE_RES(mp);
3478 error = libxfs_trans_reserve(tp, nres,
3479 XFS_REMOVE_LOG_RES(mp), 0,
3480 XFS_TRANS_PERM_LOG_RES,
3481 XFS_REMOVE_LOG_COUNT);
3482 if (error)
3483 res_failed(error);
3484
3485 libxfs_trans_ijoin(tp, ip, 0);
3486 libxfs_trans_ihold(tp, ip);
3487
3488 if (XFS_SB_VERSION_HASDIRV2(&mp->m_sb))
3489 shortform_dir2_entry_check(mp, ino, ip, &dirty,
3490 stack, irec,
3491 ino_offset);
3492 else
3493 shortform_dir_entry_check(mp, ino, ip, &dirty,
3494 stack, irec,
3495 ino_offset);
3496
27527004 3497 ASSERT(dirty == 0 || (dirty && !no_modify));
2bd0ea18
NS
3498 if (dirty) {
3499 libxfs_trans_log_inode(tp, ip,
3500 XFS_ILOG_CORE | XFS_ILOG_DDATA);
3501 libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES
3502 |XFS_TRANS_SYNC, 0);
3503 } else {
3504 libxfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES);
3505 }
3506 break;
3507 default:
3508 break;
3509 }
3510
3511 hashval = 0;
3512
3513 if (!no_modify && !orphanage_entered &&
3514 ino == mp->m_sb.sb_rootino) {
3515 do_warn("re-entering %s into root directory\n",
3516 ORPHANAGE);
3517 tp = libxfs_trans_alloc(mp, 0);
3518 nres = XFS_MKDIR_SPACE_RES(mp, strlen(ORPHANAGE));
3519 error = libxfs_trans_reserve(tp, nres,
3520 XFS_MKDIR_LOG_RES(mp), 0,
3521 XFS_TRANS_PERM_LOG_RES,
3522 XFS_MKDIR_LOG_COUNT);
3523 if (error)
3524 res_failed(error);
3525 libxfs_trans_ijoin(tp, ip, 0);
3526 libxfs_trans_ihold(tp, ip);
3527 XFS_BMAP_INIT(&flist, &first);
27527004 3528 if ((error = dir_createname(mp, tp, ip, ORPHANAGE,
2bd0ea18
NS
3529 strlen(ORPHANAGE),
3530 orphanage_ino, &first, &flist,
27527004 3531 nres)))
2bd0ea18
NS
3532 do_error("can't make %s entry in root inode "
3533 "%llu, createname error %d\n",
3534 ORPHANAGE, ino, error);
3535 libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
3536 error = libxfs_bmap_finish(&tp, &flist, first, &committed);
3537 ASSERT(error == 0);
3538 libxfs_trans_commit(tp,
3539 XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_SYNC, 0);
3540 orphanage_entered = 1;
3541 }
3542
3543 /*
3544 * if we have to create a .. for /, do it now *before*
3545 * we delete the bogus entries, otherwise the directory
3546 * could transform into a shortform dir which would
3547 * probably cause the simulation to choke. Even
3548 * if the illegal entries get shifted around, it's ok
3549 * because the entries are structurally intact and in
3550 * in hash-value order so the simulation won't get confused
3551 * if it has to move them around.
3552 */
3553 if (!no_modify && need_root_dotdot &&
3554 ino == mp->m_sb.sb_rootino) {
3555 ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_LOCAL);
3556
3557 do_warn("recreating root directory .. entry\n");
3558
3559 tp = libxfs_trans_alloc(mp, 0);
3560 ASSERT(tp != NULL);
3561
3562 nres = XFS_MKDIR_SPACE_RES(mp, 2);
3563 error = libxfs_trans_reserve(tp, nres,
3564 XFS_MKDIR_LOG_RES(mp),
3565 0,
3566 XFS_TRANS_PERM_LOG_RES,
3567 XFS_MKDIR_LOG_COUNT);
3568
3569 if (error)
3570 res_failed(error);
3571
3572 libxfs_trans_ijoin(tp, ip, 0);
3573 libxfs_trans_ihold(tp, ip);
3574
3575 XFS_BMAP_INIT(&flist, &first);
3576
27527004
NS
3577 if ((error = dir_createname(mp, tp, ip, "..", 2,
3578 ip->i_ino, &first, &flist, nres)))
2bd0ea18
NS
3579 do_error(
3580"can't make \"..\" entry in root inode %llu, createname error %d\n",
3581 ino, error);
3582
3583 libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
3584
3585 error = libxfs_bmap_finish(&tp, &flist, first,
3586 &committed);
3587 ASSERT(error == 0);
3588 libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES
3589 |XFS_TRANS_SYNC, 0);
3590
3591 need_root_dotdot = 0;
3592 } else if (need_root_dotdot && ino == mp->m_sb.sb_rootino) {
3593 do_warn("would recreate root directory .. entry\n");
3594 }
3595
3596 /*
3597 * delete any illegal entries -- which should only exist
3598 * if the directory is a longform directory. bogus
3599 * shortform directory entries were deleted in phase 4.
3600 */
3601 if (!no_modify && num_illegal > 0) {
3602 ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_LOCAL);
3603 ASSERT(!XFS_SB_VERSION_HASDIRV2(&mp->m_sb));
3604
3605 while (num_illegal > 0 && ip->i_d.di_format !=
3606 XFS_DINODE_FMT_LOCAL) {
3607 prune_lf_dir_entry(mp, ino, ip, &hashval);
3608 num_illegal--;
3609 }
3610
3611 /*
3612 * handle case where we've deleted so many
3613 * entries that the directory has changed from
3614 * a longform to a shortform directory. have
3615 * to allocate a transaction since we're working
3616 * with the incore data fork.
3617 */
3618 if (num_illegal > 0) {
3619 ASSERT(ip->i_d.di_format ==
3620 XFS_DINODE_FMT_LOCAL);
3621 tp = libxfs_trans_alloc(mp, 0);
3622 /*
3623 * using the remove reservation is overkill
3624 * since at most we'll only need to log the
3625 * inode but it's easier than wedging a
3626 * new define in ourselves. 10 block fs
3627 * space reservation is also overkill but
3628 * what the heck...
3629 */
3630 nres = XFS_REMOVE_SPACE_RES(mp);
3631 error = libxfs_trans_reserve(tp, nres,
3632 XFS_REMOVE_LOG_RES(mp), 0,
3633 XFS_TRANS_PERM_LOG_RES,
3634 XFS_REMOVE_LOG_COUNT);
3635 if (error)
3636 res_failed(error);
3637
3638 libxfs_trans_ijoin(tp, ip, 0);
3639 libxfs_trans_ihold(tp, ip);
3640
3641 prune_sf_dir_entry(mp, ino, ip);
3642
3643 libxfs_trans_log_inode(tp, ip,
3644 XFS_ILOG_CORE | XFS_ILOG_DDATA);
3645 ASSERT(error == 0);
3646 libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES
3647 |XFS_TRANS_SYNC, 0);
3648 }
3649 }
3650
3651 /*
3652 * if we need to create the '.' entry, do so only if
3653 * the directory is a longform dir. it it's been
3654 * turned into a shortform dir, then the inode is ok
3655 * since shortform dirs have no '.' entry and the inode
3656 * has already been committed by prune_lf_dir_entry().
3657 */
3658 if (need_dot) {
3659 /*
3660 * bump up our link count but don't
3661 * bump up the inode link count. chances
3662 * are good that even though we lost '.'
3663 * the inode link counts reflect '.' so
3664 * leave the inode link count alone and if
3665 * it turns out to be wrong, we'll catch
3666 * that in phase 7.
3667 */
3668 add_inode_ref(irec, ino_offset);
3669
3670 if (no_modify) {
3671 do_warn(
3672 "would create missing \".\" entry in dir ino %llu\n",
3673 ino);
3674 } else if (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) {
3675 /*
3676 * need to create . entry in longform dir.
3677 */
3678 do_warn(
3679 "creating missing \".\" entry in dir ino %llu\n",
3680 ino);
3681
3682 tp = libxfs_trans_alloc(mp, 0);
3683 ASSERT(tp != NULL);
3684
3685 nres = XFS_MKDIR_SPACE_RES(mp, 1);
3686 error = libxfs_trans_reserve(tp, nres,
3687 XFS_MKDIR_LOG_RES(mp),
3688 0,
3689 XFS_TRANS_PERM_LOG_RES,
3690 XFS_MKDIR_LOG_COUNT);
3691
3692 if (error)
3693 res_failed(error);
3694
3695 libxfs_trans_ijoin(tp, ip, 0);
3696 libxfs_trans_ihold(tp, ip);
3697
3698 XFS_BMAP_INIT(&flist, &first);
3699
27527004 3700 if ((error = dir_createname(mp, tp, ip, ".",
2bd0ea18 3701 1, ip->i_ino, &first, &flist,
27527004 3702 nres)))
2bd0ea18
NS
3703 do_error(
3704 "can't make \".\" entry in dir ino %llu, createname error %d\n",
3705 ino, error);
3706
3707 libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
3708
3709 error = libxfs_bmap_finish(&tp, &flist, first,
3710 &committed);
3711 ASSERT(error == 0);
3712 libxfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES
3713 |XFS_TRANS_SYNC, 0);
3714 }
3715 }
3716
3717 libxfs_iput(ip, 0);
3718 }
3719}
3720
3721/*
3722 * mark realtime bitmap and summary inodes as reached.
3723 * quota inode will be marked here as well
3724 */
3725void
3726mark_standalone_inodes(xfs_mount_t *mp)
3727{
3728 ino_tree_node_t *irec;
3729 int offset;
3730
3731 irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rbmino),
3732 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rbmino));
3733
3734 ASSERT(irec != NULL);
3735
3736 offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rbmino) -
3737 irec->ino_startnum;
3738
3739 add_inode_reached(irec, offset);
3740
3741 irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rsumino),
3742 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rsumino));
3743
3744 offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rsumino) -
3745 irec->ino_startnum;
3746
3747 ASSERT(irec != NULL);
3748
3749 add_inode_reached(irec, offset);
3750
3751 if (fs_quotas) {
3752 if (mp->m_sb.sb_uquotino
3753 && mp->m_sb.sb_uquotino != NULLFSINO) {
3754 irec = find_inode_rec(XFS_INO_TO_AGNO(mp,
3755 mp->m_sb.sb_uquotino),
3756 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino));
3757 offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_uquotino)
3758 - irec->ino_startnum;
3759 add_inode_reached(irec, offset);
3760 }
b36eef04
NS
3761 if (mp->m_sb.sb_gquotino
3762 && mp->m_sb.sb_gquotino != NULLFSINO) {
2bd0ea18 3763 irec = find_inode_rec(XFS_INO_TO_AGNO(mp,
b36eef04
NS
3764 mp->m_sb.sb_gquotino),
3765 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino));
3766 offset = XFS_INO_TO_AGINO(mp, mp->m_sb.sb_gquotino)
2bd0ea18
NS
3767 - irec->ino_startnum;
3768 add_inode_reached(irec, offset);
3769 }
3770 }
3771}
3772
3773void
3774phase6(xfs_mount_t *mp)
3775{
3776 xfs_ino_t ino;
3777 ino_tree_node_t *irec;
3778 dir_stack_t stack;
3779 int i;
3780 int j;
3781
3782 bzero(&zerocr, sizeof(cred_t));
3783
3784 do_log("Phase 6 - check inode connectivity...\n");
3785
3786 if (!no_modify)
3787 teardown_bmap_finish(mp);
3788 else
3789 teardown_bmap(mp);
3790
3791 incore_ext_teardown(mp);
3792
3793 add_ino_backptrs(mp);
3794
3795 /*
3796 * verify existence of root directory - if we have to
3797 * make one, it's ok for the incore data structs not to
3798 * know about it since everything about it (and the other
3799 * inodes in its chunk if a new chunk was created) are ok
3800 */
3801 if (need_root_inode) {
3802 if (!no_modify) {
3803 do_warn("reinitializing root directory\n");
3804 mk_root_dir(mp);
3805 need_root_inode = 0;
3806 need_root_dotdot = 0;
3807 } else {
3808 do_warn("would reinitialize root directory\n");
3809 }
3810 }
3811
3812 if (need_rbmino) {
3813 if (!no_modify) {
3814 do_warn("reinitializing realtime bitmap inode\n");
3815 mk_rbmino(mp);
3816 need_rbmino = 0;
3817 } else {
3818 do_warn("would reinitialize realtime bitmap inode\n");
3819 }
3820 }
3821
3822 if (need_rsumino) {
3823 if (!no_modify) {
3824 do_warn("reinitializing realtime summary inode\n");
3825 mk_rsumino(mp);
3826 need_rsumino = 0;
3827 } else {
3828 do_warn("would reinitialize realtime summary inode\n");
3829 }
3830 }
3831
3832 if (!no_modify) {
3833 do_log(
3834 " - resetting contents of realtime bitmap and summary inodes\n");
3835 if (fill_rbmino(mp)) {
3836 do_warn(
3837 "Warning: realtime bitmap may be inconsistent\n");
3838 }
3839
3840 if (fill_rsumino(mp)) {
3841 do_warn(
3842 "Warning: realtime bitmap may be inconsistent\n");
3843 }
3844 }
3845
3846 /*
3847 * make orphanage (it's guaranteed to not exist now)
3848 */
3849 if (!no_modify) {
3850 do_log(" - ensuring existence of %s directory\n",
3851 ORPHANAGE);
3852 orphanage_ino = mk_orphanage(mp);
3853 }
3854
3855 dir_stack_init(&stack);
3856
3857 mark_standalone_inodes(mp);
3858
3859 /*
3860 * push root dir on stack, then go
3861 */
3862 if (!need_root_inode) {
3863 do_log(" - traversing filesystem starting at / ... \n");
3864
3865 push_dir(&stack, mp->m_sb.sb_rootino);
3866 process_dirstack(mp, &stack);
3867
3868 do_log(" - traversal finished ... \n");
3869 } else {
3870 ASSERT(no_modify != 0);
3871
3872 do_log(
3873" - root inode lost, cannot make new one in no modify mode ... \n");
3874 do_log(
3875" - skipping filesystem traversal from / ... \n");
3876 }
3877
3878 do_log(" - traversing all unattached subtrees ... \n");
3879
3880 irec = find_inode_rec(XFS_INO_TO_AGNO(mp, mp->m_sb.sb_rootino),
3881 XFS_INO_TO_AGINO(mp, mp->m_sb.sb_rootino));
3882
3883 /*
3884 * we always have a root inode, even if it's free...
3885 * if the root is free, forget it, lost+found is already gone
3886 */
3887 if (is_inode_free(irec, 0) || !inode_isadir(irec, 0)) {
3888 need_root_inode = 1;
3889 }
3890
3891 /*
3892 * then process all unreached inodes
3893 * by walking incore inode tree
3894 *
3895 * get next unreached directory inode # from
3896 * incore list
3897 * push inode on dir stack
3898 * call process_dirstack
3899 */
3900 for (i = 0; i < glob_agcount; i++) {
3901 irec = findfirst_inode_rec(i);
3902
3903 if (irec == NULL)
3904 continue;
3905
3906 while (irec != NULL) {
3907 for (j = 0; j < XFS_INODES_PER_CHUNK; j++) {
3908 if (!is_inode_confirmed(irec, j))
3909 continue;
3910 /*
3911 * skip directories that have already been
3912 * processed, even if they haven't been
3913 * reached. If they are reachable, we'll
3914 * pick them up when we process their parent.
3915 */
3916 ino = XFS_AGINO_TO_INO(mp, i,
3917 j + irec->ino_startnum);
3918 if (inode_isadir(irec, j) &&
3919 !is_inode_refchecked(ino,
3920 irec, j)) {
3921 push_dir(&stack, ino);
3922 process_dirstack(mp, &stack);
3923 }
3924 }
3925 irec = next_ino_rec(irec);
3926 }
3927 }
3928
3929 do_log(" - traversals finished ... \n");
3930 do_log(" - moving disconnected inodes to lost+found ... \n");
3931
3932 /*
3933 * move all disconnected inodes to the orphanage
3934 */
3935 for (i = 0; i < glob_agcount; i++) {
3936 irec = findfirst_inode_rec(i);
3937
3938 if (irec == NULL)
3939 continue;
3940
3941 while (irec != NULL) {
3942 for (j = 0; j < XFS_INODES_PER_CHUNK; j++) {
3943 ASSERT(is_inode_confirmed(irec, j));
3944 if (is_inode_free(irec, j))
3945 continue;
3946 if (!is_inode_reached(irec, j)) {
3947 ASSERT(inode_isadir(irec, j) ||
3948 num_inode_references(irec, j)
3949 == 0);
3950 ino = XFS_AGINO_TO_INO(mp, i,
3951 j + irec->ino_startnum);
3952 if (inode_isadir(irec, j))
3953 do_warn(
3954 "disconnected dir inode %llu, ",
3955 ino);
3956 else
3957 do_warn(
3958 "disconnected inode %llu, ",
3959 ino);
3960 if (!no_modify) {
3961 do_warn("moving to %s\n",
3962 ORPHANAGE);
3963 mv_orphanage(mp, orphanage_ino,
3964 ino,
3965 inode_isadir(irec, j));
3966 } else {
3967 do_warn("would move to %s\n",
3968 ORPHANAGE);
3969 }
3970 /*
3971 * for read-only case, even though
3972 * the inode isn't really reachable,
3973 * set the flag (and bump our link
3974 * count) anyway to fool phase 7
3975 */
3976 add_inode_reached(irec, j);
3977 }
3978 }
3979 irec = next_ino_rec(irec);
3980 }
3981 }
3982}