Commit 5efa3d61 authored by Ben Walker's avatar Ben Walker Committed by Tomasz Zawadzki
Browse files

nvmf: Add spdk_nvmf_subsystem_disconnect_host



This will disconnect all connections to a subsystem from a given
host identified by HOSTNQN.

Change-Id: Ibc9cea1f08a58a05dbac3a0bb47df8d8a58e7c10
Signed-off-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/4556


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarAleksey Marchuk <alexeymar@mellanox.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
parent ce594c1e
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -484,6 +484,25 @@ int spdk_nvmf_subsystem_add_host(struct spdk_nvmf_subsystem *subsystem,
 */
int spdk_nvmf_subsystem_remove_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn);

/**
 * Disconnect all connections originating from the provided hostnqn
 *
 * To disconnect and block all new connections from a host, first call
 * spdk_nvmf_subsystem_remove_host() to remove it from the list of allowed hosts, then
 * call spdk_nvmf_subsystem_disconnect_host() to close any remaining connections.
 *
 * \param subsystem Subsystem to operate on
 * \param hostnqn The NQN for the host
 * \param cb_fn The function to call on completion.
 * \param cb_arg The argument to pass to the cb_fn.
 *
 * \return int. 0 when the asynchronous process starts successfully or a negated errno on failure.
 */
int spdk_nvmf_subsystem_disconnect_host(struct spdk_nvmf_subsystem *subsystem,
					const char *hostnqn,
					spdk_nvmf_tgt_subsystem_listen_done_fn cb_fn,
					void *cb_arg);

/**
 * Set whether a subsystem should allow any host or only hosts in the allowed list.
 *
+1 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
	spdk_nvmf_subsystem_get_next;
	spdk_nvmf_subsystem_add_host;
	spdk_nvmf_subsystem_remove_host;
	spdk_nvmf_subsystem_disconnect_host;
	spdk_nvmf_subsystem_set_allow_any_host;
	spdk_nvmf_subsystem_get_allow_any_host;
	spdk_nvmf_subsystem_host_allowed;
+73 −0
Original line number Diff line number Diff line
@@ -760,6 +760,79 @@ spdk_nvmf_subsystem_remove_host(struct spdk_nvmf_subsystem *subsystem, const cha
	return 0;
}

struct nvmf_subsystem_disconnect_host_ctx {
	struct spdk_nvmf_subsystem		*subsystem;
	char					*hostnqn;
	spdk_nvmf_tgt_subsystem_listen_done_fn	cb_fn;
	void					*cb_arg;
};

static void
nvmf_subsystem_disconnect_host_fini(struct spdk_io_channel_iter *i, int status)
{
	struct nvmf_subsystem_disconnect_host_ctx *ctx;

	ctx = spdk_io_channel_iter_get_ctx(i);

	if (ctx->cb_fn) {
		ctx->cb_fn(ctx->cb_arg, status);
	}
	free(ctx->hostnqn);
	free(ctx);
}

static void
nvmf_subsystem_disconnect_qpairs_by_host(struct spdk_io_channel_iter *i)
{
	struct nvmf_subsystem_disconnect_host_ctx *ctx;
	struct spdk_nvmf_poll_group *group;
	struct spdk_io_channel *ch;
	struct spdk_nvmf_qpair *qpair, *tmp_qpair;
	struct spdk_nvmf_ctrlr *ctrlr;

	ctx = spdk_io_channel_iter_get_ctx(i);
	ch = spdk_io_channel_iter_get_channel(i);
	group = spdk_io_channel_get_ctx(ch);

	TAILQ_FOREACH_SAFE(qpair, &group->qpairs, link, tmp_qpair) {
		ctrlr = qpair->ctrlr;

		if (ctrlr == NULL || ctrlr->subsys != ctx->subsystem) {
			continue;
		}

		if (strncmp(ctrlr->hostnqn, ctx->hostnqn, sizeof(ctrlr->hostnqn)) == 0) {
			/* Right now this does not wait for the queue pairs to actually disconnect. */
			spdk_nvmf_qpair_disconnect(qpair, NULL, NULL);
		}
	}
	spdk_for_each_channel_continue(i, 0);
}

int
spdk_nvmf_subsystem_disconnect_host(struct spdk_nvmf_subsystem *subsystem,
				    const char *hostnqn,
				    spdk_nvmf_tgt_subsystem_listen_done_fn cb_fn,
				    void *cb_arg)
{
	struct nvmf_subsystem_disconnect_host_ctx *ctx;

	ctx = calloc(1, sizeof(struct nvmf_subsystem_disconnect_host_ctx));
	if (ctx == NULL) {
		return -ENOMEM;
	}

	ctx->subsystem = subsystem;
	ctx->hostnqn = strdup(hostnqn);
	ctx->cb_fn = cb_fn;
	ctx->cb_arg = cb_arg;

	spdk_for_each_channel(subsystem->tgt, nvmf_subsystem_disconnect_qpairs_by_host, ctx,
			      nvmf_subsystem_disconnect_host_fini);

	return 0;
}

int
spdk_nvmf_subsystem_set_allow_any_host(struct spdk_nvmf_subsystem *subsystem, bool allow_any_host)
{