diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2019-04-17 18:21:19 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:08:21 -0400 |
commit | 619f5bee86b558e0dad91c3759b90652cd5f55d2 (patch) | |
tree | 500b0250cf8c39b6419a4af5535fde28f2837a1a | |
parent | 460651ee86b2d2e0cf1a70a15a07031213e27181 (diff) |
bcachefs: some improvements to startup messages and options
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/chardev.c | 2 | ||||
-rw-r--r-- | fs/bcachefs/fs-ioctl.c | 3 | ||||
-rw-r--r-- | fs/bcachefs/fs.c | 3 | ||||
-rw-r--r-- | fs/bcachefs/fsck.c | 115 | ||||
-rw-r--r-- | fs/bcachefs/fsck.h | 4 | ||||
-rw-r--r-- | fs/bcachefs/opts.h | 7 | ||||
-rw-r--r-- | fs/bcachefs/recovery.c | 81 | ||||
-rw-r--r-- | fs/bcachefs/super.c | 85 | ||||
-rw-r--r-- | fs/bcachefs/super.h | 2 |
9 files changed, 163 insertions, 139 deletions
diff --git a/fs/bcachefs/chardev.c b/fs/bcachefs/chardev.c index 2573376290bb..4d8331022648 100644 --- a/fs/bcachefs/chardev.c +++ b/fs/bcachefs/chardev.c @@ -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) diff --git a/fs/bcachefs/fs-ioctl.c b/fs/bcachefs/fs-ioctl.c index b00d25b18ed4..4dca716217a6 100644 --- a/fs/bcachefs/fs-ioctl.c +++ b/fs/bcachefs/fs-ioctl.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; diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c index 7ae1b7520351..aac59b8a15eb 100644 --- a/fs/bcachefs/fs.c +++ b/fs/bcachefs/fs.c @@ -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; } diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c index ade3446d8dc3..61569e4e1c77 100644 --- a/fs/bcachefs/fsck.c +++ b/fs/bcachefs/fsck.c @@ -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,101 +1425,60 @@ static int check_inode_nlinks(struct bch_fs *c, return ret; } -noinline_for_stack -static int check_inodes_fast(struct bch_fs *c) -{ - struct btree_trans trans; - struct btree_iter *iter; - struct bkey_s_c k; - struct bkey_s_c_inode inode; - int ret; - - bch2_trans_init(&trans, c); - bch2_trans_preload_iters(&trans); - - for_each_btree_key(&trans, iter, BTREE_ID_INODES, POS_MIN, 0, k, ret) { - if (k.k->type != KEY_TYPE_inode) - continue; - - inode = bkey_s_c_to_inode(k); - - if (inode.v->bi_flags & - (BCH_INODE_I_SIZE_DIRTY| - BCH_INODE_I_SECTORS_DIRTY| - BCH_INODE_UNLINKED)) { - ret = check_inode(&trans, NULL, iter, inode, NULL); - BUG_ON(ret == -EINTR); - if (ret) - break; - } - } - BUG_ON(ret == -EINTR); - - 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) +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) ?: + 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); - - bch2_flush_fsck_errs(c); - bch_verbose(c, "fsck done"); - - return ret; } -static int bch2_fsck_inode_nlink(struct bch_fs *c) +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) ?: + return 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 bch2_fsck_walk_inodes_only(struct bch_fs *c) { + struct btree_trans trans; + struct btree_iter *iter; + struct bkey_s_c k; + struct bkey_s_c_inode inode; int ret; - bch_verbose(c, "walking inodes:"); - ret = check_inodes_fast(c); - - bch2_flush_fsck_errs(c); - bch_verbose(c, "done"); + bch2_trans_init(&trans, c); + bch2_trans_preload_iters(&trans); - return ret; -} + for_each_btree_key(&trans, iter, BTREE_ID_INODES, POS_MIN, 0, k, ret) { + if (k.k->type != KEY_TYPE_inode) + continue; -int bch2_fsck(struct bch_fs *c) -{ - if (c->opts.fsck) - return bch2_fsck_full(c); + inode = bkey_s_c_to_inode(k); - if (c->sb.clean) - return 0; + if (inode.v->bi_flags & + (BCH_INODE_I_SIZE_DIRTY| + BCH_INODE_I_SECTORS_DIRTY| + BCH_INODE_UNLINKED)) { + ret = check_inode(&trans, NULL, iter, inode, NULL); + BUG_ON(ret == -EINTR); + if (ret) + break; + } + } + BUG_ON(ret == -EINTR); - return c->sb.features & (1 << BCH_FEATURE_ATOMIC_NLINK) - ? bch2_fsck_walk_inodes_only(c) - : bch2_fsck_inode_nlink(c); + return bch2_trans_exit(&trans) ?: ret; } diff --git a/fs/bcachefs/fsck.h b/fs/bcachefs/fsck.h index 97460452e842..9e4af02bde1e 100644 --- a/fs/bcachefs/fsck.h +++ b/fs/bcachefs/fsck.h @@ -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 */ diff --git a/fs/bcachefs/opts.h b/fs/bcachefs/opts.h index 53bf06e70cd5..a69bd3718ac4 100644 --- a/fs/bcachefs/opts.h +++ b/fs/bcachefs/opts.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(), \ diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c index a80de5d814d6..3f0eda9f5d0c 100644 --- a/fs/bcachefs/recovery.c +++ b/fs/bcachefs/recovery.c @@ -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) diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c index 8f25c1d9b8cb..654ccc611099 100644 --- a/fs/bcachefs/super.c +++ b/fs/bcachefs/super.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; } diff --git a/fs/bcachefs/super.h b/fs/bcachefs/super.h index 92ef3e7c8dc2..1b97c6115535 100644 --- a/fs/bcachefs/super.h +++ b/fs/bcachefs/super.h @@ -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); |