mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
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 <kent.overstreet@linux.dev>
This commit is contained in:
parent
bf4baaa087
commit
bade9711e0
@ -1292,6 +1292,58 @@ int bch2_check_inodes(struct bch_fs *c)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int check_unreachable_inode(struct btree_trans *trans,
|
||||
struct btree_iter *iter,
|
||||
struct bkey_s_c k)
|
||||
{
|
||||
struct bch_fs *c = trans->c;
|
||||
struct printbuf buf = PRINTBUF;
|
||||
int ret = 0;
|
||||
|
||||
if (!bkey_is_inode(k.k))
|
||||
return 0;
|
||||
|
||||
struct bch_inode_unpacked inode;
|
||||
BUG_ON(bch2_inode_unpack(k, &inode));
|
||||
|
||||
if (inode.bi_subvol)
|
||||
return 0;
|
||||
|
||||
if (inode.bi_flags & BCH_INODE_unlinked)
|
||||
return 0;
|
||||
|
||||
if (fsck_err_on(!inode.bi_dir,
|
||||
trans, inode_unreachable,
|
||||
"unreachable inode:\n%s",
|
||||
(printbuf_reset(&buf),
|
||||
bch2_bkey_val_to_text(&buf, c, k),
|
||||
buf.buf)))
|
||||
ret = reattach_inode(trans, &inode);
|
||||
fsck_err:
|
||||
printbuf_exit(&buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reattach unreachable (but not unlinked) inodes
|
||||
*
|
||||
* Run after check_inodes() and check_dirents(), so we node that inode
|
||||
* backpointer fields point to valid dirents, and every inode that has a dirent
|
||||
* that points to it has its backpointer field set - so we're just looking for
|
||||
* non-unlinked inodes without backpointers:
|
||||
*/
|
||||
int bch2_check_unreachable_inodes(struct bch_fs *c)
|
||||
{
|
||||
int ret = bch2_trans_run(c,
|
||||
for_each_btree_key_commit(trans, iter, BTREE_ID_inodes,
|
||||
POS_MIN,
|
||||
BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k,
|
||||
NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
|
||||
check_unreachable_inode(trans, &iter, k)));
|
||||
bch_err_fn(c, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline bool btree_matches_i_mode(enum btree_id btree, unsigned mode)
|
||||
{
|
||||
switch (btree) {
|
||||
@ -2450,22 +2502,6 @@ static int check_subvol_path(struct btree_trans *trans, struct btree_iter *iter,
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
/*
|
||||
* We've checked that inode backpointers point to valid dirents;
|
||||
* here, it's sufficient to check that the subvolume root has a
|
||||
* dirent:
|
||||
*/
|
||||
if (fsck_err_on(!subvol_root.bi_dir,
|
||||
trans, subvol_unreachable,
|
||||
"unreachable subvolume %s",
|
||||
(bch2_bkey_val_to_text(&buf, c, s.s_c),
|
||||
prt_newline(&buf),
|
||||
bch2_inode_unpacked_to_text(&buf, &subvol_root),
|
||||
buf.buf))) {
|
||||
ret = reattach_subvol(trans, s);
|
||||
break;
|
||||
}
|
||||
|
||||
u32 parent = le32_to_cpu(s.v->fs_path_parent);
|
||||
|
||||
if (darray_u32_has(&subvol_path, parent)) {
|
||||
@ -2526,12 +2562,6 @@ static bool path_is_dup(pathbuf *p, u64 inum, u32 snapshot)
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that a given inode is reachable from its subvolume root - we already
|
||||
* verified subvolume connectivity:
|
||||
*
|
||||
* XXX: we should also be verifying that inodes are in the right subvolumes
|
||||
*/
|
||||
static int check_path(struct btree_trans *trans, pathbuf *p, struct bkey_s_c inode_k)
|
||||
{
|
||||
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
|
||||
|
||||
BUG_ON(bch2_inode_unpack(inode_k, &inode));
|
||||
|
||||
if (!S_ISDIR(inode.bi_mode))
|
||||
return 0;
|
||||
|
||||
while (!inode.bi_subvol) {
|
||||
struct btree_iter dirent_iter;
|
||||
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
|
||||
bch2_trans_iter_exit(trans, &dirent_iter);
|
||||
|
||||
if (bch2_err_matches(ret, ENOENT)) {
|
||||
ret = 0;
|
||||
if (fsck_err(trans, inode_unreachable,
|
||||
"unreachable inode\n%s",
|
||||
(printbuf_reset(&buf),
|
||||
bch2_bkey_val_to_text(&buf, c, inode_k),
|
||||
buf.buf)))
|
||||
ret = reattach_inode(trans, &inode);
|
||||
printbuf_reset(&buf);
|
||||
bch2_bkey_val_to_text(&buf, c, inode_k);
|
||||
bch_err(c, "unreachable inode in check_directory_structure: %s\n%s",
|
||||
bch2_err_str(ret), buf.buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
bch2_trans_iter_exit(trans, &dirent_iter);
|
||||
|
||||
if (!S_ISDIR(inode.bi_mode))
|
||||
break;
|
||||
|
||||
ret = darray_push(p, ((struct pathbuf_entry) {
|
||||
.inum = inode.bi_inum,
|
||||
.snapshot = snapshot,
|
||||
@ -2626,9 +2653,8 @@ static int check_path(struct btree_trans *trans, pathbuf *p, struct bkey_s_c ino
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for unreachable inodes, as well as loops in the directory structure:
|
||||
* After bch2_check_dirents(), if an inode backpointer doesn't exist that means it's
|
||||
* unreachable:
|
||||
* Check for loops in the directory structure: all other connectivity issues
|
||||
* have been fixed by prior passes
|
||||
*/
|
||||
int bch2_check_directory_structure(struct bch_fs *c)
|
||||
{
|
||||
@ -2756,6 +2782,10 @@ static int check_nlinks_find_hardlinks(struct bch_fs *c,
|
||||
if (S_ISDIR(u.bi_mode))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Previous passes ensured that bi_nlink is nonzero if
|
||||
* it had multiple hardlinks:
|
||||
*/
|
||||
if (!u.bi_nlink)
|
||||
continue;
|
||||
|
||||
|
@ -9,6 +9,7 @@ int bch2_check_dirents(struct bch_fs *);
|
||||
int bch2_check_xattrs(struct bch_fs *);
|
||||
int bch2_check_root(struct bch_fs *);
|
||||
int bch2_check_subvolume_structure(struct bch_fs *);
|
||||
int bch2_check_unreachable_inodes(struct bch_fs *);
|
||||
int bch2_check_directory_structure(struct bch_fs *);
|
||||
int bch2_check_nlinks(struct bch_fs *);
|
||||
int bch2_fix_reflink_p(struct bch_fs *);
|
||||
|
@ -46,6 +46,7 @@
|
||||
x(check_dirents, 27, PASS_FSCK) \
|
||||
x(check_xattrs, 28, PASS_FSCK) \
|
||||
x(check_root, 29, PASS_ONLINE|PASS_FSCK) \
|
||||
x(check_unreachable_inodes, 40, PASS_ONLINE|PASS_FSCK) \
|
||||
x(check_subvolume_structure, 36, PASS_ONLINE|PASS_FSCK) \
|
||||
x(check_directory_structure, 30, PASS_ONLINE|PASS_FSCK) \
|
||||
x(check_nlinks, 31, PASS_FSCK) \
|
||||
|
Loading…
Reference in New Issue
Block a user