bcachefs: some improvements to startup messages and options
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
460651ee86
commit
619f5bee86
@ -158,7 +158,7 @@ static long bch2_ioctl_start(struct bch_fs *c, struct bch_ioctl_start arg)
|
||||
if (arg.flags || arg.pad)
|
||||
return -EINVAL;
|
||||
|
||||
return bch2_fs_start(c) ? -EIO : 0;
|
||||
return bch2_fs_start(c);
|
||||
}
|
||||
|
||||
static long bch2_ioctl_stop(struct bch_fs *c)
|
||||
|
@ -267,7 +267,8 @@ long bch2_fs_file_ioctl(struct file *file, unsigned cmd, unsigned long arg)
|
||||
|
||||
down_write(&sb->s_umount);
|
||||
sb->s_flags |= SB_RDONLY;
|
||||
bch2_fs_emergency_read_only(c);
|
||||
if (bch2_fs_emergency_read_only(c))
|
||||
bch_err(c, "emergency read only due to ioctl");
|
||||
up_write(&sb->s_umount);
|
||||
return 0;
|
||||
|
||||
|
@ -1834,12 +1834,15 @@ static struct dentry *bch2_mount(struct file_system_type *fs_type,
|
||||
|
||||
vinode = bch2_vfs_inode_get(c, BCACHEFS_ROOT_INO);
|
||||
if (IS_ERR(vinode)) {
|
||||
bch_err(c, "error mounting: error getting root inode %i",
|
||||
(int) PTR_ERR(vinode));
|
||||
ret = PTR_ERR(vinode);
|
||||
goto err_put_super;
|
||||
}
|
||||
|
||||
sb->s_root = d_make_root(vinode);
|
||||
if (!sb->s_root) {
|
||||
bch_err(c, "error mounting: error allocating root dentry");
|
||||
ret = -ENOMEM;
|
||||
goto err_put_super;
|
||||
}
|
||||
|
@ -499,8 +499,7 @@ retry:
|
||||
BTREE_INSERT_NOFAIL|
|
||||
BTREE_INSERT_LAZY_RW);
|
||||
if (ret) {
|
||||
bch_err(c, "error in fs gc: error %i "
|
||||
"updating inode", ret);
|
||||
bch_err(c, "error in fsck: error %i updating inode", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -1064,7 +1063,7 @@ static void inc_link(struct bch_fs *c, nlink_table *links,
|
||||
|
||||
link = genradix_ptr_alloc(links, inum - range_start, GFP_KERNEL);
|
||||
if (!link) {
|
||||
bch_verbose(c, "allocation failed during fs gc - will need another pass");
|
||||
bch_verbose(c, "allocation failed during fsck - will need another pass");
|
||||
*range_end = inum;
|
||||
return;
|
||||
}
|
||||
@ -1111,7 +1110,7 @@ static int bch2_gc_walk_dirents(struct bch_fs *c, nlink_table *links,
|
||||
}
|
||||
ret = bch2_trans_exit(&trans) ?: ret;
|
||||
if (ret)
|
||||
bch_err(c, "error in fs gc: btree error %i while walking dirents", ret);
|
||||
bch_err(c, "error in fsck: btree error %i while walking dirents", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1252,8 +1251,7 @@ static int check_inode(struct btree_trans *trans,
|
||||
|
||||
ret = bch2_inode_rm(c, u.bi_inum);
|
||||
if (ret)
|
||||
bch_err(c, "error in fs gc: error %i "
|
||||
"while deleting inode", ret);
|
||||
bch_err(c, "error in fsck: error %i while deleting inode", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1270,8 +1268,7 @@ static int check_inode(struct btree_trans *trans,
|
||||
|
||||
ret = bch2_inode_truncate(c, u.bi_inum, u.bi_size);
|
||||
if (ret) {
|
||||
bch_err(c, "error in fs gc: error %i "
|
||||
"truncating inode", ret);
|
||||
bch_err(c, "error in fsck: error %i truncating inode", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1296,8 +1293,7 @@ static int check_inode(struct btree_trans *trans,
|
||||
|
||||
sectors = bch2_count_inode_sectors(trans, u.bi_inum);
|
||||
if (sectors < 0) {
|
||||
bch_err(c, "error in fs gc: error %i "
|
||||
"recounting inode sectors",
|
||||
bch_err(c, "error in fsck: error %i recounting inode sectors",
|
||||
(int) sectors);
|
||||
return sectors;
|
||||
}
|
||||
@ -1317,7 +1313,7 @@ static int check_inode(struct btree_trans *trans,
|
||||
BTREE_INSERT_NOFAIL|
|
||||
BTREE_INSERT_LAZY_RW);
|
||||
if (ret && ret != -EINTR)
|
||||
bch_err(c, "error in fs gc: error %i "
|
||||
bch_err(c, "error in fsck: error %i "
|
||||
"updating inode", ret);
|
||||
}
|
||||
fsck_err:
|
||||
@ -1388,7 +1384,7 @@ fsck_err:
|
||||
bch2_trans_exit(&trans);
|
||||
|
||||
if (ret2)
|
||||
bch_err(c, "error in fs gc: btree error %i while walking inodes", ret2);
|
||||
bch_err(c, "error in fsck: btree error %i while walking inodes", ret2);
|
||||
|
||||
return ret ?: ret2;
|
||||
}
|
||||
@ -1429,8 +1425,33 @@ static int check_inode_nlinks(struct bch_fs *c,
|
||||
return ret;
|
||||
}
|
||||
|
||||
noinline_for_stack
|
||||
static int check_inodes_fast(struct bch_fs *c)
|
||||
/*
|
||||
* Checks for inconsistencies that shouldn't happen, unless we have a bug.
|
||||
* Doesn't fix them yet, mainly because they haven't yet been observed:
|
||||
*/
|
||||
int bch2_fsck_full(struct bch_fs *c)
|
||||
{
|
||||
struct bch_inode_unpacked root_inode, lostfound_inode;
|
||||
|
||||
return check_extents(c) ?:
|
||||
check_dirents(c) ?:
|
||||
check_xattrs(c) ?:
|
||||
check_root(c, &root_inode) ?:
|
||||
check_lostfound(c, &root_inode, &lostfound_inode) ?:
|
||||
check_directory_structure(c, &lostfound_inode) ?:
|
||||
check_inode_nlinks(c, &lostfound_inode);
|
||||
}
|
||||
|
||||
int bch2_fsck_inode_nlink(struct bch_fs *c)
|
||||
{
|
||||
struct bch_inode_unpacked root_inode, lostfound_inode;
|
||||
|
||||
return check_root(c, &root_inode) ?:
|
||||
check_lostfound(c, &root_inode, &lostfound_inode) ?:
|
||||
check_inode_nlinks(c, &lostfound_inode);
|
||||
}
|
||||
|
||||
int bch2_fsck_walk_inodes_only(struct bch_fs *c)
|
||||
{
|
||||
struct btree_trans trans;
|
||||
struct btree_iter *iter;
|
||||
@ -1461,69 +1482,3 @@ static int check_inodes_fast(struct bch_fs *c)
|
||||
|
||||
return bch2_trans_exit(&trans) ?: ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks for inconsistencies that shouldn't happen, unless we have a bug.
|
||||
* Doesn't fix them yet, mainly because they haven't yet been observed:
|
||||
*/
|
||||
static int bch2_fsck_full(struct bch_fs *c)
|
||||
{
|
||||
struct bch_inode_unpacked root_inode, lostfound_inode;
|
||||
int ret;
|
||||
|
||||
bch_verbose(c, "starting fsck:");
|
||||
ret = check_extents(c) ?:
|
||||
check_dirents(c) ?:
|
||||
check_xattrs(c) ?:
|
||||
check_root(c, &root_inode) ?:
|
||||
check_lostfound(c, &root_inode, &lostfound_inode) ?:
|
||||
check_directory_structure(c, &lostfound_inode) ?:
|
||||
check_inode_nlinks(c, &lostfound_inode);
|
||||
|
||||
bch2_flush_fsck_errs(c);
|
||||
bch_verbose(c, "fsck done");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bch2_fsck_inode_nlink(struct bch_fs *c)
|
||||
{
|
||||
struct bch_inode_unpacked root_inode, lostfound_inode;
|
||||
int ret;
|
||||
|
||||
bch_verbose(c, "checking inode link counts:");
|
||||
ret = check_root(c, &root_inode) ?:
|
||||
check_lostfound(c, &root_inode, &lostfound_inode) ?:
|
||||
check_inode_nlinks(c, &lostfound_inode);
|
||||
|
||||
bch2_flush_fsck_errs(c);
|
||||
bch_verbose(c, "done");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bch2_fsck_walk_inodes_only(struct bch_fs *c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
bch_verbose(c, "walking inodes:");
|
||||
ret = check_inodes_fast(c);
|
||||
|
||||
bch2_flush_fsck_errs(c);
|
||||
bch_verbose(c, "done");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bch2_fsck(struct bch_fs *c)
|
||||
{
|
||||
if (c->opts.fsck)
|
||||
return bch2_fsck_full(c);
|
||||
|
||||
if (c->sb.clean)
|
||||
return 0;
|
||||
|
||||
return c->sb.features & (1 << BCH_FEATURE_ATOMIC_NLINK)
|
||||
? bch2_fsck_walk_inodes_only(c)
|
||||
: bch2_fsck_inode_nlink(c);
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
#ifndef _BCACHEFS_FSCK_H
|
||||
#define _BCACHEFS_FSCK_H
|
||||
|
||||
int bch2_fsck(struct bch_fs *);
|
||||
int bch2_fsck_full(struct bch_fs *);
|
||||
int bch2_fsck_inode_nlink(struct bch_fs *);
|
||||
int bch2_fsck_walk_inodes_only(struct bch_fs *);
|
||||
|
||||
#endif /* _BCACHEFS_FSCK_H */
|
||||
|
@ -233,16 +233,11 @@ enum opt_type {
|
||||
NO_SB_OPT, false, \
|
||||
NULL, "Super read only mode - no writes at all will be issued,\n"\
|
||||
"even if we have to replay the journal") \
|
||||
x(noreplay, u8, \
|
||||
OPT_MOUNT, \
|
||||
OPT_BOOL(), \
|
||||
NO_SB_OPT, false, \
|
||||
NULL, "Don't replay the journal (only for internal tools)")\
|
||||
x(norecovery, u8, \
|
||||
OPT_MOUNT, \
|
||||
OPT_BOOL(), \
|
||||
NO_SB_OPT, false, \
|
||||
NULL, NULL) \
|
||||
NULL, "Don't replay the journal") \
|
||||
x(noexcl, u8, \
|
||||
OPT_MOUNT, \
|
||||
OPT_BOOL(), \
|
||||
|
@ -714,8 +714,8 @@ int bch2_fs_recovery(struct bch_fs *c)
|
||||
|
||||
if (!c->sb.clean) {
|
||||
ret = bch2_journal_seq_blacklist_add(c,
|
||||
journal_seq,
|
||||
journal_seq + 4);
|
||||
journal_seq,
|
||||
journal_seq + 4);
|
||||
if (ret) {
|
||||
bch_err(c, "error creating new journal seq blacklist entry");
|
||||
goto err;
|
||||
@ -763,7 +763,7 @@ int bch2_fs_recovery(struct bch_fs *c)
|
||||
* journal; after an unclean shutdown we have to walk all
|
||||
* pointers to metadata:
|
||||
*/
|
||||
bch_verbose(c, "starting metadata mark and sweep:");
|
||||
bch_info(c, "starting metadata mark and sweep");
|
||||
err = "error in mark and sweep";
|
||||
ret = bch2_gc(c, NULL, true, true);
|
||||
if (ret)
|
||||
@ -774,7 +774,7 @@ int bch2_fs_recovery(struct bch_fs *c)
|
||||
if (c->opts.fsck ||
|
||||
!(c->sb.compat & (1ULL << BCH_COMPAT_FEAT_ALLOC_INFO)) ||
|
||||
test_bit(BCH_FS_REBUILD_REPLICAS, &c->flags)) {
|
||||
bch_verbose(c, "starting mark and sweep:");
|
||||
bch_info(c, "starting mark and sweep");
|
||||
err = "error in mark and sweep";
|
||||
ret = bch2_gc(c, &journal_keys, true, false);
|
||||
if (ret)
|
||||
@ -792,36 +792,63 @@ int bch2_fs_recovery(struct bch_fs *c)
|
||||
if (c->sb.encryption_type && !c->sb.clean)
|
||||
atomic64_add(1 << 16, &c->key_version);
|
||||
|
||||
if (c->opts.noreplay)
|
||||
if (c->opts.norecovery)
|
||||
goto out;
|
||||
|
||||
bch_verbose(c, "starting journal replay:");
|
||||
bch_verbose(c, "starting journal replay");
|
||||
err = "journal replay failed";
|
||||
ret = bch2_journal_replay(c, journal_keys);
|
||||
if (ret)
|
||||
goto err;
|
||||
bch_verbose(c, "journal replay done");
|
||||
|
||||
bch_verbose(c, "writing allocation info:");
|
||||
err = "error writing out alloc info";
|
||||
ret = bch2_stripes_write(c, BTREE_INSERT_LAZY_RW, &wrote) ?:
|
||||
bch2_alloc_write(c, BTREE_INSERT_LAZY_RW, &wrote);
|
||||
if (ret) {
|
||||
bch_err(c, "error writing alloc info");
|
||||
goto err;
|
||||
if (!c->opts.nochanges) {
|
||||
/*
|
||||
* note that even when filesystem was clean there might be work
|
||||
* to do here, if we ran gc (because of fsck) which recalculated
|
||||
* oldest_gen:
|
||||
*/
|
||||
bch_verbose(c, "writing allocation info");
|
||||
err = "error writing out alloc info";
|
||||
ret = bch2_stripes_write(c, BTREE_INSERT_LAZY_RW, &wrote) ?:
|
||||
bch2_alloc_write(c, BTREE_INSERT_LAZY_RW, &wrote);
|
||||
if (ret) {
|
||||
bch_err(c, "error writing alloc info");
|
||||
goto err;
|
||||
}
|
||||
bch_verbose(c, "alloc write done");
|
||||
}
|
||||
bch_verbose(c, "alloc write done");
|
||||
|
||||
if (c->opts.norecovery)
|
||||
goto out;
|
||||
if (!c->sb.clean) {
|
||||
if (!(c->sb.features & (1 << BCH_FEATURE_ATOMIC_NLINK))) {
|
||||
bch_info(c, "checking inode link counts");
|
||||
err = "error in recovery";
|
||||
ret = bch2_fsck_inode_nlink(c);
|
||||
if (ret)
|
||||
goto err;
|
||||
bch_verbose(c, "check inodes done");
|
||||
|
||||
err = "error in fsck";
|
||||
ret = bch2_fsck(c);
|
||||
if (ret)
|
||||
goto err;
|
||||
} else {
|
||||
bch_verbose(c, "checking for deleted inodes");
|
||||
err = "error in recovery";
|
||||
ret = bch2_fsck_walk_inodes_only(c);
|
||||
if (ret)
|
||||
goto err;
|
||||
bch_verbose(c, "check inodes done");
|
||||
}
|
||||
}
|
||||
|
||||
if (c->opts.fsck) {
|
||||
bch_info(c, "starting fsck");
|
||||
err = "error in fsck";
|
||||
ret = bch2_fsck_full(c);
|
||||
if (ret)
|
||||
goto err;
|
||||
bch_verbose(c, "fsck done");
|
||||
}
|
||||
|
||||
if (enabled_qtypes(c)) {
|
||||
bch_verbose(c, "reading quotas:");
|
||||
bch_verbose(c, "reading quotas");
|
||||
ret = bch2_fs_quota_read(c);
|
||||
if (ret)
|
||||
goto err;
|
||||
@ -857,14 +884,18 @@ int bch2_fs_recovery(struct bch_fs *c)
|
||||
c->journal_seq_blacklist_table->nr > 128)
|
||||
queue_work(system_long_wq, &c->journal_seq_blacklist_gc_work);
|
||||
out:
|
||||
ret = 0;
|
||||
err:
|
||||
fsck_err:
|
||||
bch2_flush_fsck_errs(c);
|
||||
journal_keys_free(&journal_keys);
|
||||
journal_entries_free(&journal_entries);
|
||||
kfree(clean);
|
||||
if (ret)
|
||||
bch_err(c, "Error in recovery: %s (%i)", err, ret);
|
||||
else
|
||||
bch_verbose(c, "ret %i", ret);
|
||||
return ret;
|
||||
err:
|
||||
fsck_err:
|
||||
bch_err(c, "Error in recovery: %s (%i)", err, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
int bch2_fs_initialize(struct bch_fs *c)
|
||||
|
@ -305,7 +305,6 @@ void bch2_fs_read_only(struct bch_fs *c)
|
||||
!test_bit(BCH_FS_ERROR, &c->flags) &&
|
||||
!test_bit(BCH_FS_EMERGENCY_RO, &c->flags) &&
|
||||
test_bit(BCH_FS_STARTED, &c->flags) &&
|
||||
!c->opts.noreplay &&
|
||||
!c->opts.norecovery)
|
||||
bch2_fs_mark_clean(c);
|
||||
|
||||
@ -379,9 +378,14 @@ int __bch2_fs_read_write(struct bch_fs *c, bool early)
|
||||
if (test_bit(BCH_FS_RW, &c->flags))
|
||||
return 0;
|
||||
|
||||
if (c->opts.nochanges ||
|
||||
c->opts.noreplay)
|
||||
return -EINVAL;
|
||||
/*
|
||||
* nochanges is used for fsck -n mode - we have to allow going rw
|
||||
* during recovery for that to work:
|
||||
*/
|
||||
if (c->opts.norecovery ||
|
||||
(c->opts.nochanges &&
|
||||
(!early || c->opts.read_only)))
|
||||
return -EROFS;
|
||||
|
||||
ret = bch2_fs_mark_dirty(c);
|
||||
if (ret)
|
||||
@ -694,10 +698,6 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
|
||||
c->block_bits = ilog2(c->opts.block_size);
|
||||
c->btree_foreground_merge_threshold = BTREE_FOREGROUND_MERGE_THRESHOLD(c);
|
||||
|
||||
c->opts.nochanges |= c->opts.noreplay;
|
||||
c->opts.read_only |= c->opts.nochanges;
|
||||
c->opts.read_only |= c->opts.noreplay;
|
||||
|
||||
if (bch2_fs_init_fault("fs_alloc"))
|
||||
goto err;
|
||||
|
||||
@ -776,7 +776,41 @@ err:
|
||||
goto out;
|
||||
}
|
||||
|
||||
const char *bch2_fs_start(struct bch_fs *c)
|
||||
noinline_for_stack
|
||||
static void print_mount_opts(struct bch_fs *c)
|
||||
{
|
||||
enum bch_opt_id i;
|
||||
char buf[512];
|
||||
struct printbuf p = PBUF(buf);
|
||||
bool first = true;
|
||||
|
||||
strcpy(buf, "(null)");
|
||||
|
||||
if (c->opts.read_only) {
|
||||
pr_buf(&p, "ro");
|
||||
first = false;
|
||||
}
|
||||
|
||||
for (i = 0; i < bch2_opts_nr; i++) {
|
||||
const struct bch_option *opt = &bch2_opt_table[i];
|
||||
u64 v = bch2_opt_get_by_id(&c->opts, i);
|
||||
|
||||
if (!(opt->mode & OPT_MOUNT))
|
||||
continue;
|
||||
|
||||
if (v == bch2_opt_get_by_id(&bch2_opts_default, i))
|
||||
continue;
|
||||
|
||||
if (!first)
|
||||
pr_buf(&p, ",");
|
||||
first = false;
|
||||
bch2_opt_to_text(&p, c, opt, v, OPT_SHOW_MOUNT_STYLE);
|
||||
}
|
||||
|
||||
bch_info(c, "mounted with opts: %s", buf);
|
||||
}
|
||||
|
||||
int bch2_fs_start(struct bch_fs *c)
|
||||
{
|
||||
const char *err = "cannot allocate memory";
|
||||
struct bch_sb_field_members *mi;
|
||||
@ -815,26 +849,27 @@ const char *bch2_fs_start(struct bch_fs *c)
|
||||
goto err;
|
||||
|
||||
err = "dynamic fault";
|
||||
ret = -EINVAL;
|
||||
if (bch2_fs_init_fault("fs_start"))
|
||||
goto err;
|
||||
|
||||
if (c->opts.read_only) {
|
||||
if (c->opts.read_only || c->opts.nochanges) {
|
||||
bch2_fs_read_only(c);
|
||||
} else {
|
||||
if (!test_bit(BCH_FS_RW, &c->flags)
|
||||
? bch2_fs_read_write(c)
|
||||
: bch2_fs_read_write_late(c)) {
|
||||
err = "error going read write";
|
||||
err = "error going read write";
|
||||
ret = !test_bit(BCH_FS_RW, &c->flags)
|
||||
? bch2_fs_read_write(c)
|
||||
: bch2_fs_read_write_late(c);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
set_bit(BCH_FS_STARTED, &c->flags);
|
||||
|
||||
err = NULL;
|
||||
print_mount_opts(c);
|
||||
ret = 0;
|
||||
out:
|
||||
mutex_unlock(&c->state_lock);
|
||||
return err;
|
||||
return ret;
|
||||
err:
|
||||
switch (ret) {
|
||||
case BCH_FSCK_ERRORS_NOT_FIXED:
|
||||
@ -862,7 +897,7 @@ err:
|
||||
break;
|
||||
}
|
||||
|
||||
BUG_ON(!err);
|
||||
BUG_ON(!ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -1789,9 +1824,9 @@ struct bch_fs *bch2_fs_open(char * const *devices, unsigned nr_devices,
|
||||
goto err_print;
|
||||
|
||||
if (!c->opts.nostart) {
|
||||
err = bch2_fs_start(c);
|
||||
if (err)
|
||||
goto err_print;
|
||||
ret = bch2_fs_start(c);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
out:
|
||||
kfree(sb);
|
||||
@ -1818,6 +1853,7 @@ static const char *__bch2_fs_open_incremental(struct bch_sb_handle *sb,
|
||||
const char *err;
|
||||
struct bch_fs *c;
|
||||
bool allocated_fs = false;
|
||||
int ret;
|
||||
|
||||
err = bch2_sb_validate(sb);
|
||||
if (err)
|
||||
@ -1850,8 +1886,9 @@ static const char *__bch2_fs_open_incremental(struct bch_sb_handle *sb,
|
||||
mutex_unlock(&c->sb_lock);
|
||||
|
||||
if (!c->opts.nostart && bch2_fs_may_start(c)) {
|
||||
err = bch2_fs_start(c);
|
||||
if (err)
|
||||
err = "error starting filesystem";
|
||||
ret = bch2_fs_start(c);
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,7 @@ int bch2_fs_read_write_early(struct bch_fs *);
|
||||
|
||||
void bch2_fs_stop(struct bch_fs *);
|
||||
|
||||
const char *bch2_fs_start(struct bch_fs *);
|
||||
int bch2_fs_start(struct bch_fs *);
|
||||
struct bch_fs *bch2_fs_open(char * const *, unsigned, struct bch_opts);
|
||||
const char *bch2_fs_open_incremental(const char *path);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user