Commit 95ac75aa authored by Ben Walker's avatar Ben Walker Committed by Jim Harris
Browse files

nvmf: Add synchronization primitives for subsystems



This allows the user to pause a subsystem, make some
modifications, and then resume it.

Change-Id: Ia18371023d8fc66e1797fda293a01b68c0a61c96
Signed-off-by: default avatarBen Walker <benjamin.walker@intel.com>
Reviewed-on: https://review.gerrithub.io/392422


Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent acbec142
Loading
Loading
Loading
Loading
+16 −15
Original line number Diff line number Diff line
@@ -160,6 +160,7 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp)
	const char *sn;
	size_t num_ns;
	struct spdk_nvmf_ns_params ns_list[MAX_NAMESPACES] = {};
	struct spdk_nvmf_subsystem *subsystem;

	nqn = spdk_conf_section_get_val(sp, "NQN");
	mode = spdk_conf_section_get_val(sp, "Mode");
@@ -258,7 +259,7 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp)
		num_ns++;
	}

	ret = spdk_nvmf_construct_subsystem(nqn,
	subsystem = spdk_nvmf_construct_subsystem(nqn,
			num_listen_addrs, listen_addrs,
			num_hosts, hosts, allow_any_host,
			sn,
@@ -268,7 +269,7 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp)
		free(listen_addrs_str[i]);
	}

	return ret;
	return (subsystem != NULL);
}

static int
@@ -310,7 +311,7 @@ spdk_nvmf_parse_conf(void)
	return 0;
}

int
struct spdk_nvmf_subsystem *
	spdk_nvmf_construct_subsystem(const char *name,
			      int num_listen_addresses, struct rpc_listen_address *addresses,
			      int num_hosts, char *hosts[], bool allow_any_host,
@@ -323,23 +324,23 @@ spdk_nvmf_construct_subsystem(const char *name,

	if (name == NULL) {
		SPDK_ERRLOG("No NQN specified for subsystem\n");
		return -1;
		return NULL;
	}

	if (num_listen_addresses > MAX_LISTEN_ADDRESSES) {
		SPDK_ERRLOG("invalid listen adresses number\n");
		return -1;
		return NULL;
	}

	if (num_hosts > MAX_HOSTS) {
		SPDK_ERRLOG("invalid hosts number\n");
		return -1;
		return NULL;
	}

	subsystem = nvmf_tgt_create_subsystem(name, SPDK_NVMF_SUBTYPE_NVME, num_ns);
	if (subsystem == NULL) {
		SPDK_ERRLOG("Subsystem creation failed\n");
		return -1;
		return NULL;
	}

	/* Parse Listen sections */
@@ -409,9 +410,9 @@ spdk_nvmf_construct_subsystem(const char *name,

	}

	return 0;
	return subsystem;

error:
	spdk_nvmf_delete_subsystem(subsystem);
	return -1;
	spdk_nvmf_subsystem_destroy(subsystem);
	return NULL;
}
+52 −24
Original line number Diff line number Diff line
@@ -333,6 +333,22 @@ free_rpc_subsystem(struct rpc_subsystem *req)
	free_rpc_hosts(&req->hosts);
}

static void
spdk_rpc_nvmf_subsystem_started(struct spdk_nvmf_subsystem *subsystem,
				void *cb_arg, int status)
{
	struct spdk_jsonrpc_request *request = cb_arg;
	struct spdk_json_write_ctx *w;

	w = spdk_jsonrpc_begin_result(request);
	if (w == NULL) {
		return;
	}

	spdk_json_write_bool(w, true);
	spdk_jsonrpc_end_result(request, w);
}

static const struct spdk_json_object_decoder rpc_subsystem_decoders[] = {
	{"core", offsetof(struct rpc_subsystem, core), spdk_json_decode_int32, true},
	{"mode", offsetof(struct rpc_subsystem, mode), spdk_json_decode_string, true},
@@ -349,8 +365,7 @@ spdk_rpc_construct_nvmf_subsystem(struct spdk_jsonrpc_request *request,
				  const struct spdk_json_val *params)
{
	struct rpc_subsystem req = {};
	struct spdk_json_write_ctx *w;
	int ret;
	struct spdk_nvmf_subsystem *subsystem;
	req.core = -1;	/* Explicitly set the core as the uninitialized value */

	if (spdk_json_decode_object(params, rpc_subsystem_decoders,
@@ -384,25 +399,23 @@ spdk_rpc_construct_nvmf_subsystem(struct spdk_jsonrpc_request *request,
		SPDK_NOTICELOG("Ignoring it and continuing.\n");
	}

	ret = spdk_nvmf_construct_subsystem(req.nqn,
	subsystem = spdk_nvmf_construct_subsystem(req.nqn,
			req.listen_addresses.num_listen_address,
			req.listen_addresses.addresses,
			req.hosts.num_hosts, req.hosts.hosts, req.allow_any_host,
			req.serial_number,
			req.namespaces.num_ns, req.namespaces.ns_params);
	if (ret) {
	if (!subsystem) {
		goto invalid;
	}

	free_rpc_subsystem(&req);

	w = spdk_jsonrpc_begin_result(request);
	if (w == NULL) {
		return;
	}

	spdk_json_write_bool(w, true);
	spdk_jsonrpc_end_result(request, w);
	spdk_nvmf_subsystem_start(subsystem,
				  spdk_rpc_nvmf_subsystem_started,
				  request);

	return;

invalid:
@@ -421,6 +434,24 @@ free_rpc_delete_subsystem(struct rpc_delete_subsystem *r)
	free(r->nqn);
}

static void
spdk_rpc_nvmf_subsystem_stopped(struct spdk_nvmf_subsystem *subsystem,
				void *cb_arg, int status)
{
	struct spdk_jsonrpc_request *request = cb_arg;
	struct spdk_json_write_ctx *w;

	spdk_nvmf_subsystem_destroy(subsystem);

	w = spdk_jsonrpc_begin_result(request);
	if (w == NULL) {
		return;
	}

	spdk_json_write_bool(w, true);
	spdk_jsonrpc_end_result(request, w);
}

static const struct spdk_json_object_decoder rpc_delete_subsystem_decoders[] = {
	{"nqn", offsetof(struct rpc_delete_subsystem, nqn), spdk_json_decode_string},
};
@@ -430,7 +461,7 @@ spdk_rpc_delete_nvmf_subsystem(struct spdk_jsonrpc_request *request,
			       const struct spdk_json_val *params)
{
	struct rpc_delete_subsystem req = {};
	struct spdk_json_write_ctx *w;
	struct spdk_nvmf_subsystem *subsystem;

	if (spdk_json_decode_object(params, rpc_delete_subsystem_decoders,
				    SPDK_COUNTOF(rpc_delete_subsystem_decoders),
@@ -444,20 +475,17 @@ spdk_rpc_delete_nvmf_subsystem(struct spdk_jsonrpc_request *request,
		goto invalid;
	}

	if (nvmf_tgt_shutdown_subsystem_by_nqn(req.nqn)) {
		SPDK_ERRLOG("shutdown_subsystem failed\n");
	subsystem = spdk_nvmf_tgt_find_subsystem(g_tgt.tgt, req.nqn);
	if (!subsystem) {
		goto invalid;
	}

	free_rpc_delete_subsystem(&req);

	w = spdk_jsonrpc_begin_result(request);
	if (w == NULL) {
		return;
	}
	spdk_nvmf_subsystem_stop(subsystem,
				 spdk_rpc_nvmf_subsystem_stopped,
				 request);

	spdk_json_write_bool(w, true);
	spdk_jsonrpc_end_result(request, w);
	return;

invalid:
+58 −4
Original line number Diff line number Diff line
@@ -99,7 +99,7 @@ nvmf_tgt_create_subsystem(const char *name, enum spdk_nvmf_subtype subtype, uint
		return NULL;
	}

	subsystem = spdk_nvmf_create_subsystem(g_tgt.tgt, name, subtype, num_ns);
	subsystem = spdk_nvmf_subsystem_create(g_tgt.tgt, name, subtype, num_ns);
	if (subsystem == NULL) {
		SPDK_ERRLOG("Subsystem creation failed\n");
		return NULL;
@@ -120,7 +120,7 @@ nvmf_tgt_shutdown_subsystem_by_nqn(const char *nqn)
		return -EINVAL;
	}

	spdk_nvmf_delete_subsystem(subsystem);
	spdk_nvmf_subsystem_destroy(subsystem);

	return 0;
}
@@ -187,7 +187,7 @@ nvmf_tgt_destroy_poll_group(void *ctx)
static void
nvmf_tgt_create_poll_group_done(void *ctx)
{
	g_tgt.state = NVMF_TGT_INIT_START_ACCEPTOR;
	g_tgt.state = NVMF_TGT_INIT_START_SUBSYSTEMS;
	nvmf_tgt_advance_state(NULL, NULL);
}

@@ -207,6 +207,36 @@ nvmf_tgt_create_poll_group(void *ctx)
	g_active_poll_groups++;
}

static void
nvmf_tgt_subsystem_started(struct spdk_nvmf_subsystem *subsystem,
			   void *cb_arg, int status)
{
	subsystem = spdk_nvmf_subsystem_get_next(subsystem);

	if (subsystem) {
		spdk_nvmf_subsystem_start(subsystem, nvmf_tgt_subsystem_started, NULL);
		return;
	}

	g_tgt.state = NVMF_TGT_INIT_START_ACCEPTOR;
	nvmf_tgt_advance_state(NULL, NULL);
}

static void
nvmf_tgt_subsystem_stopped(struct spdk_nvmf_subsystem *subsystem,
			   void *cb_arg, int status)
{
	subsystem = spdk_nvmf_subsystem_get_next(subsystem);

	if (subsystem) {
		spdk_nvmf_subsystem_stop(subsystem, nvmf_tgt_subsystem_stopped, NULL);
		return;
	}

	g_tgt.state = NVMF_TGT_FINI_DESTROY_POLL_GROUPS;
	nvmf_tgt_advance_state(NULL, NULL);
}

static void
nvmf_tgt_advance_state(void *arg1, void *arg2)
{
@@ -254,6 +284,18 @@ nvmf_tgt_advance_state(void *arg1, void *arg2)
					     NULL,
					     nvmf_tgt_create_poll_group_done);
			break;
		case NVMF_TGT_INIT_START_SUBSYSTEMS: {
			struct spdk_nvmf_subsystem *subsystem;

			subsystem = spdk_nvmf_subsystem_get_first(g_tgt.tgt);

			if (subsystem) {
				spdk_nvmf_subsystem_start(subsystem, nvmf_tgt_subsystem_started, NULL);
			} else {
				g_tgt.state = NVMF_TGT_INIT_START_ACCEPTOR;
			}
			break;
		}
		case NVMF_TGT_INIT_START_ACCEPTOR:
			g_acceptor_poller = spdk_poller_register(acceptor_poll, g_tgt.tgt,
					    g_spdk_nvmf_tgt_conf.acceptor_poll_rate);
@@ -268,8 +310,20 @@ nvmf_tgt_advance_state(void *arg1, void *arg2)
			break;
		case NVMF_TGT_FINI_STOP_ACCEPTOR:
			spdk_poller_unregister(&g_acceptor_poller);
			g_tgt.state = NVMF_TGT_FINI_STOP_SUBSYSTEMS;
			break;
		case NVMF_TGT_FINI_STOP_SUBSYSTEMS: {
			struct spdk_nvmf_subsystem *subsystem;

			subsystem = spdk_nvmf_subsystem_get_first(g_tgt.tgt);

			if (subsystem) {
				spdk_nvmf_subsystem_stop(subsystem, nvmf_tgt_subsystem_stopped, NULL);
			} else {
				g_tgt.state = NVMF_TGT_FINI_DESTROY_POLL_GROUPS;
			}
			break;
		}
		case NVMF_TGT_FINI_DESTROY_POLL_GROUPS:
			/* Send a message to each thread and destroy the poll group */
			spdk_for_each_thread(nvmf_tgt_destroy_poll_group,
+6 −5
Original line number Diff line number Diff line
@@ -55,10 +55,12 @@ enum nvmf_tgt_state {
	NVMF_TGT_INIT_NONE = 0,
	NVMF_TGT_INIT_PARSE_CONFIG,
	NVMF_TGT_INIT_CREATE_POLL_GROUPS,
	NVMF_TGT_INIT_START_SUBSYSTEMS,
	NVMF_TGT_INIT_START_ACCEPTOR,
	NVMF_TGT_RUNNING,
	NVMF_TGT_FINI_STOP_ACCEPTOR,
	NVMF_TGT_FINI_DESTROY_POLL_GROUPS,
	NVMF_TGT_FINI_STOP_SUBSYSTEMS,
	NVMF_TGT_FINI_FREE_RESOURCES,
	NVMF_TGT_STOPPED,
	NVMF_TGT_ERROR,
@@ -86,8 +88,7 @@ struct spdk_nvmf_ns_params {
	uint32_t nsid;
};

int
spdk_nvmf_construct_subsystem(const char *name,
struct spdk_nvmf_subsystem *spdk_nvmf_construct_subsystem(const char *name,
		int num_listen_addresses, struct rpc_listen_address *addresses,
		int num_hosts, char *hosts[], bool allow_any_host,
		const char *sn, size_t num_ns, struct spdk_nvmf_ns_params *ns_list);
+75 −7
Original line number Diff line number Diff line
@@ -132,16 +132,86 @@ int spdk_nvmf_poll_group_add(struct spdk_nvmf_poll_group *group,
int spdk_nvmf_poll_group_remove(struct spdk_nvmf_poll_group *group,
				struct spdk_nvmf_qpair *qpair);

/*
 * The NVMf subsystem, as indicated in the specification, is a collection
 * of controllers.  Any individual controller has
 * access to all the NVMe device/namespaces maintained by the subsystem.
/**
 * Create an NVMe-oF subsystem.
 *
 * Subsystems are in one of three states: Inactive, Active, Paused. This
 * state affects which operations may be performed on the subsystem. Upon
 * creation, the subsystem will be in the Inactive state and may be activated
 * by calling spdk_nvmf_subsystem_start(). No I/O will be processed in the Inactive
 * or Paused states, but changes to the state of the subsystem may be made.
 *
 * \param tgt The NVMe-oF target that will own this subsystem.
 * \param nqn The NVMe qualified name of this subsystem.
 * \param type Whether this subsystem is an I/O subsystem or a Discovery subsystem.
 * \param num_ns The number of namespaces this subsystem contains.
 *
 * \return An spdk_nvmf_subsystem or NULL on error.
 */
struct spdk_nvmf_subsystem *spdk_nvmf_create_subsystem(struct spdk_nvmf_tgt *tgt,
struct spdk_nvmf_subsystem *spdk_nvmf_subsystem_create(struct spdk_nvmf_tgt *tgt,
		const char *nqn,
		enum spdk_nvmf_subtype type,
		uint32_t num_ns);

/**
 * Destroy an NVMe-oF subsystem. A subsystem may only be destroyed when in
 * the Inactive state. See spdk_nvmf_subsystem_stop().
 *
 * \param subsystem The NVMe-oF subsystem to destroy.
 */
void spdk_nvmf_subsystem_destroy(struct spdk_nvmf_subsystem *subsystem);

typedef void (*spdk_nvmf_subsystem_state_change_done)(struct spdk_nvmf_subsystem *subsystem,
		void *cb_arg, int status);

/**
 * Transition an NVMe-oF subsystem from Inactive to Active state.
 *
 * \param subsystem The NVMe-oF subsystem.
 * \param cb_fn A function that will be called once the subsystem has changed state.
 * \param cb_arg Argument passed to cb_fn.
 *
 */
void spdk_nvmf_subsystem_start(struct spdk_nvmf_subsystem *subsystem,
			       spdk_nvmf_subsystem_state_change_done cb_fn,
			       void *cb_arg);

/**
 * Transition an NVMe-oF subsystem from Active to Inactive state.
 *
 * \param subsystem The NVMe-oF subsystem.
 * \param cb_fn A function that will be called once the subsystem has changed state.
 * \param cb_arg Argument passed to cb_fn.
 *
 */
void spdk_nvmf_subsystem_stop(struct spdk_nvmf_subsystem *subsystem,
			      spdk_nvmf_subsystem_state_change_done cb_fn,
			      void *cb_arg);

/**
 * Transition an NVMe-oF subsystem from Active to Paused state.
 *
 * \param subsystem The NVMe-oF subsystem.
 * \param cb_fn A function that will be called once the subsystem has changed state.
 * \param cb_arg Argument passed to cb_fn.
 *
 */
void spdk_nvmf_subsystem_pause(struct spdk_nvmf_subsystem *subsystem,
			       spdk_nvmf_subsystem_state_change_done cb_fn,
			       void *cb_arg);

/**
 * Transition an NVMe-oF subsystem from Paused to Active state.
 *
 * \param subsystem The NVMe-oF subsystem.
 * \param cb_fn A function that will be called once the subsystem has changed state.
 * \param cb_arg Argument passed to cb_fn.
 *
 */
void spdk_nvmf_subsystem_resume(struct spdk_nvmf_subsystem *subsystem,
				spdk_nvmf_subsystem_state_change_done cb_fn,
				void *cb_arg);

/**
 * Search the target for a subsystem with the given NQN
 */
@@ -158,8 +228,6 @@ struct spdk_nvmf_subsystem *spdk_nvmf_subsystem_get_first(struct spdk_nvmf_tgt *
 */
struct spdk_nvmf_subsystem *spdk_nvmf_subsystem_get_next(struct spdk_nvmf_subsystem *subsystem);

void spdk_nvmf_delete_subsystem(struct spdk_nvmf_subsystem *subsystem);

/**
 * Allow the given host NQN to connect to the given subsystem.
 *
Loading