Commit 6bd13057 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Fsck locking improvements

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 36e916e1
...@@ -329,17 +329,18 @@ u64 bch2_dirent_lookup(struct bch_fs *c, u64 dir_inum, ...@@ -329,17 +329,18 @@ u64 bch2_dirent_lookup(struct bch_fs *c, u64 dir_inum,
return inum; return inum;
} }
int bch2_empty_dir(struct bch_fs *c, u64 dir_inum) int bch2_empty_dir_trans(struct btree_trans *trans, u64 dir_inum)
{ {
struct btree_trans trans;
struct btree_iter *iter; struct btree_iter *iter;
struct bkey_s_c k; struct bkey_s_c k;
int ret = 0; int ret = 0;
bch2_trans_init(&trans, c); iter = bch2_trans_get_iter(trans, BTREE_ID_DIRENTS,
POS(dir_inum, 0), 0);
if (IS_ERR(iter))
return PTR_ERR(iter);
for_each_btree_key(&trans, iter, BTREE_ID_DIRENTS, for_each_btree_key_continue(iter, 0, k) {
POS(dir_inum, 0), 0, k) {
if (k.k->p.inode > dir_inum) if (k.k->p.inode > dir_inum)
break; break;
...@@ -348,11 +349,17 @@ int bch2_empty_dir(struct bch_fs *c, u64 dir_inum) ...@@ -348,11 +349,17 @@ int bch2_empty_dir(struct bch_fs *c, u64 dir_inum)
break; break;
} }
} }
bch2_trans_exit(&trans); bch2_trans_iter_put(trans, iter);
return ret; return ret;
} }
int bch2_empty_dir(struct bch_fs *c, u64 dir_inum)
{
return bch2_trans_do(c, NULL, 0,
bch2_empty_dir_trans(&trans, dir_inum));
}
int bch2_readdir(struct bch_fs *c, struct file *file, int bch2_readdir(struct bch_fs *c, struct file *file,
struct dir_context *ctx) struct dir_context *ctx)
{ {
......
...@@ -55,6 +55,7 @@ int bch2_dirent_rename(struct btree_trans *, ...@@ -55,6 +55,7 @@ int bch2_dirent_rename(struct btree_trans *,
u64 bch2_dirent_lookup(struct bch_fs *, u64, const struct bch_hash_info *, u64 bch2_dirent_lookup(struct bch_fs *, u64, const struct bch_hash_info *,
const struct qstr *); const struct qstr *);
int bch2_empty_dir_trans(struct btree_trans *, u64);
int bch2_empty_dir(struct bch_fs *, u64); int bch2_empty_dir(struct bch_fs *, u64);
int bch2_readdir(struct bch_fs *, struct file *, struct dir_context *); int bch2_readdir(struct bch_fs *, struct file *, struct dir_context *);
......
...@@ -128,18 +128,21 @@ static struct inode_walker inode_walker_init(void) ...@@ -128,18 +128,21 @@ static struct inode_walker inode_walker_init(void)
}; };
} }
static int walk_inode(struct bch_fs *c, struct inode_walker *w, u64 inum) static int walk_inode(struct btree_trans *trans,
struct inode_walker *w, u64 inum)
{ {
w->first_this_inode = inum != w->cur_inum; if (inum != w->cur_inum) {
w->cur_inum = inum; int ret = bch2_inode_find_by_inum_trans(trans, inum,
&w->inode);
if (w->first_this_inode) {
int ret = bch2_inode_find_by_inum(c, inum, &w->inode);
if (ret && ret != -ENOENT) if (ret && ret != -ENOENT)
return ret; return ret;
w->have_inode = !ret; w->have_inode = !ret;
w->cur_inum = inum;
w->first_this_inode = true;
} else {
w->first_this_inode = false;
} }
return 0; return 0;
...@@ -445,12 +448,15 @@ static int check_extents(struct bch_fs *c) ...@@ -445,12 +448,15 @@ static int check_extents(struct bch_fs *c)
int ret = 0; int ret = 0;
bch2_trans_init(&trans, c); bch2_trans_init(&trans, c);
bch2_trans_preload_iters(&trans);
bch_verbose(c, "checking extents"); bch_verbose(c, "checking extents");
for_each_btree_key(&trans, iter, BTREE_ID_EXTENTS, iter = bch2_trans_get_iter(&trans, BTREE_ID_EXTENTS,
POS(BCACHEFS_ROOT_INO, 0), 0, k) { POS(BCACHEFS_ROOT_INO, 0), 0);
ret = walk_inode(c, &w, k.k->p.inode); retry:
for_each_btree_key_continue(iter, 0, k) {
ret = walk_inode(&trans, &w, k.k->p.inode);
if (ret) if (ret)
break; break;
...@@ -515,6 +521,8 @@ static int check_extents(struct bch_fs *c) ...@@ -515,6 +521,8 @@ static int check_extents(struct bch_fs *c)
} }
err: err:
fsck_err: fsck_err:
if (ret == -EINTR)
goto retry;
return bch2_trans_exit(&trans) ?: ret; return bch2_trans_exit(&trans) ?: ret;
} }
...@@ -537,21 +545,20 @@ static int check_dirents(struct bch_fs *c) ...@@ -537,21 +545,20 @@ static int check_dirents(struct bch_fs *c)
bch_verbose(c, "checking dirents"); bch_verbose(c, "checking dirents");
bch2_trans_init(&trans, c); bch2_trans_init(&trans, c);
bch2_trans_preload_iters(&trans); bch2_trans_preload_iters(&trans);
iter = bch2_trans_get_iter(&trans, BTREE_ID_DIRENTS,
POS(BCACHEFS_ROOT_INO, 0), 0);
hash_check_init(&h); hash_check_init(&h);
iter = bch2_trans_get_iter(&trans, BTREE_ID_DIRENTS,
POS(BCACHEFS_ROOT_INO, 0), 0);
retry:
for_each_btree_key_continue(iter, 0, k) { for_each_btree_key_continue(iter, 0, k) {
struct bkey_s_c_dirent d; struct bkey_s_c_dirent d;
struct bch_inode_unpacked target; struct bch_inode_unpacked target;
bool have_target; bool have_target;
u64 d_inum; u64 d_inum;
ret = walk_inode(c, &w, k.k->p.inode); ret = walk_inode(&trans, &w, k.k->p.inode);
if (ret) if (ret)
break; break;
...@@ -620,7 +627,7 @@ static int check_dirents(struct bch_fs *c) ...@@ -620,7 +627,7 @@ static int check_dirents(struct bch_fs *c)
continue; continue;
} }
ret = bch2_inode_find_by_inum(c, d_inum, &target); ret = bch2_inode_find_by_inum_trans(&trans, d_inum, &target);
if (ret && ret != -ENOENT) if (ret && ret != -ENOENT)
break; break;
...@@ -671,6 +678,9 @@ static int check_dirents(struct bch_fs *c) ...@@ -671,6 +678,9 @@ static int check_dirents(struct bch_fs *c)
hash_stop_chain(&trans, &h); hash_stop_chain(&trans, &h);
err: err:
fsck_err: fsck_err:
if (ret == -EINTR)
goto retry;
return bch2_trans_exit(&trans) ?: ret; return bch2_trans_exit(&trans) ?: ret;
} }
...@@ -689,17 +699,16 @@ static int check_xattrs(struct bch_fs *c) ...@@ -689,17 +699,16 @@ static int check_xattrs(struct bch_fs *c)
bch_verbose(c, "checking xattrs"); bch_verbose(c, "checking xattrs");
bch2_trans_init(&trans, c); hash_check_init(&h);
bch2_trans_init(&trans, c);
bch2_trans_preload_iters(&trans); bch2_trans_preload_iters(&trans);
iter = bch2_trans_get_iter(&trans, BTREE_ID_XATTRS, iter = bch2_trans_get_iter(&trans, BTREE_ID_XATTRS,
POS(BCACHEFS_ROOT_INO, 0), 0); POS(BCACHEFS_ROOT_INO, 0), 0);
retry:
hash_check_init(&h);
for_each_btree_key_continue(iter, 0, k) { for_each_btree_key_continue(iter, 0, k) {
ret = walk_inode(c, &w, k.k->p.inode); ret = walk_inode(&trans, &w, k.k->p.inode);
if (ret) if (ret)
break; break;
...@@ -722,6 +731,8 @@ static int check_xattrs(struct bch_fs *c) ...@@ -722,6 +731,8 @@ static int check_xattrs(struct bch_fs *c)
} }
err: err:
fsck_err: fsck_err:
if (ret == -EINTR)
goto retry;
return bch2_trans_exit(&trans) ?: ret; return bch2_trans_exit(&trans) ?: ret;
} }
...@@ -905,6 +916,7 @@ static int check_directory_structure(struct bch_fs *c, ...@@ -905,6 +916,7 @@ static int check_directory_structure(struct bch_fs *c,
int ret = 0; int ret = 0;
bch2_trans_init(&trans, c); bch2_trans_init(&trans, c);
bch2_trans_preload_iters(&trans);
bch_verbose(c, "checking directory structure"); bch_verbose(c, "checking directory structure");
...@@ -919,9 +931,8 @@ static int check_directory_structure(struct bch_fs *c, ...@@ -919,9 +931,8 @@ static int check_directory_structure(struct bch_fs *c,
} }
ret = path_down(&path, BCACHEFS_ROOT_INO); ret = path_down(&path, BCACHEFS_ROOT_INO);
if (ret) { if (ret)
return ret; goto err;
}
while (path.nr) { while (path.nr) {
next: next:
...@@ -983,14 +994,19 @@ static int check_directory_structure(struct bch_fs *c, ...@@ -983,14 +994,19 @@ static int check_directory_structure(struct bch_fs *c,
path.nr--; path.nr--;
} }
for_each_btree_key(&trans, iter, BTREE_ID_INODES, POS_MIN, 0, k) { iter = bch2_trans_get_iter(&trans, BTREE_ID_INODES, POS_MIN, 0);
retry:
for_each_btree_key_continue(iter, 0, k) {
if (k.k->type != KEY_TYPE_inode) if (k.k->type != KEY_TYPE_inode)
continue; continue;
if (!S_ISDIR(le16_to_cpu(bkey_s_c_to_inode(k).v->bi_mode))) if (!S_ISDIR(le16_to_cpu(bkey_s_c_to_inode(k).v->bi_mode)))
continue; continue;
if (!bch2_empty_dir(c, k.k->p.inode)) ret = bch2_empty_dir_trans(&trans, k.k->p.inode);
if (ret == -EINTR)
goto retry;
if (!ret)
continue; continue;
if (fsck_err_on(!inode_bitmap_test(&dirs_done, k.k->p.inode), c, if (fsck_err_on(!inode_bitmap_test(&dirs_done, k.k->p.inode), c,
...@@ -1018,15 +1034,12 @@ static int check_directory_structure(struct bch_fs *c, ...@@ -1018,15 +1034,12 @@ static int check_directory_structure(struct bch_fs *c,
memset(&path, 0, sizeof(path)); memset(&path, 0, sizeof(path));
goto restart_dfs; goto restart_dfs;
} }
out:
kfree(dirs_done.bits);
kfree(path.entries);
return ret;
err: err:
fsck_err: fsck_err:
ret = bch2_trans_exit(&trans) ?: ret; ret = bch2_trans_exit(&trans) ?: ret;
goto out; kfree(dirs_done.bits);
kfree(path.entries);
return ret;
} }
struct nlink { struct nlink {
...@@ -1070,6 +1083,7 @@ static int bch2_gc_walk_dirents(struct bch_fs *c, nlink_table *links, ...@@ -1070,6 +1083,7 @@ static int bch2_gc_walk_dirents(struct bch_fs *c, nlink_table *links,
int ret; int ret;
bch2_trans_init(&trans, c); bch2_trans_init(&trans, c);
bch2_trans_preload_iters(&trans);
inc_link(c, links, range_start, range_end, BCACHEFS_ROOT_INO, false); inc_link(c, links, range_start, range_end, BCACHEFS_ROOT_INO, false);
...@@ -1327,6 +1341,7 @@ static int bch2_gc_walk_inodes(struct bch_fs *c, ...@@ -1327,6 +1341,7 @@ static int bch2_gc_walk_inodes(struct bch_fs *c,
u64 nlinks_pos; u64 nlinks_pos;
bch2_trans_init(&trans, c); bch2_trans_init(&trans, c);
bch2_trans_preload_iters(&trans);
iter = bch2_trans_get_iter(&trans, BTREE_ID_INODES, iter = bch2_trans_get_iter(&trans, BTREE_ID_INODES,
POS(range_start, 0), 0); POS(range_start, 0), 0);
...@@ -1426,6 +1441,7 @@ static int check_inodes_fast(struct bch_fs *c) ...@@ -1426,6 +1441,7 @@ static int check_inodes_fast(struct bch_fs *c)
int ret = 0, ret2; int ret = 0, ret2;
bch2_trans_init(&trans, c); bch2_trans_init(&trans, c);
bch2_trans_preload_iters(&trans);
iter = bch2_trans_get_iter(&trans, BTREE_ID_INODES, iter = bch2_trans_get_iter(&trans, BTREE_ID_INODES,
POS_MIN, 0); POS_MIN, 0);
......
...@@ -444,31 +444,32 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr) ...@@ -444,31 +444,32 @@ int bch2_inode_rm(struct bch_fs *c, u64 inode_nr)
return ret; return ret;
} }
int bch2_inode_find_by_inum(struct bch_fs *c, u64 inode_nr, int bch2_inode_find_by_inum_trans(struct btree_trans *trans, u64 inode_nr,
struct bch_inode_unpacked *inode) struct bch_inode_unpacked *inode)
{ {
struct btree_trans trans;
struct btree_iter *iter; struct btree_iter *iter;
struct bkey_s_c k; struct bkey_s_c k;
int ret = -ENOENT; int ret = -ENOENT;
bch2_trans_init(&trans, c); iter = bch2_trans_get_iter(trans, BTREE_ID_INODES,
POS(inode_nr, 0), BTREE_ITER_SLOTS);
if (IS_ERR(iter))
return PTR_ERR(iter);
for_each_btree_key(&trans, iter, BTREE_ID_INODES, k = bch2_btree_iter_peek_slot(iter);
POS(inode_nr, 0), BTREE_ITER_SLOTS, k) { if (k.k->type == KEY_TYPE_inode)
switch (k.k->type) {
case KEY_TYPE_inode:
ret = bch2_inode_unpack(bkey_s_c_to_inode(k), inode); ret = bch2_inode_unpack(bkey_s_c_to_inode(k), inode);
break;
default:
/* hole, not found */
break;
}
break; bch2_trans_iter_put(trans, iter);
}
return bch2_trans_exit(&trans) ?: ret; return ret;
}
int bch2_inode_find_by_inum(struct bch_fs *c, u64 inode_nr,
struct bch_inode_unpacked *inode)
{
return bch2_trans_do(c, NULL, 0,
bch2_inode_find_by_inum_trans(&trans, inode_nr, inode));
} }
#ifdef CONFIG_BCACHEFS_DEBUG #ifdef CONFIG_BCACHEFS_DEBUG
......
...@@ -60,8 +60,9 @@ int bch2_inode_create(struct bch_fs *, struct bch_inode_unpacked *, ...@@ -60,8 +60,9 @@ int bch2_inode_create(struct bch_fs *, struct bch_inode_unpacked *,
int bch2_inode_rm(struct bch_fs *, u64); int bch2_inode_rm(struct bch_fs *, u64);
int bch2_inode_find_by_inum(struct bch_fs *, u64, int bch2_inode_find_by_inum_trans(struct btree_trans *, u64,
struct bch_inode_unpacked *); struct bch_inode_unpacked *);
int bch2_inode_find_by_inum(struct bch_fs *, u64, struct bch_inode_unpacked *);
static inline struct bch_io_opts bch2_inode_opts_get(struct bch_inode_unpacked *inode) static inline struct bch_io_opts bch2_inode_opts_get(struct bch_inode_unpacked *inode)
{ {
......
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