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

bcachefs: discard fastpath now uses bch2_discard_one_bucket()



The discard bucket fastpath previously was using its own code for
discarding buckets and clearing them in the need_discard btree, which
didn't have any of the consistency checks of the main discard path.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent e1cb4f56
Loading
Loading
Loading
Loading
+41 −34
Original line number Diff line number Diff line
@@ -1725,7 +1725,8 @@ static int bch2_discard_one_bucket(struct btree_trans *trans,
				   struct bch_dev *ca,
				   struct btree_iter *need_discard_iter,
				   struct bpos *discard_pos_done,
				   struct discard_buckets_state *s)
				   struct discard_buckets_state *s,
				   bool fastpath)
{
	struct bch_fs *c = trans->c;
	struct bpos pos = need_discard_iter->pos;
@@ -1782,10 +1783,12 @@ static int bch2_discard_one_bucket(struct btree_trans *trans,
		goto out;
	}

	if (!fastpath) {
		if (discard_in_flight_add(ca, iter.pos.offset, true))
			goto out;

		discard_locked = true;
	}

	if (!bkey_eq(*discard_pos_done, iter.pos) &&
	    ca->mi.discard && !c->opts.nochanges) {
@@ -1799,6 +1802,7 @@ static int bch2_discard_one_bucket(struct btree_trans *trans,
				     ca->mi.bucket_size,
				     GFP_KERNEL);
		*discard_pos_done = iter.pos;
		s->discarded++;

		ret = bch2_trans_relock_notrace(trans);
		if (ret)
@@ -1819,11 +1823,11 @@ static int bch2_discard_one_bucket(struct btree_trans *trans,
		goto out;

	count_event(c, bucket_discard);
	s->discarded++;
out:
fsck_err:
	if (discard_locked)
		discard_in_flight_remove(ca, iter.pos.offset);
	if (!ret)
		s->seen++;
	bch2_trans_iter_exit(trans, &iter);
	printbuf_exit(&buf);
@@ -1848,7 +1852,7 @@ static void bch2_do_discards_work(struct work_struct *work)
				   BTREE_ID_need_discard,
				   POS(ca->dev_idx, 0),
				   POS(ca->dev_idx, U64_MAX), 0, k,
			bch2_discard_one_bucket(trans, ca, &iter, &discard_pos_done, &s)));
			bch2_discard_one_bucket(trans, ca, &iter, &discard_pos_done, &s, false)));

	trace_discard_buckets(c, s.seen, s.open, s.need_journal_commit, s.discarded,
			      bch2_err_str(ret));
@@ -1881,27 +1885,31 @@ void bch2_do_discards(struct bch_fs *c)
		bch2_dev_do_discards(ca);
}

static int bch2_clear_bucket_needs_discard(struct btree_trans *trans, struct bpos bucket)
static int bch2_do_discards_fast_one(struct btree_trans *trans,
				     struct bch_dev *ca,
				     u64 bucket,
				     struct bpos *discard_pos_done,
				     struct discard_buckets_state *s)
{
	struct btree_iter iter;
	bch2_trans_iter_init(trans, &iter, BTREE_ID_alloc, bucket, BTREE_ITER_intent);
	struct bkey_s_c k = bch2_btree_iter_peek_slot(&iter);
	int ret = bkey_err(k);
	struct btree_iter need_discard_iter;
	struct bkey_s_c discard_k = bch2_bkey_get_iter(trans, &need_discard_iter,
					BTREE_ID_need_discard, POS(ca->dev_idx, bucket), 0);
	int ret = bkey_err(discard_k);
	if (ret)
		goto err;

	struct bkey_i_alloc_v4 *a = bch2_alloc_to_v4_mut(trans, k);
	ret = PTR_ERR_OR_ZERO(a);
	if (ret)
		goto err;
		return ret;

	BUG_ON(a->v.dirty_sectors);
	SET_BCH_ALLOC_V4_NEED_DISCARD(&a->v, false);
	alloc_data_type_set(&a->v, a->v.data_type);
	if (log_fsck_err_on(discard_k.k->type != KEY_TYPE_set,
			    trans, discarding_bucket_not_in_need_discard_btree,
			    "attempting to discard bucket %u:%llu not in need_discard btree",
			    ca->dev_idx, bucket)) {
		/* log it in the superblock and continue: */
		goto out;
	}

	ret = bch2_trans_update(trans, &iter, &a->k_i, 0);
err:
	bch2_trans_iter_exit(trans, &iter);
	ret = bch2_discard_one_bucket(trans, ca, &need_discard_iter, discard_pos_done, s, true);
out:
fsck_err:
	bch2_trans_iter_exit(trans, &need_discard_iter);
	return ret;
}

@@ -1909,6 +1917,10 @@ static void bch2_do_discards_fast_work(struct work_struct *work)
{
	struct bch_dev *ca = container_of(work, struct bch_dev, discard_fast_work);
	struct bch_fs *c = ca->fs;
	struct discard_buckets_state s = {};
	struct bpos discard_pos_done = POS_MAX;
	struct btree_trans *trans = bch2_trans_get(c);
	int ret = 0;

	while (1) {
		bool got_bucket = false;
@@ -1929,16 +1941,8 @@ static void bch2_do_discards_fast_work(struct work_struct *work)
		if (!got_bucket)
			break;

		if (ca->mi.discard && !c->opts.nochanges)
			blkdev_issue_discard(ca->disk_sb.bdev,
					     bucket_to_sector(ca, bucket),
					     ca->mi.bucket_size,
					     GFP_KERNEL);

		int ret = bch2_trans_commit_do(c, NULL, NULL,
			BCH_WATERMARK_btree|
			BCH_TRANS_COMMIT_no_enospc,
			bch2_clear_bucket_needs_discard(trans, POS(ca->dev_idx, bucket)));
		ret = lockrestart_do(trans,
			bch2_do_discards_fast_one(trans, ca, bucket, &discard_pos_done, &s));
		bch_err_fn(c, ret);

		discard_in_flight_remove(ca, bucket);
@@ -1947,6 +1951,9 @@ static void bch2_do_discards_fast_work(struct work_struct *work)
			break;
	}

	trace_discard_buckets(c, s.seen, s.open, s.need_journal_commit, s.discarded, bch2_err_str(ret));

	bch2_trans_put(trans);
	percpu_ref_put(&ca->io_ref);
	bch2_write_ref_put(c, BCH_WRITE_REF_discard_fast);
}