Commit 63316903 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: moving_context now owns a btree_trans



btree_trans and moving_context are used together, and having the
moving_context owns the transaction object reduces some plumbing.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent a0bfe3b0
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -487,7 +487,7 @@ int bch2_data_update_init(struct btree_trans *trans,

		if (c->opts.nocow_enabled) {
			if (ctxt) {
				move_ctxt_wait_event(ctxt, trans,
				move_ctxt_wait_event(ctxt,
						(locked = bch2_bucket_nocow_trylock(&c->nocow_locks,
									  PTR_BUCKET_POS(c, &p.ptr), 0)) ||
						!atomic_read(&ctxt->read_sectors));
+42 −51
Original line number Diff line number Diff line
@@ -157,13 +157,11 @@ static void move_read_endio(struct bio *bio)
	closure_put(&ctxt->cl);
}

void bch2_moving_ctxt_do_pending_writes(struct moving_context *ctxt,
					struct btree_trans *trans)
void bch2_moving_ctxt_do_pending_writes(struct moving_context *ctxt)
{
	struct moving_io *io;

	if (trans)
		bch2_trans_unlock(trans);
	bch2_trans_unlock(ctxt->trans);

	while ((io = bch2_moving_ctxt_next_pending_write(ctxt))) {
		list_del(&io->read_list);
@@ -171,21 +169,20 @@ void bch2_moving_ctxt_do_pending_writes(struct moving_context *ctxt,
	}
}

void bch2_move_ctxt_wait_for_io(struct moving_context *ctxt,
				struct btree_trans *trans)
void bch2_move_ctxt_wait_for_io(struct moving_context *ctxt)
{
	unsigned sectors_pending = atomic_read(&ctxt->write_sectors);

	move_ctxt_wait_event(ctxt, trans,
	move_ctxt_wait_event(ctxt,
		!atomic_read(&ctxt->write_sectors) ||
		atomic_read(&ctxt->write_sectors) != sectors_pending);
}

void bch2_moving_ctxt_exit(struct moving_context *ctxt)
{
	struct bch_fs *c = ctxt->c;
	struct bch_fs *c = ctxt->trans->c;

	move_ctxt_wait_event(ctxt, NULL, list_empty(&ctxt->reads));
	move_ctxt_wait_event(ctxt, list_empty(&ctxt->reads));
	closure_sync(&ctxt->cl);

	EBUG_ON(atomic_read(&ctxt->write_sectors));
@@ -203,6 +200,9 @@ void bch2_moving_ctxt_exit(struct moving_context *ctxt)
	mutex_lock(&c->moving_context_lock);
	list_del(&ctxt->list);
	mutex_unlock(&c->moving_context_lock);

	bch2_trans_put(ctxt->trans);
	memset(ctxt, 0, sizeof(*ctxt));
}

void bch2_moving_ctxt_init(struct moving_context *ctxt,
@@ -214,7 +214,7 @@ void bch2_moving_ctxt_init(struct moving_context *ctxt,
{
	memset(ctxt, 0, sizeof(*ctxt));

	ctxt->c		= c;
	ctxt->trans	= bch2_trans_get(c);
	ctxt->fn	= (void *) _RET_IP_;
	ctxt->rate	= rate;
	ctxt->stats	= stats;
@@ -287,14 +287,14 @@ static int bch2_extent_drop_ptrs(struct btree_trans *trans,
		bch2_trans_commit(trans, NULL, NULL, BTREE_INSERT_NOFAIL);
}

int bch2_move_extent(struct btree_trans *trans,
		     struct btree_iter *iter,
		     struct moving_context *ctxt,
int bch2_move_extent(struct moving_context *ctxt,
		     struct move_bucket_in_flight *bucket_in_flight,
		     struct bch_io_opts io_opts,
		     struct btree_iter *iter,
		     struct bkey_s_c k,
		     struct bch_io_opts io_opts,
		     struct data_update_opts data_opts)
{
	struct btree_trans *trans = ctxt->trans;
	struct bch_fs *c = trans->c;
	struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
	struct moving_io *io;
@@ -499,14 +499,13 @@ int bch2_move_get_io_opts_one(struct btree_trans *trans,
	return 0;
}

int bch2_move_ratelimit(struct btree_trans *trans,
			struct moving_context *ctxt)
int bch2_move_ratelimit(struct moving_context *ctxt)
{
	struct bch_fs *c = trans->c;
	struct bch_fs *c = ctxt->trans->c;
	u64 delay;

	if (ctxt->wait_on_copygc) {
		bch2_trans_unlock(trans);
		bch2_trans_unlock(ctxt->trans);
		wait_event_killable(c->copygc_running_wq,
				    !c->copygc_running ||
				    kthread_should_stop());
@@ -516,7 +515,7 @@ int bch2_move_ratelimit(struct btree_trans *trans,
		delay = ctxt->rate ? bch2_ratelimit_delay(ctxt->rate) : 0;

		if (delay) {
			bch2_trans_unlock(trans);
			bch2_trans_unlock(ctxt->trans);
			set_current_state(TASK_INTERRUPTIBLE);
		}

@@ -529,7 +528,7 @@ int bch2_move_ratelimit(struct btree_trans *trans,
			schedule_timeout(delay);

		if (unlikely(freezing(current))) {
			move_ctxt_wait_event(ctxt, trans, list_empty(&ctxt->reads));
			move_ctxt_wait_event(ctxt, list_empty(&ctxt->reads));
			try_to_freeze();
		}
	} while (delay);
@@ -538,7 +537,7 @@ int bch2_move_ratelimit(struct btree_trans *trans,
	 * XXX: these limits really ought to be per device, SSDs and hard drives
	 * will want different limits
	 */
	move_ctxt_wait_event(ctxt, trans,
	move_ctxt_wait_event(ctxt,
		atomic_read(&ctxt->write_sectors) < c->opts.move_bytes_in_flight >> 9 &&
		atomic_read(&ctxt->read_sectors) < c->opts.move_bytes_in_flight >> 9 &&
		atomic_read(&ctxt->write_ios) < c->opts.move_ios_in_flight &&
@@ -547,14 +546,14 @@ int bch2_move_ratelimit(struct btree_trans *trans,
	return 0;
}

static int bch2_move_data_btree(struct btree_trans *trans,
			    struct moving_context *ctxt,
static int bch2_move_data_btree(struct moving_context *ctxt,
				struct bpos start,
				struct bpos end,
				move_pred_fn pred, void *arg,
				enum btree_id btree_id)
{
	struct bch_fs *c = ctxt->c;
	struct btree_trans *trans = ctxt->trans;
	struct bch_fs *c = trans->c;
	struct per_snapshot_io_opts snapshot_io_opts;
	struct bch_io_opts *io_opts;
	struct bkey_buf sk;
@@ -579,7 +578,7 @@ static int bch2_move_data_btree(struct btree_trans *trans,
	if (ctxt->rate)
		bch2_ratelimit_reset(ctxt->rate);

	while (!bch2_move_ratelimit(trans, ctxt)) {
	while (!bch2_move_ratelimit(ctxt)) {
		bch2_trans_begin(trans);

		k = bch2_btree_iter_peek(&iter);
@@ -617,15 +616,14 @@ static int bch2_move_data_btree(struct btree_trans *trans,
		bch2_bkey_buf_reassemble(&sk, c, k);
		k = bkey_i_to_s_c(sk.k);

		ret2 = bch2_move_extent(trans, &iter, ctxt, NULL,
					*io_opts, k, data_opts);
		ret2 = bch2_move_extent(ctxt, NULL, &iter, k, *io_opts, data_opts);
		if (ret2) {
			if (bch2_err_matches(ret2, BCH_ERR_transaction_restart))
				continue;

			if (ret2 == -ENOMEM) {
				/* memory allocation failure, wait for some IO to finish */
				bch2_move_ctxt_wait_for_io(ctxt, trans);
				bch2_move_ctxt_wait_for_io(ctxt);
				continue;
			}

@@ -646,13 +644,12 @@ static int bch2_move_data_btree(struct btree_trans *trans,
	return ret;
}

int __bch2_move_data(struct btree_trans *trans,
		     struct moving_context *ctxt,
int __bch2_move_data(struct moving_context *ctxt,
		     struct bbpos start,
		     struct bbpos end,
		     move_pred_fn pred, void *arg)
{
	struct bch_fs *c = trans->c;
	struct bch_fs *c = ctxt->trans->c;
	enum btree_id id;
	int ret = 0;

@@ -665,7 +662,7 @@ int __bch2_move_data(struct btree_trans *trans,
		    !bch2_btree_id_root(c, id)->b)
			continue;

		ret = bch2_move_data_btree(trans, ctxt,
		ret = bch2_move_data_btree(ctxt,
				       id == start.btree ? start.pos : POS_MIN,
				       id == end.btree   ? end.pos   : POS_MAX,
				       pred, arg, id);
@@ -686,26 +683,23 @@ int bch2_move_data(struct bch_fs *c,
		   move_pred_fn pred, void *arg)
{

	struct btree_trans *trans;
	struct moving_context ctxt;
	int ret;

	bch2_moving_ctxt_init(&ctxt, c, rate, stats, wp, wait_on_copygc);
	trans = bch2_trans_get(c);
	ret = __bch2_move_data(trans, &ctxt, start, end, pred, arg);
	bch2_trans_put(trans);
	ret = __bch2_move_data(&ctxt, start, end, pred, arg);
	bch2_moving_ctxt_exit(&ctxt);

	return ret;
}

int __bch2_evacuate_bucket(struct btree_trans *trans,
			   struct moving_context *ctxt,
int __bch2_evacuate_bucket(struct moving_context *ctxt,
			   struct move_bucket_in_flight *bucket_in_flight,
			   struct bpos bucket, int gen,
			   struct data_update_opts _data_opts)
{
	struct bch_fs *c = ctxt->c;
	struct btree_trans *trans = ctxt->trans;
	struct bch_fs *c = trans->c;
	struct bch_io_opts io_opts = bch2_opts_to_inode_opts(c->opts);
	struct btree_iter iter;
	struct bkey_buf sk;
@@ -750,7 +744,7 @@ int __bch2_evacuate_bucket(struct btree_trans *trans,
		goto err;
	}

	while (!(ret = bch2_move_ratelimit(trans, ctxt))) {
	while (!(ret = bch2_move_ratelimit(ctxt))) {
		bch2_trans_begin(trans);

		ret = bch2_get_next_backpointer(trans, bucket, gen,
@@ -800,16 +794,15 @@ int __bch2_evacuate_bucket(struct btree_trans *trans,
				i++;
			}

			ret = bch2_move_extent(trans, &iter, ctxt,
					bucket_in_flight,
					io_opts, k, data_opts);
			ret = bch2_move_extent(ctxt, bucket_in_flight,
					       &iter, k, io_opts, data_opts);
			bch2_trans_iter_exit(trans, &iter);

			if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
				continue;
			if (ret == -ENOMEM) {
				/* memory allocation failure, wait for some IO to finish */
				bch2_move_ctxt_wait_for_io(ctxt, trans);
				bch2_move_ctxt_wait_for_io(ctxt);
				continue;
			}
			if (ret)
@@ -865,14 +858,12 @@ int bch2_evacuate_bucket(struct bch_fs *c,
			 struct write_point_specifier wp,
			 bool wait_on_copygc)
{
	struct btree_trans *trans = bch2_trans_get(c);
	struct moving_context ctxt;
	int ret;

	bch2_moving_ctxt_init(&ctxt, c, rate, stats, wp, wait_on_copygc);
	ret = __bch2_evacuate_bucket(trans, &ctxt, NULL, bucket, gen, data_opts);
	ret = __bch2_evacuate_bucket(&ctxt, NULL, bucket, gen, data_opts);
	bch2_moving_ctxt_exit(&ctxt);
	bch2_trans_put(trans);

	return ret;
}
+11 −16
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@
struct bch_read_bio;

struct moving_context {
	struct bch_fs		*c;
	struct btree_trans	*trans;
	struct list_head	list;
	void			*fn;

@@ -38,10 +38,10 @@ struct moving_context {
	wait_queue_head_t	wait;
};

#define move_ctxt_wait_event(_ctxt, _trans, _cond)			\
#define move_ctxt_wait_event(_ctxt, _cond)				\
do {									\
	bool cond_finished = false;					\
	bch2_moving_ctxt_do_pending_writes(_ctxt, _trans);		\
	bch2_moving_ctxt_do_pending_writes(_ctxt);			\
									\
	if (_cond)							\
		break;							\
@@ -60,11 +60,9 @@ void bch2_moving_ctxt_init(struct moving_context *, struct bch_fs *,
			   struct bch_ratelimit *, struct bch_move_stats *,
			   struct write_point_specifier, bool);
struct moving_io *bch2_moving_ctxt_next_pending_write(struct moving_context *);
void bch2_moving_ctxt_do_pending_writes(struct moving_context *,
					struct btree_trans *);
void bch2_move_ctxt_wait_for_io(struct moving_context *,
				struct btree_trans *);
int bch2_move_ratelimit(struct btree_trans *, struct moving_context *);
void bch2_moving_ctxt_do_pending_writes(struct moving_context *);
void bch2_move_ctxt_wait_for_io(struct moving_context *);
int bch2_move_ratelimit(struct moving_context *);

/* Inodes in different snapshots may have different IO options: */
struct snapshot_io_opts_entry {
@@ -95,16 +93,14 @@ int bch2_move_get_io_opts_one(struct btree_trans *, struct bch_io_opts *, struct

int bch2_scan_old_btree_nodes(struct bch_fs *, struct bch_move_stats *);

int bch2_move_extent(struct btree_trans *,
		     struct btree_iter *,
		     struct moving_context *,
int bch2_move_extent(struct moving_context *,
		     struct move_bucket_in_flight *,
		     struct bch_io_opts,
		     struct btree_iter *,
		     struct bkey_s_c,
		     struct bch_io_opts,
		     struct data_update_opts);

int __bch2_move_data(struct btree_trans *,
		     struct moving_context *,
int __bch2_move_data(struct moving_context *,
		     struct bbpos,
		     struct bbpos,
		     move_pred_fn, void *);
@@ -117,8 +113,7 @@ int bch2_move_data(struct bch_fs *,
		   bool,
		   move_pred_fn, void *);

int __bch2_evacuate_bucket(struct btree_trans *,
			   struct moving_context *,
int __bch2_evacuate_bucket(struct moving_context *,
			   struct move_bucket_in_flight *,
			   struct bpos, int,
			   struct data_update_opts);
+16 −20
Original line number Diff line number Diff line
@@ -101,8 +101,7 @@ static int bch2_bucket_is_movable(struct btree_trans *trans,
	return ret;
}

static void move_buckets_wait(struct btree_trans *trans,
			      struct moving_context *ctxt,
static void move_buckets_wait(struct moving_context *ctxt,
			      struct buckets_in_flight *list,
			      bool flush)
{
@@ -111,7 +110,7 @@ static void move_buckets_wait(struct btree_trans *trans,

	while ((i = list->first)) {
		if (flush)
			move_ctxt_wait_event(ctxt, trans, !atomic_read(&i->count));
			move_ctxt_wait_event(ctxt, !atomic_read(&i->count));

		if (atomic_read(&i->count))
			break;
@@ -129,7 +128,7 @@ static void move_buckets_wait(struct btree_trans *trans,
		kfree(i);
	}

	bch2_trans_unlock(trans);
	bch2_trans_unlock(ctxt->trans);
}

static bool bucket_in_flight(struct buckets_in_flight *list,
@@ -140,11 +139,11 @@ static bool bucket_in_flight(struct buckets_in_flight *list,

typedef DARRAY(struct move_bucket) move_buckets;

static int bch2_copygc_get_buckets(struct btree_trans *trans,
			struct moving_context *ctxt,
static int bch2_copygc_get_buckets(struct moving_context *ctxt,
			struct buckets_in_flight *buckets_in_flight,
			move_buckets *buckets)
{
	struct btree_trans *trans = ctxt->trans;
	struct bch_fs *c = trans->c;
	struct btree_iter iter;
	struct bkey_s_c k;
@@ -152,7 +151,7 @@ static int bch2_copygc_get_buckets(struct btree_trans *trans,
	size_t saw = 0, in_flight = 0, not_movable = 0, sectors = 0;
	int ret;

	move_buckets_wait(trans, ctxt, buckets_in_flight, false);
	move_buckets_wait(ctxt, buckets_in_flight, false);

	ret = bch2_btree_write_buffer_flush(trans);
	if (bch2_fs_fatal_err_on(ret, c, "%s: error %s from bch2_btree_write_buffer_flush()",
@@ -188,10 +187,10 @@ static int bch2_copygc_get_buckets(struct btree_trans *trans,
}

noinline
static int bch2_copygc(struct btree_trans *trans,
		       struct moving_context *ctxt,
static int bch2_copygc(struct moving_context *ctxt,
		       struct buckets_in_flight *buckets_in_flight)
{
	struct btree_trans *trans = ctxt->trans;
	struct bch_fs *c = trans->c;
	struct data_update_opts data_opts = {
		.btree_insert_flags = BCH_WATERMARK_copygc,
@@ -202,7 +201,7 @@ static int bch2_copygc(struct btree_trans *trans,
	u64 moved = atomic64_read(&ctxt->stats->sectors_moved);
	int ret = 0;

	ret = bch2_copygc_get_buckets(trans, ctxt, buckets_in_flight, &buckets);
	ret = bch2_copygc_get_buckets(ctxt, buckets_in_flight, &buckets);
	if (ret)
		goto err;

@@ -221,7 +220,7 @@ static int bch2_copygc(struct btree_trans *trans,
			break;
		}

		ret = __bch2_evacuate_bucket(trans, ctxt, f, f->bucket.k.bucket,
		ret = __bch2_evacuate_bucket(ctxt, f, f->bucket.k.bucket,
					     f->bucket.k.gen, data_opts);
		if (ret)
			goto err;
@@ -300,7 +299,6 @@ void bch2_copygc_wait_to_text(struct printbuf *out, struct bch_fs *c)
static int bch2_copygc_thread(void *arg)
{
	struct bch_fs *c = arg;
	struct btree_trans *trans;
	struct moving_context ctxt;
	struct bch_move_stats move_stats;
	struct io_clock *clock = &c->io_clock[WRITE];
@@ -317,7 +315,6 @@ static int bch2_copygc_thread(void *arg)
	}

	set_freezable();
	trans = bch2_trans_get(c);

	bch2_move_stats_init(&move_stats, "copygc");
	bch2_moving_ctxt_init(&ctxt, c, NULL, &move_stats,
@@ -325,16 +322,16 @@ static int bch2_copygc_thread(void *arg)
			      false);

	while (!ret && !kthread_should_stop()) {
		bch2_trans_unlock(trans);
		bch2_trans_unlock(ctxt.trans);
		cond_resched();

		if (!c->copy_gc_enabled) {
			move_buckets_wait(trans, &ctxt, &buckets, true);
			move_buckets_wait(&ctxt, &buckets, true);
			kthread_wait_freezable(c->copy_gc_enabled);
		}

		if (unlikely(freezing(current))) {
			move_buckets_wait(trans, &ctxt, &buckets, true);
			move_buckets_wait(&ctxt, &buckets, true);
			__refrigerator(false);
			continue;
		}
@@ -345,7 +342,7 @@ static int bch2_copygc_thread(void *arg)
		if (wait > clock->max_slop) {
			c->copygc_wait_at = last;
			c->copygc_wait = last + wait;
			move_buckets_wait(trans, &ctxt, &buckets, true);
			move_buckets_wait(&ctxt, &buckets, true);
			trace_and_count(c, copygc_wait, c, wait, last + wait);
			bch2_kthread_io_clock_wait(clock, last + wait,
					MAX_SCHEDULE_TIMEOUT);
@@ -355,15 +352,14 @@ static int bch2_copygc_thread(void *arg)
		c->copygc_wait = 0;

		c->copygc_running = true;
		ret = bch2_copygc(trans, &ctxt, &buckets);
		ret = bch2_copygc(&ctxt, &buckets);
		c->copygc_running = false;

		wake_up(&c->copygc_running_wq);
	}

	move_buckets_wait(trans, &ctxt, &buckets, true);
	move_buckets_wait(&ctxt, &buckets, true);
	rhashtable_destroy(&buckets.table);
	bch2_trans_put(trans);
	bch2_moving_ctxt_exit(&ctxt);

	return 0;