]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/recovery.c
Update bcachefs sources to df6415fefb27 bcachefs: Fixes for rust bindgen
[bcachefs-tools-debian] / libbcachefs / recovery.c
index 130274b195e21621c391ad89d965440cf077816c..62ec1df6a312789d97f986399983724036911f78 100644 (file)
@@ -145,12 +145,11 @@ static int bch2_journal_replay(struct bch_fs *c)
 {
        struct journal_keys *keys = &c->journal_keys;
        DARRAY(struct journal_key *) keys_sorted = { 0 };
-       struct journal_key **kp;
        struct journal *j = &c->journal;
        u64 start_seq   = c->journal_replay_seq_start;
        u64 end_seq     = c->journal_replay_seq_start;
        struct btree_trans *trans = bch2_trans_get(c);
-       int ret;
+       int ret = 0;
 
        if (keys->nr) {
                ret = bch2_journal_log_msg(c, "Starting journal replay (%zu keys in entries %llu-%llu)",
@@ -159,20 +158,24 @@ static int bch2_journal_replay(struct bch_fs *c)
                        goto err;
        }
 
+       BUG_ON(!atomic_read(&keys->ref));
+
        /*
         * First, attempt to replay keys in sorted order. This is more
-        * efficient, but some might fail if that would cause a journal
-        * deadlock.
+        * efficient - better locality of btree access -  but some might fail if
+        * that would cause a journal deadlock.
         */
        for (size_t i = 0; i < keys->nr; i++) {
                cond_resched();
 
                struct journal_key *k = keys->d + i;
 
-               ret = commit_do(trans, NULL, NULL,
-                               BCH_TRANS_COMMIT_no_enospc|
-                               BCH_TRANS_COMMIT_journal_reclaim|
-                               (!k->allocated ? BCH_TRANS_COMMIT_no_journal_res : 0),
+               /* Skip fastpath if we're low on space in the journal */
+               ret = c->journal.watermark ? -1 :
+                       commit_do(trans, NULL, NULL,
+                                 BCH_TRANS_COMMIT_no_enospc|
+                                 BCH_TRANS_COMMIT_journal_reclaim|
+                                 (!k->allocated ? BCH_TRANS_COMMIT_no_journal_res : 0),
                             bch2_journal_replay_key(trans, k));
                BUG_ON(!ret && !k->overwritten);
                if (ret) {
@@ -211,17 +214,22 @@ static int bch2_journal_replay(struct bch_fs *c)
                BUG_ON(!k->overwritten);
        }
 
+       /*
+        * We need to put our btree_trans before calling flush_all_pins(), since
+        * that will use a btree_trans internally
+        */
        bch2_trans_put(trans);
        trans = NULL;
 
+       if (!c->opts.keep_journal)
+               bch2_journal_keys_put_initial(c);
+
        replay_now_at(j, j->replay_journal_seq_end);
        j->replay_journal_seq = 0;
 
        bch2_journal_set_replay_done(j);
-       bch2_journal_flush_all_pins(j);
-       ret = bch2_journal_error(j);
 
-       if (keys->nr && !ret)
+       if (keys->nr)
                bch2_journal_log_msg(c, "journal replay finished");
 err:
        if (trans)
@@ -295,8 +303,6 @@ static int journal_replay_entry_early(struct bch_fs *c,
                struct bch_dev *ca = bch_dev_bkey_exists(c, le32_to_cpu(u->dev));
                unsigned i, nr_types = jset_entry_dev_usage_nr_types(u);
 
-               ca->usage_base->buckets_ec              = le64_to_cpu(u->buckets_ec);
-
                for (i = 0; i < min_t(unsigned, nr_types, BCH_DATA_NR); i++) {
                        ca->usage_base->d[i].buckets    = le64_to_cpu(u->d[i].buckets);
                        ca->usage_base->d[i].sectors    = le64_to_cpu(u->d[i].sectors);
@@ -337,14 +343,11 @@ static int journal_replay_entry_early(struct bch_fs *c,
 static int journal_replay_early(struct bch_fs *c,
                                struct bch_sb_field_clean *clean)
 {
-       struct jset_entry *entry;
-       int ret;
-
        if (clean) {
-               for (entry = clean->start;
+               for (struct jset_entry *entry = clean->start;
                     entry != vstruct_end(&clean->field);
                     entry = vstruct_next(entry)) {
-                       ret = journal_replay_entry_early(c, entry);
+                       int ret = journal_replay_entry_early(c, entry);
                        if (ret)
                                return ret;
                }
@@ -359,7 +362,7 @@ static int journal_replay_early(struct bch_fs *c,
                                continue;
 
                        vstruct_for_each(&i->j, entry) {
-                               ret = journal_replay_entry_early(c, entry);
+                               int ret = journal_replay_entry_early(c, entry);
                                if (ret)
                                        return ret;
                        }
@@ -455,8 +458,7 @@ static int bch2_initialize_subvolumes(struct bch_fs *c)
        ret =   bch2_btree_insert(c, BTREE_ID_snapshot_trees,   &root_tree.k_i, NULL, 0) ?:
                bch2_btree_insert(c, BTREE_ID_snapshots,        &root_snapshot.k_i, NULL, 0) ?:
                bch2_btree_insert(c, BTREE_ID_subvolumes,       &root_volume.k_i, NULL, 0);
-       if (ret)
-               bch_err_fn(c, ret);
+       bch_err_fn(c, ret);
        return ret;
 }
 
@@ -496,8 +498,7 @@ static int bch2_fs_upgrade_for_subvolumes(struct bch_fs *c)
 {
        int ret = bch2_trans_do(c, NULL, NULL, BCH_TRANS_COMMIT_lazy_rw,
                                __bch2_fs_upgrade_for_subvolumes(trans));
-       if (ret)
-               bch_err_fn(c, ret);
+       bch_err_fn(c, ret);
        return ret;
 }
 
@@ -525,8 +526,9 @@ static int bch2_set_may_go_rw(struct bch_fs *c)
        move_gap(keys->d, keys->nr, keys->size, keys->gap, keys->nr);
        keys->gap = keys->nr;
 
-       set_bit(BCH_FS_MAY_GO_RW, &c->flags);
-       if (keys->nr)
+       set_bit(BCH_FS_may_go_rw, &c->flags);
+
+       if (keys->nr || c->opts.fsck || !c->sb.clean)
                return bch2_fs_read_write_early(c);
        return 0;
 }
@@ -627,7 +629,7 @@ u64 bch2_fsck_recovery_passes(void)
 
 static bool should_run_recovery_pass(struct bch_fs *c, enum bch_recovery_pass pass)
 {
-       struct recovery_pass_fn *p = recovery_pass_fns + c->curr_recovery_pass;
+       struct recovery_pass_fn *p = recovery_pass_fns + pass;
 
        if (c->opts.norecovery && pass > BCH_RECOVERY_PASS_snapshots_read)
                return false;
@@ -644,39 +646,59 @@ static bool should_run_recovery_pass(struct bch_fs *c, enum bch_recovery_pass pa
 
 static int bch2_run_recovery_pass(struct bch_fs *c, enum bch_recovery_pass pass)
 {
+       struct recovery_pass_fn *p = recovery_pass_fns + pass;
        int ret;
 
-       c->curr_recovery_pass = pass;
+       if (!(p->when & PASS_SILENT))
+               bch2_print(c, KERN_INFO bch2_log_msg(c, "%s..."),
+                          bch2_recovery_passes[pass]);
+       ret = p->fn(c);
+       if (ret)
+               return ret;
+       if (!(p->when & PASS_SILENT))
+               bch2_print(c, KERN_CONT " done\n");
 
-       if (should_run_recovery_pass(c, pass)) {
-               struct recovery_pass_fn *p = recovery_pass_fns + pass;
+       return 0;
+}
 
-               if (!(p->when & PASS_SILENT))
-                       printk(KERN_INFO bch2_log_msg(c, "%s..."),
-                              bch2_recovery_passes[pass]);
-               ret = p->fn(c);
-               if (ret)
-                       return ret;
-               if (!(p->when & PASS_SILENT))
-                       printk(KERN_CONT " done\n");
+static int bch2_run_recovery_passes(struct bch_fs *c)
+{
+       int ret = 0;
+
+       while (c->curr_recovery_pass < ARRAY_SIZE(recovery_pass_fns)) {
+               if (should_run_recovery_pass(c, c->curr_recovery_pass)) {
+                       ret = bch2_run_recovery_pass(c, c->curr_recovery_pass);
+                       if (bch2_err_matches(ret, BCH_ERR_restart_recovery))
+                               continue;
+                       if (ret)
+                               break;
 
-               c->recovery_passes_complete |= BIT_ULL(pass);
+                       c->recovery_passes_complete |= BIT_ULL(c->curr_recovery_pass);
+               }
+               c->curr_recovery_pass++;
+               c->recovery_pass_done = max(c->recovery_pass_done, c->curr_recovery_pass);
        }
 
-       return 0;
+       return ret;
 }
 
-static int bch2_run_recovery_passes(struct bch_fs *c)
+int bch2_run_online_recovery_passes(struct bch_fs *c)
 {
        int ret = 0;
 
-       while (c->curr_recovery_pass < ARRAY_SIZE(recovery_pass_fns)) {
-               ret = bch2_run_recovery_pass(c, c->curr_recovery_pass);
-               if (bch2_err_matches(ret, BCH_ERR_restart_recovery))
+       for (unsigned i = 0; i < ARRAY_SIZE(recovery_pass_fns); i++) {
+               struct recovery_pass_fn *p = recovery_pass_fns + i;
+
+               if (!(p->when & PASS_ONLINE))
                        continue;
+
+               ret = bch2_run_recovery_pass(c, i);
+               if (bch2_err_matches(ret, BCH_ERR_restart_recovery)) {
+                       i = c->curr_recovery_pass;
+                       continue;
+               }
                if (ret)
                        break;
-               c->curr_recovery_pass++;
        }
 
        return ret;
@@ -871,11 +893,13 @@ use_clean:
 
        /* If we fixed errors, verify that fs is actually clean now: */
        if (IS_ENABLED(CONFIG_BCACHEFS_DEBUG) &&
-           test_bit(BCH_FS_ERRORS_FIXED, &c->flags) &&
-           !test_bit(BCH_FS_ERRORS_NOT_FIXED, &c->flags) &&
-           !test_bit(BCH_FS_ERROR, &c->flags)) {
+           test_bit(BCH_FS_errors_fixed, &c->flags) &&
+           !test_bit(BCH_FS_errors_not_fixed, &c->flags) &&
+           !test_bit(BCH_FS_error, &c->flags)) {
+               bch2_flush_fsck_errs(c);
+
                bch_info(c, "Fixed errors, running fsck a second time to verify fs is clean");
-               clear_bit(BCH_FS_ERRORS_FIXED, &c->flags);
+               clear_bit(BCH_FS_errors_fixed, &c->flags);
 
                c->curr_recovery_pass = BCH_RECOVERY_PASS_check_alloc_info;
 
@@ -883,13 +907,13 @@ use_clean:
                if (ret)
                        goto err;
 
-               if (test_bit(BCH_FS_ERRORS_FIXED, &c->flags) ||
-                   test_bit(BCH_FS_ERRORS_NOT_FIXED, &c->flags)) {
+               if (test_bit(BCH_FS_errors_fixed, &c->flags) ||
+                   test_bit(BCH_FS_errors_not_fixed, &c->flags)) {
                        bch_err(c, "Second fsck run was not clean");
-                       set_bit(BCH_FS_ERRORS_NOT_FIXED, &c->flags);
+                       set_bit(BCH_FS_errors_not_fixed, &c->flags);
                }
 
-               set_bit(BCH_FS_ERRORS_FIXED, &c->flags);
+               set_bit(BCH_FS_errors_fixed, &c->flags);
        }
 
        if (enabled_qtypes(c)) {
@@ -906,14 +930,14 @@ use_clean:
                write_sb = true;
        }
 
-       if (!test_bit(BCH_FS_ERROR, &c->flags)) {
+       if (!test_bit(BCH_FS_error, &c->flags)) {
                c->disk_sb.sb->compat[0] |= cpu_to_le64(1ULL << BCH_COMPAT_alloc_info);
                write_sb = true;
        }
 
        if (c->opts.fsck &&
-           !test_bit(BCH_FS_ERROR, &c->flags) &&
-           !test_bit(BCH_FS_ERRORS_NOT_FIXED, &c->flags)) {
+           !test_bit(BCH_FS_error, &c->flags) &&
+           !test_bit(BCH_FS_errors_not_fixed, &c->flags)) {
                SET_BCH_SB_HAS_ERRORS(c->disk_sb.sb, 0);
                SET_BCH_SB_HAS_TOPOLOGY_ERRORS(c->disk_sb.sb, 0);
                write_sb = true;
@@ -929,8 +953,12 @@ use_clean:
 
                bch2_move_stats_init(&stats, "recovery");
 
-               bch_info(c, "scanning for old btree nodes");
-               ret =   bch2_fs_read_write(c) ?:
+               struct printbuf buf = PRINTBUF;
+               bch2_version_to_text(&buf, c->sb.version_min);
+               bch_info(c, "scanning for old btree nodes: min_version %s", buf.buf);
+               printbuf_exit(&buf);
+
+               ret =   bch2_fs_read_write_early(c) ?:
                        bch2_scan_old_btree_nodes(c, &stats);
                if (ret)
                        goto err;
@@ -943,23 +971,20 @@ use_clean:
 
        ret = 0;
 out:
-       set_bit(BCH_FS_FSCK_DONE, &c->flags);
+       set_bit(BCH_FS_fsck_done, &c->flags);
        bch2_flush_fsck_errs(c);
 
        if (!c->opts.keep_journal &&
-           test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags)) {
-               bch2_journal_keys_free(&c->journal_keys);
-               bch2_journal_entries_free(c);
-       }
+           test_bit(JOURNAL_REPLAY_DONE, &c->journal.flags))
+               bch2_journal_keys_put_initial(c);
        kfree(clean);
 
-       if (!ret && test_bit(BCH_FS_NEED_DELETE_DEAD_SNAPSHOTS, &c->flags)) {
+       if (!ret && test_bit(BCH_FS_need_delete_dead_snapshots, &c->flags)) {
                bch2_fs_read_write_early(c);
                bch2_delete_dead_snapshots_async(c);
        }
 
-       if (ret)
-               bch_err_fn(c, ret);
+       bch_err_fn(c, ret);
        return ret;
 err:
 fsck_err:
@@ -972,8 +997,6 @@ int bch2_fs_initialize(struct bch_fs *c)
        struct bch_inode_unpacked root_inode, lostfound_inode;
        struct bkey_inode_buf packed_inode;
        struct qstr lostfound = QSTR("lost+found");
-       struct bch_dev *ca;
-       unsigned i;
        int ret;
 
        bch_notice(c, "initializing new filesystem");
@@ -992,13 +1015,13 @@ int bch2_fs_initialize(struct bch_fs *c)
        mutex_unlock(&c->sb_lock);
 
        c->curr_recovery_pass = ARRAY_SIZE(recovery_pass_fns);
-       set_bit(BCH_FS_MAY_GO_RW, &c->flags);
-       set_bit(BCH_FS_FSCK_DONE, &c->flags);
+       set_bit(BCH_FS_may_go_rw, &c->flags);
+       set_bit(BCH_FS_fsck_done, &c->flags);
 
-       for (i = 0; i < BTREE_ID_NR; i++)
+       for (unsigned i = 0; i < BTREE_ID_NR; i++)
                bch2_btree_root_alloc(c, i);
 
-       for_each_member_device(ca, c, i)
+       for_each_member_device(c, ca)
                bch2_dev_usage_init(ca);
 
        ret = bch2_fs_journal_alloc(c);
@@ -1026,7 +1049,7 @@ int bch2_fs_initialize(struct bch_fs *c)
        if (ret)
                goto err;
 
-       for_each_online_member(ca, c, i)
+       for_each_online_member(c, ca)
                ca->new_fs_bucket_idx = 0;
 
        ret = bch2_fs_freespace_init(c);
@@ -1050,10 +1073,9 @@ int bch2_fs_initialize(struct bch_fs *c)
        packed_inode.inode.k.p.snapshot = U32_MAX;
 
        ret = bch2_btree_insert(c, BTREE_ID_inodes, &packed_inode.inode.k_i, NULL, 0);
-       if (ret) {
-               bch_err_msg(c, ret, "creating root directory");
+       bch_err_msg(c, ret, "creating root directory");
+       if (ret)
                goto err;
-       }
 
        bch2_inode_init_early(c, &lostfound_inode);
 
@@ -1064,10 +1086,9 @@ int bch2_fs_initialize(struct bch_fs *c)
                                  &lostfound,
                                  0, 0, S_IFDIR|0700, 0,
                                  NULL, NULL, (subvol_inum) { 0 }, 0));
-       if (ret) {
-               bch_err_msg(c, ret, "creating lost+found");
+       bch_err_msg(c, ret, "creating lost+found");
+       if (ret)
                goto err;
-       }
 
        if (enabled_qtypes(c)) {
                ret = bch2_fs_quota_read(c);
@@ -1076,10 +1097,9 @@ int bch2_fs_initialize(struct bch_fs *c)
        }
 
        ret = bch2_journal_flush(&c->journal);
-       if (ret) {
-               bch_err_msg(c, ret, "writing first journal entry");
+       bch_err_msg(c, ret, "writing first journal entry");
+       if (ret)
                goto err;
-       }
 
        mutex_lock(&c->sb_lock);
        SET_BCH_SB_INITIALIZED(c->disk_sb.sb, true);
@@ -1090,6 +1110,6 @@ int bch2_fs_initialize(struct bch_fs *c)
 
        return 0;
 err:
-       bch_err_fn(ca, ret);
+       bch_err_fn(c, ret);
        return ret;
 }