bcachefs: some improvements to startup messages and options
authorKent Overstreet <kent.overstreet@gmail.com>
Wed, 17 Apr 2019 22:21:19 +0000 (18:21 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:21 +0000 (17:08 -0400)
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/chardev.c
fs/bcachefs/fs-ioctl.c
fs/bcachefs/fs.c
fs/bcachefs/fsck.c
fs/bcachefs/fsck.h
fs/bcachefs/opts.h
fs/bcachefs/recovery.c
fs/bcachefs/super.c
fs/bcachefs/super.h

index 2573376290bb791fc778131792c9e2146f04a94e..4d83310226486078ae9c350ec425c5af7d31c7ae 100644 (file)
@@ -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)
index b00d25b18ed4a82ea48c37742679e43da6a6fb19..4dca716217a61d651ae9f90577b9fbe7e02f4db5 100644 (file)
@@ -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;
 
index 7ae1b7520351a209825820fc5e38b8f79edc64d5..aac59b8a15eb6c7c14ca67876f7f09c758c14bec 100644 (file)
@@ -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;
        }
index ade3446d8dc3c069f1ea9993ae9dfbc2467b6d26..61569e4e1c77125b6a46c3038732894ec7b87991 100644 (file)
@@ -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;
 }
index 97460452e842866e83fd0fd09cb04692a8817590..9e4af02bde1e344b285da0c3bfa19934b23bd705 100644 (file)
@@ -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 */
index 53bf06e70cd5115e794d04c2b171a3c602bab5bc..a69bd3718ac4e336ed4858f3f4bf2e52a94de749 100644 (file)
@@ -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(),                                                   \
index a80de5d814d69dc1e1a231c091b68f4eeb54a19e..3f0eda9f5d0c170862c69d156c21f07533ea7fdc 100644 (file)
@@ -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)
index 8f25c1d9b8cb704e85e058896c5495c26d7251f3..654ccc611099261573c7b26bf90d7e8cce95a255 100644 (file)
@@ -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;
        }
 
index 92ef3e7c8dc2a4ebbfd822045dd7b06bea7a6cca..1b97c6115535a6dd570e7114ca6b3a6905829b8f 100644 (file)
@@ -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);