Commit 58686a25 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Lookup/create lost+found lazily

This is prep work for subvolumes - each subvolume will have its own
lost+found.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent eb365fbc
...@@ -38,7 +38,7 @@ static s64 bch2_count_inode_sectors(struct btree_trans *trans, u64 inum) ...@@ -38,7 +38,7 @@ static s64 bch2_count_inode_sectors(struct btree_trans *trans, u64 inum)
return ret ?: sectors; return ret ?: sectors;
} }
static int lookup_inode(struct btree_trans *trans, u64 inode_nr, static int __lookup_inode(struct btree_trans *trans, u64 inode_nr,
struct bch_inode_unpacked *inode, struct bch_inode_unpacked *inode,
u32 *snapshot) u32 *snapshot)
{ {
...@@ -63,7 +63,14 @@ static int lookup_inode(struct btree_trans *trans, u64 inode_nr, ...@@ -63,7 +63,14 @@ static int lookup_inode(struct btree_trans *trans, u64 inode_nr,
return ret; return ret;
} }
static int write_inode(struct btree_trans *trans, static int lookup_inode(struct btree_trans *trans, u64 inode_nr,
struct bch_inode_unpacked *inode,
u32 *snapshot)
{
return lockrestart_do(trans, __lookup_inode(trans, inode_nr, inode, snapshot));
}
static int __write_inode(struct btree_trans *trans,
struct bch_inode_unpacked *inode, struct bch_inode_unpacked *inode,
u32 snapshot) u32 snapshot)
{ {
...@@ -71,11 +78,19 @@ static int write_inode(struct btree_trans *trans, ...@@ -71,11 +78,19 @@ static int write_inode(struct btree_trans *trans,
bch2_trans_get_iter(trans, BTREE_ID_inodes, bch2_trans_get_iter(trans, BTREE_ID_inodes,
SPOS(0, inode->bi_inum, snapshot), SPOS(0, inode->bi_inum, snapshot),
BTREE_ITER_INTENT); BTREE_ITER_INTENT);
int ret = bch2_inode_write(trans, inode_iter, inode);
bch2_trans_iter_put(trans, inode_iter);
return ret;
}
static int write_inode(struct btree_trans *trans,
struct bch_inode_unpacked *inode,
u32 snapshot)
{
int ret = __bch2_trans_do(trans, NULL, NULL, int ret = __bch2_trans_do(trans, NULL, NULL,
BTREE_INSERT_NOFAIL| BTREE_INSERT_NOFAIL|
BTREE_INSERT_LAZY_RW, BTREE_INSERT_LAZY_RW,
bch2_inode_write(trans, inode_iter, inode)); __write_inode(trans, inode, snapshot));
bch2_trans_iter_put(trans, inode_iter);
if (ret) if (ret)
bch_err(trans->c, "error in fsck: error %i updating inode", ret); bch_err(trans->c, "error in fsck: error %i updating inode", ret);
return ret; return ret;
...@@ -114,57 +129,101 @@ static int remove_dirent(struct btree_trans *trans, struct bpos pos) ...@@ -114,57 +129,101 @@ static int remove_dirent(struct btree_trans *trans, struct bpos pos)
return ret; return ret;
} }
static int __reattach_inode(struct btree_trans *trans, /* Get lost+found, create if it doesn't exist: */
struct bch_inode_unpacked *lostfound, static int lookup_lostfound(struct btree_trans *trans,
u64 inum) struct bch_inode_unpacked *lostfound)
{ {
struct bch_hash_info dir_hash = struct bch_fs *c = trans->c;
bch2_hash_info_init(trans->c, lostfound); struct bch_inode_unpacked root;
struct bch_inode_unpacked inode_u; struct bch_hash_info root_hash_info;
char name_buf[20]; struct qstr lostfound_str = QSTR("lost+found");
struct qstr name; u64 inum;
u64 dir_offset = 0;
u32 snapshot; u32 snapshot;
int ret; int ret;
snprintf(name_buf, sizeof(name_buf), "%llu", inum); ret = lookup_inode(trans, BCACHEFS_ROOT_INO, &root, &snapshot);
name = (struct qstr) QSTR(name_buf); if (ret && ret != -ENOENT)
ret = lookup_inode(trans, inum, &inode_u, &snapshot);
if (ret)
return ret; return ret;
if (S_ISDIR(inode_u.bi_mode)) { root_hash_info = bch2_hash_info_init(c, &root);
lostfound->bi_nlink++; inum = bch2_dirent_lookup(c, BCACHEFS_ROOT_INO, &root_hash_info,
&lostfound_str);
if (!inum) {
bch_notice(c, "creating lost+found");
goto create_lostfound;
}
ret = write_inode(trans, lostfound, U32_MAX); ret = lookup_inode(trans, inum, lostfound, &snapshot);
if (ret) if (ret && ret != -ENOENT) {
/*
* The check_dirents pass has already run, dangling dirents
* shouldn't exist here:
*/
bch_err(c, "error looking up lost+found: %i", ret);
return ret; return ret;
} }
ret = bch2_dirent_create(trans, lostfound->bi_inum, &dir_hash, if (ret == -ENOENT) {
mode_to_type(inode_u.bi_mode), create_lostfound:
&name, inum, &dir_offset, bch2_inode_init_early(c, lostfound);
BCH_HASH_SET_MUST_CREATE);
if (ret)
return ret;
inode_u.bi_dir = lostfound->bi_inum; ret = __bch2_trans_do(trans, NULL, NULL,
inode_u.bi_dir_offset = dir_offset; BTREE_INSERT_NOFAIL|
BTREE_INSERT_LAZY_RW,
bch2_create_trans(trans,
BCACHEFS_ROOT_INO, &root,
lostfound,
&lostfound_str,
0, 0, S_IFDIR|0700, 0, NULL, NULL));
if (ret)
bch_err(c, "error creating lost+found: %i", ret);
}
return write_inode(trans, &inode_u, U32_MAX); return 0;
} }
static int reattach_inode(struct btree_trans *trans, static int reattach_inode(struct btree_trans *trans,
struct bch_inode_unpacked *lostfound, struct bch_inode_unpacked *inode)
u64 inum)
{ {
int ret = __bch2_trans_do(trans, NULL, NULL, BTREE_INSERT_LAZY_RW, struct bch_hash_info dir_hash;
__reattach_inode(trans, lostfound, inum)); struct bch_inode_unpacked lostfound;
char name_buf[20];
struct qstr name;
u64 dir_offset = 0;
int ret;
ret = lookup_lostfound(trans, &lostfound);
if (ret) if (ret)
bch_err(trans->c, "error %i reattaching inode %llu", ret, inum); return ret;
if (S_ISDIR(inode->bi_mode)) {
lostfound.bi_nlink++;
ret = write_inode(trans, &lostfound, U32_MAX);
if (ret)
return ret; return ret;
}
dir_hash = bch2_hash_info_init(trans->c, &lostfound);
snprintf(name_buf, sizeof(name_buf), "%llu", inode->bi_inum);
name = (struct qstr) QSTR(name_buf);
ret = __bch2_trans_do(trans, NULL, NULL, BTREE_INSERT_LAZY_RW,
bch2_dirent_create(trans, lostfound.bi_inum, &dir_hash,
mode_to_type(inode->bi_mode),
&name, inode->bi_inum, &dir_offset,
BCH_HASH_SET_MUST_CREATE));
if (ret) {
bch_err(trans->c, "error %i reattaching inode %llu",
ret, inode->bi_inum);
return ret;
}
inode->bi_dir = lostfound.bi_inum;
inode->bi_dir_offset = dir_offset;
return write_inode(trans, inode, U32_MAX);
} }
static int remove_backpointer(struct btree_trans *trans, static int remove_backpointer(struct btree_trans *trans,
...@@ -931,58 +990,6 @@ static int check_root(struct bch_fs *c, struct bch_inode_unpacked *root_inode) ...@@ -931,58 +990,6 @@ static int check_root(struct bch_fs *c, struct bch_inode_unpacked *root_inode)
BTREE_INSERT_LAZY_RW); BTREE_INSERT_LAZY_RW);
} }
/* Get lost+found, create if it doesn't exist: */
static int check_lostfound(struct bch_fs *c,
struct bch_inode_unpacked *root_inode,
struct bch_inode_unpacked *lostfound_inode)
{
struct qstr lostfound = QSTR("lost+found");
struct bch_hash_info root_hash_info =
bch2_hash_info_init(c, root_inode);
u64 inum;
u32 snapshot;
int ret;
bch_verbose(c, "checking lost+found");
inum = bch2_dirent_lookup(c, BCACHEFS_ROOT_INO, &root_hash_info,
&lostfound);
if (!inum) {
bch_notice(c, "creating lost+found");
goto create_lostfound;
}
ret = bch2_trans_do(c, NULL, NULL, 0,
lookup_inode(&trans, inum, lostfound_inode, &snapshot));
if (ret && ret != -ENOENT)
return ret;
if (fsck_err_on(ret, c, "lost+found missing"))
goto create_lostfound;
if (fsck_err_on(!S_ISDIR(lostfound_inode->bi_mode), c,
"lost+found inode not a directory"))
goto create_lostfound;
return 0;
fsck_err:
return ret;
create_lostfound:
bch2_inode_init_early(c, lostfound_inode);
ret = bch2_trans_do(c, NULL, NULL,
BTREE_INSERT_NOFAIL|
BTREE_INSERT_LAZY_RW,
bch2_create_trans(&trans,
BCACHEFS_ROOT_INO, root_inode,
lostfound_inode, &lostfound,
0, 0, S_IFDIR|0700, 0, NULL, NULL));
if (ret)
bch_err(c, "error creating lost+found: %i", ret);
return ret;
}
struct pathbuf { struct pathbuf {
size_t nr; size_t nr;
size_t size; size_t size;
...@@ -1014,7 +1021,6 @@ static int path_down(struct pathbuf *p, u64 inum) ...@@ -1014,7 +1021,6 @@ static int path_down(struct pathbuf *p, u64 inum)
} }
static int check_path(struct btree_trans *trans, static int check_path(struct btree_trans *trans,
struct bch_inode_unpacked *lostfound,
struct pathbuf *p, struct pathbuf *p,
struct bch_inode_unpacked *inode) struct bch_inode_unpacked *inode)
{ {
...@@ -1038,7 +1044,7 @@ static int check_path(struct btree_trans *trans, ...@@ -1038,7 +1044,7 @@ static int check_path(struct btree_trans *trans,
inode->bi_nlink, inode->bi_nlink,
inode->bi_dir, inode->bi_dir,
inode->bi_dir_offset)) inode->bi_dir_offset))
ret = reattach_inode(trans, lostfound, inode->bi_inum); ret = reattach_inode(trans, inode);
break; break;
} }
ret = 0; ret = 0;
...@@ -1067,12 +1073,11 @@ static int check_path(struct btree_trans *trans, ...@@ -1067,12 +1073,11 @@ static int check_path(struct btree_trans *trans,
break; break;
} }
ret = reattach_inode(trans, lostfound, inode->bi_inum); ret = reattach_inode(trans, inode);
break; break;
} }
ret = lockrestart_do(trans, ret = lookup_inode(trans, inode->bi_dir, inode, &snapshot);
lookup_inode(trans, inode->bi_dir, inode, &snapshot));
if (ret) { if (ret) {
/* Should have been caught in dirents pass */ /* Should have been caught in dirents pass */
bch_err(c, "error looking up parent directory: %i", ret); bch_err(c, "error looking up parent directory: %i", ret);
...@@ -1090,8 +1095,7 @@ static int check_path(struct btree_trans *trans, ...@@ -1090,8 +1095,7 @@ static int check_path(struct btree_trans *trans,
* After check_dirents(), if an inode backpointer doesn't exist that means it's * After check_dirents(), if an inode backpointer doesn't exist that means it's
* unreachable: * unreachable:
*/ */
static int check_directory_structure(struct bch_fs *c, static int check_directory_structure(struct bch_fs *c)
struct bch_inode_unpacked *lostfound)
{ {
struct btree_trans trans; struct btree_trans trans;
struct btree_iter *iter; struct btree_iter *iter;
...@@ -1113,7 +1117,7 @@ static int check_directory_structure(struct bch_fs *c, ...@@ -1113,7 +1117,7 @@ static int check_directory_structure(struct bch_fs *c,
break; break;
} }
ret = check_path(&trans, lostfound, &path, &u); ret = check_path(&trans, &path, &u);
if (ret) if (ret)
break; break;
} }
...@@ -1190,7 +1194,6 @@ static int bch2_gc_walk_dirents(struct bch_fs *c, nlink_table *links, ...@@ -1190,7 +1194,6 @@ static int bch2_gc_walk_dirents(struct bch_fs *c, nlink_table *links,
} }
static int check_inode_nlink(struct btree_trans *trans, static int check_inode_nlink(struct btree_trans *trans,
struct bch_inode_unpacked *lostfound_inode,
struct btree_iter *iter, struct btree_iter *iter,
struct bkey_s_c_inode inode, struct bkey_s_c_inode inode,
unsigned nlink) unsigned nlink)
...@@ -1238,7 +1241,6 @@ static int check_inode_nlink(struct btree_trans *trans, ...@@ -1238,7 +1241,6 @@ static int check_inode_nlink(struct btree_trans *trans,
noinline_for_stack noinline_for_stack
static int bch2_gc_walk_inodes(struct bch_fs *c, static int bch2_gc_walk_inodes(struct bch_fs *c,
struct bch_inode_unpacked *lostfound_inode,
nlink_table *links, nlink_table *links,
u64 range_start, u64 range_end) u64 range_start, u64 range_end)
{ {
...@@ -1259,7 +1261,7 @@ static int bch2_gc_walk_inodes(struct bch_fs *c, ...@@ -1259,7 +1261,7 @@ static int bch2_gc_walk_inodes(struct bch_fs *c,
continue; continue;
link = genradix_ptr(links, k.k->p.offset - range_start); link = genradix_ptr(links, k.k->p.offset - range_start);
ret = check_inode_nlink(&trans, lostfound_inode, iter, ret = check_inode_nlink(&trans, iter,
bkey_s_c_to_inode(k), link ? link->count : 0); bkey_s_c_to_inode(k), link ? link->count : 0);
if (ret) if (ret)
break; break;
...@@ -1275,8 +1277,7 @@ static int bch2_gc_walk_inodes(struct bch_fs *c, ...@@ -1275,8 +1277,7 @@ static int bch2_gc_walk_inodes(struct bch_fs *c,
} }
noinline_for_stack noinline_for_stack
static int check_nlinks(struct bch_fs *c, static int check_nlinks(struct bch_fs *c)
struct bch_inode_unpacked *lostfound_inode)
{ {
nlink_table links; nlink_table links;
u64 this_iter_range_start, next_iter_range_start = 0; u64 this_iter_range_start, next_iter_range_start = 0;
...@@ -1296,7 +1297,7 @@ static int check_nlinks(struct bch_fs *c, ...@@ -1296,7 +1297,7 @@ static int check_nlinks(struct bch_fs *c,
if (ret) if (ret)
break; break;
ret = bch2_gc_walk_inodes(c, lostfound_inode, &links, ret = bch2_gc_walk_inodes(c, &links,
this_iter_range_start, this_iter_range_start,
next_iter_range_start); next_iter_range_start);
if (ret) if (ret)
...@@ -1316,16 +1317,15 @@ static int check_nlinks(struct bch_fs *c, ...@@ -1316,16 +1317,15 @@ static int check_nlinks(struct bch_fs *c,
*/ */
int bch2_fsck_full(struct bch_fs *c) int bch2_fsck_full(struct bch_fs *c)
{ {
struct bch_inode_unpacked root_inode, lostfound_inode; struct bch_inode_unpacked root_inode;
return check_inodes(c, true) ?: return check_inodes(c, true) ?:
check_extents(c) ?: check_extents(c) ?:
check_dirents(c) ?: check_dirents(c) ?:
check_xattrs(c) ?: check_xattrs(c) ?:
check_root(c, &root_inode) ?: check_root(c, &root_inode) ?:
check_lostfound(c, &root_inode, &lostfound_inode) ?: check_directory_structure(c) ?:
check_directory_structure(c, &lostfound_inode) ?: check_nlinks(c);
check_nlinks(c, &lostfound_inode);
} }
int bch2_fsck_walk_inodes_only(struct bch_fs *c) int bch2_fsck_walk_inodes_only(struct bch_fs *c)
......
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