diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h index cf092903a6ab..e2df0f7182b4 100644 --- a/fs/bcachefs/bcachefs_format.h +++ b/fs/bcachefs/bcachefs_format.h @@ -1373,6 +1373,7 @@ enum bch_sb_feature { enum bch_sb_compat { BCH_COMPAT_FEAT_ALLOC_INFO = 0, BCH_COMPAT_FEAT_ALLOC_METADATA = 1, + BCH_COMPAT_FEAT_EXTENTS_ABOVE_BTREE_UPDATES_DONE = 2, }; /* options: */ diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c index 426c932098da..259a36f41629 100644 --- a/fs/bcachefs/btree_gc.c +++ b/fs/bcachefs/btree_gc.c @@ -1618,7 +1618,8 @@ int bch2_gc_thread_start(struct bch_fs *c) { struct task_struct *p; - BUG_ON(c->gc_thread); + if (c->gc_thread) + return 0; p = kthread_create(bch2_gc_thread, c, "bch-gc/%s", c->name); if (IS_ERR(p)) { diff --git a/fs/bcachefs/move.c b/fs/bcachefs/move.c index 72958b867014..ed18abf8bf14 100644 --- a/fs/bcachefs/move.c +++ b/fs/bcachefs/move.c @@ -845,6 +845,25 @@ static enum data_cmd rewrite_old_nodes_pred(struct bch_fs *c, void *arg, return DATA_SKIP; } +int bch2_scan_old_btree_nodes(struct bch_fs *c, struct bch_move_stats *stats) +{ + int ret; + + ret = bch2_move_btree(c, + 0, POS_MIN, + BTREE_ID_NR, POS_MAX, + rewrite_old_nodes_pred, c, stats); + if (!ret) { + mutex_lock(&c->sb_lock); + c->disk_sb.sb->compat[0] |= 1ULL << BCH_COMPAT_FEAT_EXTENTS_ABOVE_BTREE_UPDATES_DONE; + c->disk_sb.sb->version_min = c->disk_sb.sb->version; + bch2_write_super(c); + mutex_unlock(&c->sb_lock); + } + + return ret; +} + int bch2_data_job(struct bch_fs *c, struct bch_move_stats *stats, struct bch_ioctl_data op) @@ -894,17 +913,7 @@ int bch2_data_job(struct bch_fs *c, ret = bch2_replicas_gc2(c) ?: ret; break; case BCH_DATA_OP_REWRITE_OLD_NODES: - ret = bch2_move_btree(c, - op.start_btree, op.start_pos, - op.end_btree, op.end_pos, - rewrite_old_nodes_pred, &op, stats) ?: ret; - - if (!ret) { - mutex_lock(&c->sb_lock); - c->disk_sb.sb->version_min = c->disk_sb.sb->version; - bch2_write_super(c); - mutex_unlock(&c->sb_lock); - } + ret = bch2_scan_old_btree_nodes(c, stats); break; default: ret = -EINVAL; diff --git a/fs/bcachefs/move.h b/fs/bcachefs/move.h index 403ca695c875..5076153689d1 100644 --- a/fs/bcachefs/move.h +++ b/fs/bcachefs/move.h @@ -52,6 +52,8 @@ typedef enum data_cmd (*move_pred_fn)(struct bch_fs *, void *, struct bkey_s_c, struct bch_io_opts *, struct data_opts *); +int bch2_scan_old_btree_nodes(struct bch_fs *, struct bch_move_stats *); + int bch2_move_data(struct bch_fs *, enum btree_id, struct bpos, enum btree_id, struct bpos, diff --git a/fs/bcachefs/rebalance.c b/fs/bcachefs/rebalance.c index c83c12dbb0d2..0e1f18d82855 100644 --- a/fs/bcachefs/rebalance.c +++ b/fs/bcachefs/rebalance.c @@ -312,6 +312,9 @@ int bch2_rebalance_start(struct bch_fs *c) { struct task_struct *p; + if (c->rebalance.thread) + return 0; + if (c->opts.nochanges) return 0; diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c index 0aeaaadbf3f8..e322dc35f992 100644 --- a/fs/bcachefs/recovery.c +++ b/fs/bcachefs/recovery.c @@ -16,6 +16,7 @@ #include "journal_io.h" #include "journal_reclaim.h" #include "journal_seq_blacklist.h" +#include "move.h" #include "quota.h" #include "recovery.h" #include "replicas.h" @@ -1200,6 +1201,20 @@ use_clean: bch_verbose(c, "quotas done"); } + if (!(c->sb.compat & (1ULL << BCH_COMPAT_FEAT_EXTENTS_ABOVE_BTREE_UPDATES_DONE))) { + struct bch_move_stats stats = { 0 }; + + bch_verbose(c, "scanning for old btree nodes"); + ret = bch2_fs_read_write(c); + if (ret) + goto err; + + ret = bch2_scan_old_btree_nodes(c, &stats); + if (ret) + goto err; + bch_verbose(c, "scanning for old btree nodes done"); + } + mutex_lock(&c->sb_lock); if (c->opts.version_upgrade) { if (c->sb.version < bcachefs_metadata_version_new_versioning) @@ -1271,6 +1286,7 @@ int bch2_fs_initialize(struct bch_fs *c) le16_to_cpu(bcachefs_metadata_version_current); c->disk_sb.sb->features[0] |= 1ULL << BCH_FEATURE_atomic_nlink; c->disk_sb.sb->features[0] |= BCH_SB_FEATURES_ALL; + c->disk_sb.sb->compat[0] |= 1ULL << BCH_COMPAT_FEAT_EXTENTS_ABOVE_BTREE_UPDATES_DONE; bch2_write_super(c); mutex_unlock(&c->sb_lock);