Skip to content

Commit bade971

Browse files
author
Kent Overstreet
committed
bcachefs: Split out check_unreachable_inodes() pass
With inode backpointers, we can write a very simple check_unreachable_inodes() pass that only looks for non-unlinked inodes that are missing backpointers, and reattaches them. This simplifies check_directory_structure() so that it's now only checking for directory structure loops, Signed-off-by: Kent Overstreet <[email protected]>
1 parent bf4baaa commit bade971

File tree

3 files changed

+67
-35
lines changed

3 files changed

+67
-35
lines changed

fs/bcachefs/fsck.c

Lines changed: 65 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,58 @@ int bch2_check_inodes(struct bch_fs *c)
12921292
return ret;
12931293
}
12941294

1295+
static int check_unreachable_inode(struct btree_trans *trans,
1296+
struct btree_iter *iter,
1297+
struct bkey_s_c k)
1298+
{
1299+
struct bch_fs *c = trans->c;
1300+
struct printbuf buf = PRINTBUF;
1301+
int ret = 0;
1302+
1303+
if (!bkey_is_inode(k.k))
1304+
return 0;
1305+
1306+
struct bch_inode_unpacked inode;
1307+
BUG_ON(bch2_inode_unpack(k, &inode));
1308+
1309+
if (inode.bi_subvol)
1310+
return 0;
1311+
1312+
if (inode.bi_flags & BCH_INODE_unlinked)
1313+
return 0;
1314+
1315+
if (fsck_err_on(!inode.bi_dir,
1316+
trans, inode_unreachable,
1317+
"unreachable inode:\n%s",
1318+
(printbuf_reset(&buf),
1319+
bch2_bkey_val_to_text(&buf, c, k),
1320+
buf.buf)))
1321+
ret = reattach_inode(trans, &inode);
1322+
fsck_err:
1323+
printbuf_exit(&buf);
1324+
return ret;
1325+
}
1326+
1327+
/*
1328+
* Reattach unreachable (but not unlinked) inodes
1329+
*
1330+
* Run after check_inodes() and check_dirents(), so we node that inode
1331+
* backpointer fields point to valid dirents, and every inode that has a dirent
1332+
* that points to it has its backpointer field set - so we're just looking for
1333+
* non-unlinked inodes without backpointers:
1334+
*/
1335+
int bch2_check_unreachable_inodes(struct bch_fs *c)
1336+
{
1337+
int ret = bch2_trans_run(c,
1338+
for_each_btree_key_commit(trans, iter, BTREE_ID_inodes,
1339+
POS_MIN,
1340+
BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k,
1341+
NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
1342+
check_unreachable_inode(trans, &iter, k)));
1343+
bch_err_fn(c, ret);
1344+
return ret;
1345+
}
1346+
12951347
static inline bool btree_matches_i_mode(enum btree_id btree, unsigned mode)
12961348
{
12971349
switch (btree) {
@@ -2450,22 +2502,6 @@ static int check_subvol_path(struct btree_trans *trans, struct btree_iter *iter,
24502502
if (ret)
24512503
break;
24522504

2453-
/*
2454-
* We've checked that inode backpointers point to valid dirents;
2455-
* here, it's sufficient to check that the subvolume root has a
2456-
* dirent:
2457-
*/
2458-
if (fsck_err_on(!subvol_root.bi_dir,
2459-
trans, subvol_unreachable,
2460-
"unreachable subvolume %s",
2461-
(bch2_bkey_val_to_text(&buf, c, s.s_c),
2462-
prt_newline(&buf),
2463-
bch2_inode_unpacked_to_text(&buf, &subvol_root),
2464-
buf.buf))) {
2465-
ret = reattach_subvol(trans, s);
2466-
break;
2467-
}
2468-
24692505
u32 parent = le32_to_cpu(s.v->fs_path_parent);
24702506

24712507
if (darray_u32_has(&subvol_path, parent)) {
@@ -2526,12 +2562,6 @@ static bool path_is_dup(pathbuf *p, u64 inum, u32 snapshot)
25262562
return false;
25272563
}
25282564

2529-
/*
2530-
* Check that a given inode is reachable from its subvolume root - we already
2531-
* verified subvolume connectivity:
2532-
*
2533-
* XXX: we should also be verifying that inodes are in the right subvolumes
2534-
*/
25352565
static int check_path(struct btree_trans *trans, pathbuf *p, struct bkey_s_c inode_k)
25362566
{
25372567
struct bch_fs *c = trans->c;
@@ -2545,6 +2575,9 @@ static int check_path(struct btree_trans *trans, pathbuf *p, struct bkey_s_c ino
25452575

25462576
BUG_ON(bch2_inode_unpack(inode_k, &inode));
25472577

2578+
if (!S_ISDIR(inode.bi_mode))
2579+
return 0;
2580+
25482581
while (!inode.bi_subvol) {
25492582
struct btree_iter dirent_iter;
25502583
struct bkey_s_c_dirent d;
@@ -2559,21 +2592,15 @@ static int check_path(struct btree_trans *trans, pathbuf *p, struct bkey_s_c ino
25592592
bch2_trans_iter_exit(trans, &dirent_iter);
25602593

25612594
if (bch2_err_matches(ret, ENOENT)) {
2562-
ret = 0;
2563-
if (fsck_err(trans, inode_unreachable,
2564-
"unreachable inode\n%s",
2565-
(printbuf_reset(&buf),
2566-
bch2_bkey_val_to_text(&buf, c, inode_k),
2567-
buf.buf)))
2568-
ret = reattach_inode(trans, &inode);
2595+
printbuf_reset(&buf);
2596+
bch2_bkey_val_to_text(&buf, c, inode_k);
2597+
bch_err(c, "unreachable inode in check_directory_structure: %s\n%s",
2598+
bch2_err_str(ret), buf.buf);
25692599
goto out;
25702600
}
25712601

25722602
bch2_trans_iter_exit(trans, &dirent_iter);
25732603

2574-
if (!S_ISDIR(inode.bi_mode))
2575-
break;
2576-
25772604
ret = darray_push(p, ((struct pathbuf_entry) {
25782605
.inum = inode.bi_inum,
25792606
.snapshot = snapshot,
@@ -2626,9 +2653,8 @@ static int check_path(struct btree_trans *trans, pathbuf *p, struct bkey_s_c ino
26262653
}
26272654

26282655
/*
2629-
* Check for unreachable inodes, as well as loops in the directory structure:
2630-
* After bch2_check_dirents(), if an inode backpointer doesn't exist that means it's
2631-
* unreachable:
2656+
* Check for loops in the directory structure: all other connectivity issues
2657+
* have been fixed by prior passes
26322658
*/
26332659
int bch2_check_directory_structure(struct bch_fs *c)
26342660
{
@@ -2756,6 +2782,10 @@ static int check_nlinks_find_hardlinks(struct bch_fs *c,
27562782
if (S_ISDIR(u.bi_mode))
27572783
continue;
27582784

2785+
/*
2786+
* Previous passes ensured that bi_nlink is nonzero if
2787+
* it had multiple hardlinks:
2788+
*/
27592789
if (!u.bi_nlink)
27602790
continue;
27612791

fs/bcachefs/fsck.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ int bch2_check_dirents(struct bch_fs *);
99
int bch2_check_xattrs(struct bch_fs *);
1010
int bch2_check_root(struct bch_fs *);
1111
int bch2_check_subvolume_structure(struct bch_fs *);
12+
int bch2_check_unreachable_inodes(struct bch_fs *);
1213
int bch2_check_directory_structure(struct bch_fs *);
1314
int bch2_check_nlinks(struct bch_fs *);
1415
int bch2_fix_reflink_p(struct bch_fs *);

fs/bcachefs/recovery_passes_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
x(check_dirents, 27, PASS_FSCK) \
4747
x(check_xattrs, 28, PASS_FSCK) \
4848
x(check_root, 29, PASS_ONLINE|PASS_FSCK) \
49+
x(check_unreachable_inodes, 40, PASS_ONLINE|PASS_FSCK) \
4950
x(check_subvolume_structure, 36, PASS_ONLINE|PASS_FSCK) \
5051
x(check_directory_structure, 30, PASS_ONLINE|PASS_FSCK) \
5152
x(check_nlinks, 31, PASS_FSCK) \

0 commit comments

Comments
 (0)