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