Commit d3995f6e authored by Seth Howell's avatar Seth Howell Committed by Jim Harris
Browse files

nvmf: remove_subsystem now uses qpair_remove asynch api



This is necessary to avoid race conditions when freeing subsystems.

Change-Id: I9b4a7d006cc42cd29e13179e940ced0cc580f548
Signed-off-by: default avatarSeth Howell <seth.howell@intel.com>
Reviewed-on: https://review.gerrithub.io/417351


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
parent 1e2c9afa
Loading
Loading
Loading
Loading
+94 −15
Original line number Diff line number Diff line
@@ -56,6 +56,9 @@ SPDK_LOG_REGISTER_COMPONENT("nvmf", SPDK_LOG_NVMF)
#define SPDK_NVMF_DEFAULT_MAX_SUBSYSTEMS 1024
#define SPDK_NVMF_DEFAULT_IO_UNIT_SIZE 131072

typedef void (*nvmf_qpair_disconnect_cpl)(void *ctx, int status);

/* supplied to a single call to nvmf_qpair_disconnect */
struct nvmf_qpair_disconnect_ctx {
	struct spdk_nvmf_qpair *qpair;
	struct spdk_nvmf_ctrlr *ctrlr;
@@ -64,6 +67,17 @@ struct nvmf_qpair_disconnect_ctx {
	void *ctx;
};

/*
 * There are several times when we need to iterate through the list of all qpairs and selectively delete them.
 * In order to do this sequentially without overlap, we must provide a context to recover the next qpair from
 * to enable calling nvmf_qpair_disconnect on the next desired qpair.
 */
struct nvmf_qpair_disconnect_many_ctx {
	struct spdk_nvmf_subsystem *subsystem;
	struct spdk_nvmf_poll_group *group;
	nvmf_qpair_disconnect_cpl cb_fn;
};

void
spdk_nvmf_tgt_opts_init(struct spdk_nvmf_tgt_opts *opts)
{
@@ -859,27 +873,17 @@ spdk_nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group,
	return 0;
}

int
spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group,
				      struct spdk_nvmf_subsystem *subsystem)
static void
_nvmf_poll_group_remove_subsystem_cb(void *ctx, int status)
{
	struct spdk_nvmf_qpair *qpair, *tmp;
	struct spdk_nvmf_subsystem_poll_group *sgroup;
	int rc = 0;
	uint32_t nsid;

	TAILQ_FOREACH_SAFE(qpair, &group->qpairs, link, tmp) {
		if (qpair->ctrlr->subsys == subsystem) {
			rc += spdk_nvmf_qpair_disconnect(qpair, NULL, NULL);
		}
	}

	if (rc != 0) {
		return -1;
	if (status) {
		return;
	}

	sgroup = &group->sgroups[subsystem->id];
	sgroup->state = SPDK_NVMF_SUBSYSTEM_INACTIVE;
	sgroup = ctx;

	for (nsid = 0; nsid < sgroup->num_channels; nsid++) {
		if (sgroup->channels[nsid]) {
@@ -891,6 +895,81 @@ spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group,
	sgroup->num_channels = 0;
	free(sgroup->channels);
	sgroup->channels = NULL;
}

static void
_nvmf_subsystem_disconnect_next_qpair(void *ctx)
{
	struct spdk_nvmf_qpair *qpair;
	struct nvmf_qpair_disconnect_many_ctx *qpair_ctx = ctx;
	struct spdk_nvmf_subsystem *subsystem;
	struct spdk_nvmf_poll_group *group;
	struct spdk_nvmf_subsystem_poll_group *sgroup;
	int rc = 0;

	group = qpair_ctx->group;
	subsystem = qpair_ctx->subsystem;

	TAILQ_FOREACH(qpair, &group->qpairs, link) {
		if (qpair->ctrlr->subsys == subsystem) {
			break;
		}
	}

	if (qpair) {
		rc = spdk_nvmf_qpair_disconnect(qpair, _nvmf_subsystem_disconnect_next_qpair, qpair_ctx);
	}

	if (!qpair || rc != 0) {
		if (qpair_ctx->cb_fn) {
			sgroup = &group->sgroups[subsystem->id];
			qpair_ctx->cb_fn(sgroup, rc);
		}
		free(qpair_ctx);
		return;
	}
	return;
}

int
spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group,
				      struct spdk_nvmf_subsystem *subsystem)
{
	struct spdk_nvmf_qpair *qpair;
	struct spdk_nvmf_subsystem_poll_group *sgroup;
	struct nvmf_qpair_disconnect_many_ctx *ctx;
	int rc = 0;

	ctx = calloc(1, sizeof(struct nvmf_qpair_disconnect_many_ctx));

	if (!ctx) {
		return -ENOMEM;
	}

	ctx->cb_fn = _nvmf_poll_group_remove_subsystem_cb;
	ctx->group = group;
	ctx->subsystem = subsystem;

	sgroup = &group->sgroups[subsystem->id];
	sgroup->state = SPDK_NVMF_SUBSYSTEM_INACTIVE;

	TAILQ_FOREACH(qpair, &group->qpairs, link) {
		if (qpair->ctrlr->subsys == subsystem) {
			break;
		}
	}

	if (qpair) {
		rc = spdk_nvmf_qpair_disconnect(qpair, _nvmf_subsystem_disconnect_next_qpair, ctx);
	} else {
		free(ctx);
		_nvmf_poll_group_remove_subsystem_cb(sgroup, 0);
	}

	if (rc != 0) {
		free(ctx);
		return rc;
	}

	return 0;
}