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