Commit 06dcca51 authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: fsck: Break walk_inode() up into multiple functions

Some refactoring, prep work for algorithm improvements related to
snapshots.

we need to add a bitmap to the list of inodes for "seen this snapshot";
for this bitmap to correctly be available, we'll need to gather the list
of inodes first, and later look up the inode for a given snapshot.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 1fa3e87a
...@@ -639,26 +639,23 @@ static int add_inode(struct bch_fs *c, struct inode_walker *w, ...@@ -639,26 +639,23 @@ static int add_inode(struct bch_fs *c, struct inode_walker *w,
})); }));
} }
static int __walk_inode(struct btree_trans *trans, static int get_inodes_all_snapshots(struct btree_trans *trans,
struct inode_walker *w, struct bpos pos) struct inode_walker *w, u64 inum)
{ {
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
struct btree_iter iter; struct btree_iter iter;
struct bkey_s_c k; struct bkey_s_c k;
u32 restart_count = trans->restart_count; u32 restart_count = trans->restart_count;
unsigned i;
int ret; int ret;
pos.snapshot = bch2_snapshot_equiv(c, pos.snapshot); if (w->cur_inum == inum)
return 0;
if (pos.inode == w->cur_inum)
goto lookup_snapshot;
w->inodes.nr = 0; w->inodes.nr = 0;
for_each_btree_key(trans, iter, BTREE_ID_inodes, POS(0, pos.inode), for_each_btree_key(trans, iter, BTREE_ID_inodes, POS(0, inum),
BTREE_ITER_ALL_SNAPSHOTS, k, ret) { BTREE_ITER_ALL_SNAPSHOTS, k, ret) {
if (k.k->p.offset != pos.inode) if (k.k->p.offset != inum)
break; break;
if (bkey_is_inode(k.k)) if (bkey_is_inode(k.k))
...@@ -669,40 +666,62 @@ static int __walk_inode(struct btree_trans *trans, ...@@ -669,40 +666,62 @@ static int __walk_inode(struct btree_trans *trans,
if (ret) if (ret)
return ret; return ret;
w->cur_inum = pos.inode; w->cur_inum = inum;
w->first_this_inode = true; w->first_this_inode = true;
if (trans_was_restarted(trans, restart_count)) if (trans_was_restarted(trans, restart_count))
return -BCH_ERR_transaction_restart_nested; return -BCH_ERR_transaction_restart_nested;
lookup_snapshot: return 0;
for (i = 0; i < w->inodes.nr; i++) }
if (bch2_snapshot_is_ancestor(c, pos.snapshot, w->inodes.data[i].snapshot))
static struct inode_walker_entry *
lookup_inode_for_snapshot(struct bch_fs *c,
struct inode_walker *w, u32 snapshot)
{
struct inode_walker_entry *i;
snapshot = bch2_snapshot_equiv(c, snapshot);
darray_for_each(w->inodes, i)
if (bch2_snapshot_is_ancestor(c, snapshot, i->snapshot))
goto found; goto found;
return INT_MAX;
return NULL;
found: found:
BUG_ON(pos.snapshot > w->inodes.data[i].snapshot); BUG_ON(snapshot > i->snapshot);
if (pos.snapshot != w->inodes.data[i].snapshot) { if (snapshot != i->snapshot) {
struct inode_walker_entry e = w->inodes.data[i]; struct inode_walker_entry new = *i;
int ret;
e.snapshot = pos.snapshot; new.snapshot = snapshot;
e.count = 0; new.count = 0;
bch_info(c, "have key for inode %llu:%u but have inode in ancestor snapshot %u", bch_info(c, "have key for inode %llu:%u but have inode in ancestor snapshot %u",
pos.inode, pos.snapshot, w->inodes.data[i].snapshot); w->cur_inum, snapshot, i->snapshot);
while (i && w->inodes.data[i - 1].snapshot > pos.snapshot) while (i > w->inodes.data && i[-1].snapshot > snapshot)
--i; --i;
ret = darray_insert_item(&w->inodes, i, e); ret = darray_insert_item(&w->inodes, i - w->inodes.data, new);
if (ret) if (ret)
return ret; return ERR_PTR(ret);
} }
return i; return i;
} }
static struct inode_walker_entry *walk_inode(struct btree_trans *trans,
struct inode_walker *w, struct bpos pos)
{
int ret = get_inodes_all_snapshots(trans, w, pos.inode);
if (ret)
return ERR_PTR(ret);
return lookup_inode_for_snapshot(trans->c, w, pos.snapshot);
}
static int __get_visible_inodes(struct btree_trans *trans, static int __get_visible_inodes(struct btree_trans *trans,
struct inode_walker *w, struct inode_walker *w,
struct snapshots_seen *s, struct snapshots_seen *s,
...@@ -1300,11 +1319,12 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, ...@@ -1300,11 +1319,12 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter,
if (ret) if (ret)
goto err; goto err;
ret = __walk_inode(trans, inode, equiv); i = walk_inode(trans, inode, equiv);
if (ret < 0) ret = PTR_ERR_OR_ZERO(i);
if (ret)
goto err; goto err;
if (fsck_err_on(ret == INT_MAX, c, if (fsck_err_on(!i, c,
"extent in missing inode:\n %s", "extent in missing inode:\n %s",
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
...@@ -1313,13 +1333,8 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter, ...@@ -1313,13 +1333,8 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter,
goto out; goto out;
} }
if (ret == INT_MAX) { if (!i)
ret = 0;
goto out; goto out;
}
i = inode->inodes.data + ret;
ret = 0;
if (fsck_err_on(!S_ISREG(i->inode.bi_mode) && if (fsck_err_on(!S_ISREG(i->inode.bi_mode) &&
!S_ISLNK(i->inode.bi_mode), c, !S_ISLNK(i->inode.bi_mode), c,
...@@ -1625,7 +1640,8 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter, ...@@ -1625,7 +1640,8 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
BUG_ON(!iter->path->should_be_locked); BUG_ON(!iter->path->should_be_locked);
ret = __walk_inode(trans, dir, equiv); i = walk_inode(trans, dir, equiv);
ret = PTR_ERR_OR_ZERO(i);
if (ret < 0) if (ret < 0)
goto err; goto err;
...@@ -1633,7 +1649,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter, ...@@ -1633,7 +1649,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
*hash_info = bch2_hash_info_init(c, &dir->inodes.data[0].inode); *hash_info = bch2_hash_info_init(c, &dir->inodes.data[0].inode);
dir->first_this_inode = false; dir->first_this_inode = false;
if (fsck_err_on(ret == INT_MAX, c, if (fsck_err_on(!i, c,
"dirent in nonexisting directory:\n%s", "dirent in nonexisting directory:\n%s",
(printbuf_reset(&buf), (printbuf_reset(&buf),
bch2_bkey_val_to_text(&buf, c, k), buf.buf))) { bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
...@@ -1642,13 +1658,8 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter, ...@@ -1642,13 +1658,8 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
goto out; goto out;
} }
if (ret == INT_MAX) { if (!i)
ret = 0;
goto out; goto out;
}
i = dir->inodes.data + ret;
ret = 0;
if (fsck_err_on(!S_ISDIR(i->inode.bi_mode), c, if (fsck_err_on(!S_ISDIR(i->inode.bi_mode), c,
"dirent in non directory inode type %s:\n%s", "dirent in non directory inode type %s:\n%s",
...@@ -1802,30 +1813,30 @@ static int check_xattr(struct btree_trans *trans, struct btree_iter *iter, ...@@ -1802,30 +1813,30 @@ static int check_xattr(struct btree_trans *trans, struct btree_iter *iter,
struct inode_walker *inode) struct inode_walker *inode)
{ {
struct bch_fs *c = trans->c; struct bch_fs *c = trans->c;
struct inode_walker_entry *i;
int ret; int ret;
ret = check_key_has_snapshot(trans, iter, k); ret = check_key_has_snapshot(trans, iter, k);
if (ret) if (ret)
return ret; return ret;
ret = __walk_inode(trans, inode, k.k->p); i = walk_inode(trans, inode, k.k->p);
if (ret < 0) ret = PTR_ERR_OR_ZERO(i);
if (ret)
return ret; return ret;
if (inode->first_this_inode) if (inode->first_this_inode)
*hash_info = bch2_hash_info_init(c, &inode->inodes.data[0].inode); *hash_info = bch2_hash_info_init(c, &inode->inodes.data[0].inode);
inode->first_this_inode = false; inode->first_this_inode = false;
if (fsck_err_on(ret == INT_MAX, c, if (fsck_err_on(!i, c,
"xattr for missing inode %llu", "xattr for missing inode %llu",
k.k->p.inode)) k.k->p.inode))
return bch2_btree_delete_at(trans, iter, 0); return bch2_btree_delete_at(trans, iter, 0);
if (ret == INT_MAX) if (!i)
return 0; return 0;
ret = 0;
ret = hash_check_key(trans, bch2_xattr_hash_desc, hash_info, iter, k); ret = hash_check_key(trans, bch2_xattr_hash_desc, hash_info, iter, k);
fsck_err: fsck_err:
if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart)) if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment