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