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

bcachefs: bch2_dev_remove_stripes()



We can now correctly force-remove a device that has stripes on it; this
uses the new BCH_SB_MEMBER_INVALID sentinal value.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 934137b0
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -2310,7 +2310,8 @@ int bch2_dev_remove_alloc(struct bch_fs *c, struct bch_dev *ca)
	 * We clear the LRU and need_discard btrees first so that we don't race
	 * with bch2_do_invalidates() and bch2_do_discards()
	 */
	ret =   bch2_btree_delete_range(c, BTREE_ID_lru, start, end,
	ret =   bch2_dev_remove_stripes(c, ca->dev_idx) ?:
		bch2_btree_delete_range(c, BTREE_ID_lru, start, end,
					BTREE_TRIGGER_norun, NULL) ?:
		bch2_btree_delete_range(c, BTREE_ID_need_discard, start, end,
					BTREE_TRIGGER_norun, NULL) ?:
@@ -2318,10 +2319,10 @@ int bch2_dev_remove_alloc(struct bch_fs *c, struct bch_dev *ca)
					BTREE_TRIGGER_norun, NULL) ?:
		bch2_btree_delete_range(c, BTREE_ID_backpointers, start, end,
					BTREE_TRIGGER_norun, NULL) ?:
		bch2_btree_delete_range(c, BTREE_ID_alloc, start, end,
					BTREE_TRIGGER_norun, NULL) ?:
		bch2_btree_delete_range(c, BTREE_ID_bucket_gens, start, end,
					BTREE_TRIGGER_norun, NULL) ?:
		bch2_btree_delete_range(c, BTREE_ID_alloc, start, end,
					BTREE_TRIGGER_norun, NULL) ?:
		bch2_dev_usage_remove(c, ca->dev_idx);
	bch_err_msg(ca, ret, "removing dev alloc info");
	return ret;
+67 −0
Original line number Diff line number Diff line
@@ -2169,6 +2169,73 @@ struct ec_stripe_head *bch2_ec_stripe_head_get(struct btree_trans *trans,
	return ERR_PTR(ret);
}

/* device removal */

static int bch2_invalidate_stripe_to_dev(struct btree_trans *trans, struct bkey_s_c k_a)
{
	struct bch_alloc_v4 a_convert;
	const struct bch_alloc_v4 *a = bch2_alloc_to_v4(k_a, &a_convert);

	if (!a->stripe)
		return 0;

	if (a->stripe_sectors) {
		bch_err(trans->c, "trying to invalidate device in stripe when bucket has stripe data");
		return -BCH_ERR_invalidate_stripe_to_dev;
	}

	struct btree_iter iter;
	struct bkey_i_stripe *s =
		bch2_bkey_get_mut_typed(trans, &iter, BTREE_ID_stripes, POS(0, a->stripe),
					BTREE_ITER_slots, stripe);
	int ret = PTR_ERR_OR_ZERO(s);
	if (ret)
		return ret;

	struct disk_accounting_pos acc = {
		.type = BCH_DISK_ACCOUNTING_replicas,
	};

	s64 sectors = 0;
	for (unsigned i = 0; i < s->v.nr_blocks; i++)
		sectors -= stripe_blockcount_get(&s->v, i);

	bch2_bkey_to_replicas(&acc.replicas, bkey_i_to_s_c(&s->k_i));
	acc.replicas.data_type = BCH_DATA_user;
	ret = bch2_disk_accounting_mod(trans, &acc, &sectors, 1, false);
	if (ret)
		goto err;

	struct bkey_ptrs ptrs = bch2_bkey_ptrs(bkey_i_to_s(&s->k_i));
	bkey_for_each_ptr(ptrs, ptr)
		if (ptr->dev == k_a.k->p.inode)
			ptr->dev = BCH_SB_MEMBER_INVALID;

	sectors = -sectors;

	bch2_bkey_to_replicas(&acc.replicas, bkey_i_to_s_c(&s->k_i));
	acc.replicas.data_type = BCH_DATA_user;
	ret = bch2_disk_accounting_mod(trans, &acc, &sectors, 1, false);
	if (ret)
		goto err;
err:
	bch2_trans_iter_exit(trans, &iter);
	return ret;
}

int bch2_dev_remove_stripes(struct bch_fs *c, unsigned dev_idx)
{
	return bch2_trans_run(c,
		for_each_btree_key_upto_commit(trans, iter,
				  BTREE_ID_alloc, POS(dev_idx, 0), POS(dev_idx, U64_MAX),
				  BTREE_ITER_intent, k,
				  NULL, NULL, 0, ({
			bch2_invalidate_stripe_to_dev(trans, k);
	})));
}

/* startup/shutdown */

static void __bch2_ec_stop(struct bch_fs *c, struct bch_dev *ca)
{
	struct ec_stripe_head *h;
+2 −0
Original line number Diff line number Diff line
@@ -251,6 +251,8 @@ static inline void ec_stripe_new_put(struct bch_fs *c, struct ec_stripe_new *s,
		}
}

int bch2_dev_remove_stripes(struct bch_fs *, unsigned);

void bch2_ec_stop_dev(struct bch_fs *, struct bch_dev *);
void bch2_fs_ec_stop(struct bch_fs *);
void bch2_fs_ec_flush(struct bch_fs *);
+1 −0
Original line number Diff line number Diff line
@@ -253,6 +253,7 @@
	x(EIO,				key_type_error)				\
	x(EIO,				no_device_to_read_from)			\
	x(EIO,				missing_indirect_extent)		\
	x(EIO,				invalidate_stripe_to_dev)		\
	x(BCH_ERR_btree_node_read_err,	btree_node_read_err_fixable)		\
	x(BCH_ERR_btree_node_read_err,	btree_node_read_err_want_retry)		\
	x(BCH_ERR_btree_node_read_err,	btree_node_read_err_must_retry)		\