struct write_point copygc_write_point;
s64 copygc_wait;
+ /* DATA PROGRESS STATS */
+ struct list_head data_progress_list;
+ struct mutex data_progress_lock;
+
/* STRIPES: */
GENRADIX(struct stripe) stripes[2];
return ret;
}
+inline void bch_move_stats_init(struct bch_move_stats *stats, char *name)
+{
+ memset(stats, 0, sizeof(*stats));
+
+ scnprintf(stats->name, sizeof(stats->name),
+ "%s", name);
+}
+
+static inline void progress_list_add(struct bch_fs *c,
+ struct bch_move_stats *stats)
+{
+ mutex_lock(&c->data_progress_lock);
+ list_add(&stats->list, &c->data_progress_list);
+ mutex_unlock(&c->data_progress_lock);
+}
+
+static inline void progress_list_del(struct bch_fs *c,
+ struct bch_move_stats *stats)
+{
+ mutex_lock(&c->data_progress_lock);
+ list_del(&stats->list);
+ mutex_unlock(&c->data_progress_lock);
+}
+
int bch2_move_data(struct bch_fs *c,
enum btree_id start_btree_id, struct bpos start_pos,
enum btree_id end_btree_id, struct bpos end_pos,
enum btree_id id;
int ret;
+ progress_list_add(c, stats);
closure_init_stack(&ctxt.cl);
INIT_LIST_HEAD(&ctxt.reads);
init_waitqueue_head(&ctxt.wait);
atomic64_read(&stats->sectors_moved),
atomic64_read(&stats->keys_moved));
+ progress_list_del(c, stats);
return ret;
}
int ret = 0;
bch2_trans_init(&trans, c, 0, 0);
+ progress_list_add(c, stats);
stats->data_type = BCH_DATA_btree;
if (ret)
bch_err(c, "error %i in bch2_move_btree", ret);
+ progress_list_del(c, stats);
return ret;
}
switch (op.op) {
case BCH_DATA_OP_REREPLICATE:
+ bch_move_stats_init(stats, "rereplicate");
stats->data_type = BCH_DATA_journal;
ret = bch2_journal_flush_device_pins(&c->journal, -1);
if (op.migrate.dev >= c->sb.nr_devices)
return -EINVAL;
+ bch_move_stats_init(stats, "migrate");
stats->data_type = BCH_DATA_journal;
ret = bch2_journal_flush_device_pins(&c->journal, op.migrate.dev);
ret = bch2_replicas_gc2(c) ?: ret;
break;
case BCH_DATA_OP_REWRITE_OLD_NODES:
+ bch_move_stats_init(stats, "rewrite_old_nodes");
ret = bch2_scan_old_btree_nodes(c, stats);
break;
default:
struct bch_move_stats *,
struct bch_ioctl_data);
+inline void bch_move_stats_init(struct bch_move_stats *stats,
+ char *name);
+
+
#endif /* _BCACHEFS_MOVE_H */
enum bch_data_type data_type;
enum btree_id btree_id;
struct bpos pos;
+ struct list_head list;
+ char name[32];
atomic64_t keys_moved;
atomic64_t keys_raced;
size_t b, heap_size = 0;
int ret;
- memset(&move_stats, 0, sizeof(move_stats));
+ bch_move_stats_init(&move_stats, "copygc");
+
/*
* Find buckets with lowest sector counts, skipping completely
* empty buckets, by building a maxheap sorted by sector count,
struct bch_fs_rebalance *r = &c->rebalance;
struct io_clock *clock = &c->io_clock[WRITE];
struct rebalance_work w, p;
+ struct bch_move_stats move_stats;
unsigned long start, prev_start;
unsigned long prev_run_time, prev_run_cputime;
unsigned long cputime, prev_cputime;
prev_start = jiffies;
prev_cputime = curr_cputime();
+ bch_move_stats_init(&move_stats, "rebalance");
while (!kthread_wait_freezable(r->enabled)) {
cond_resched();
prev_cputime = cputime;
r->state = REBALANCE_RUNNING;
- memset(&r->move_stats, 0, sizeof(r->move_stats));
+ memset(&move_stats, 0, sizeof(move_stats));
rebalance_work_reset(c);
bch2_move_data(c,
NULL, /* &r->pd.rate, */
writepoint_ptr(&c->rebalance_write_point),
rebalance_pred, NULL,
- &r->move_stats);
+ &move_stats);
}
return 0;
h1);
break;
case REBALANCE_RUNNING:
- pr_buf(out, "running\n"
- "pos ");
- bch2_bpos_to_text(out, r->move_stats.pos);
- pr_buf(out, "\n");
+ pr_buf(out, "running\n");
break;
}
}
enum rebalance_state state;
u64 throttled_until_iotime;
unsigned long throttled_until_cputime;
- struct bch_move_stats move_stats;
unsigned enabled:1;
};
if (!(c->sb.compat & (1ULL << BCH_COMPAT_extents_above_btree_updates_done)) ||
!(c->sb.compat & (1ULL << BCH_COMPAT_bformat_overflow_done))) {
- struct bch_move_stats stats = { 0 };
+ struct bch_move_stats stats;
+
+ bch_move_stats_init(&stats, "recovery");
bch_info(c, "scanning for old btree nodes");
ret = bch2_fs_read_write(c);
INIT_LIST_HEAD(&c->ec_stripe_new_list);
mutex_init(&c->ec_stripe_new_lock);
+ INIT_LIST_HEAD(&c->data_progress_list);
+ mutex_init(&c->data_progress_lock);
+
spin_lock_init(&c->ec_stripes_heap_lock);
seqcount_init(&c->gc_pos_lock);
read_attribute(io_timers_read);
read_attribute(io_timers_write);
+read_attribute(data_op_data_progress);
+
#ifdef CONFIG_BCACHEFS_TESTS
write_attribute(perf_test);
#endif /* CONFIG_BCACHEFS_TESTS */
return nr ? div64_u64(sectors, nr) : 0;
}
+static long stats_to_text(struct printbuf *out, struct bch_fs *c,
+ struct bch_move_stats *stats)
+{
+ pr_buf(out, "%s: data type %s btree_id %s position: ",
+ stats->name,
+ bch2_data_types[stats->data_type],
+ bch2_btree_ids[stats->btree_id]);
+ bch2_bpos_to_text(out, stats->pos);
+ pr_buf(out, "%s", "\n");
+
+ return 0;
+}
+
+static long data_progress_to_text(struct printbuf *out, struct bch_fs *c)
+{
+ long ret = 0;
+ struct bch_move_stats *iter;
+
+ mutex_lock(&c->data_progress_lock);
+
+ if (list_empty(&c->data_progress_list))
+ pr_buf(out, "%s", "no progress to report\n");
+ else
+ list_for_each_entry(iter, &c->data_progress_list, list) {
+ stats_to_text(out, c, iter);
+ }
+
+ mutex_unlock(&c->data_progress_lock);
+ return ret;
+}
+
static int fs_alloc_debug_to_text(struct printbuf *out, struct bch_fs *c)
{
struct bch_fs_usage_online *fs_usage = bch2_fs_usage_read(c);
return out.pos - buf;
}
+ if (attr == &sysfs_data_op_data_progress) {
+ data_progress_to_text(&out, c);
+ return out.pos - buf;
+ }
+
return 0;
}
&sysfs_io_timers_read,
&sysfs_io_timers_write,
+ &sysfs_data_op_data_progress,
+
&sysfs_internal_uuid,
NULL
};