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: Ben Walker <benjamin.walker@intel.com> Reviewed-on: https://review.gerrithub.io/392422 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
parent
acbec142ae
commit
95ac75aabe
@ -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,17 +259,17 @@ spdk_nvmf_parse_subsystem(struct spdk_conf_section *sp)
|
||||
num_ns++;
|
||||
}
|
||||
|
||||
ret = spdk_nvmf_construct_subsystem(nqn,
|
||||
num_listen_addrs, listen_addrs,
|
||||
num_hosts, hosts, allow_any_host,
|
||||
sn,
|
||||
num_ns, ns_list);
|
||||
subsystem = spdk_nvmf_construct_subsystem(nqn,
|
||||
num_listen_addrs, listen_addrs,
|
||||
num_hosts, hosts, allow_any_host,
|
||||
sn,
|
||||
num_ns, ns_list);
|
||||
|
||||
for (i = 0; i < MAX_LISTEN_ADDRESSES; i++) {
|
||||
free(listen_addrs_str[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return (subsystem != NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -310,8 +311,8 @@ spdk_nvmf_parse_conf(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
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) {
|
||||
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 (!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:
|
||||
|
@ -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_DESTROY_POLL_GROUPS;
|
||||
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,
|
||||
|
@ -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,11 +88,10 @@ struct spdk_nvmf_ns_params {
|
||||
uint32_t nsid;
|
||||
};
|
||||
|
||||
int
|
||||
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);
|
||||
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);
|
||||
|
||||
int
|
||||
nvmf_tgt_shutdown_subsystem_by_nqn(const char *nqn);
|
||||
|
@ -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.
|
||||
*
|
||||
|
173
lib/nvmf/nvmf.c
173
lib/nvmf/nvmf.c
@ -207,7 +207,7 @@ spdk_nvmf_tgt_destroy(struct spdk_nvmf_tgt *tgt)
|
||||
if (tgt->subsystems) {
|
||||
for (i = 0; i < tgt->max_sid; i++) {
|
||||
if (tgt->subsystems[i]) {
|
||||
spdk_nvmf_delete_subsystem(tgt->subsystems[i]);
|
||||
spdk_nvmf_subsystem_destroy(tgt->subsystems[i]);
|
||||
}
|
||||
}
|
||||
free(tgt->subsystems);
|
||||
@ -416,18 +416,19 @@ spdk_nvmf_poll_group_add_transport(struct spdk_nvmf_poll_group *group,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem)
|
||||
static int
|
||||
poll_group_update_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem)
|
||||
{
|
||||
struct spdk_nvmf_subsystem_poll_group *sgroup;
|
||||
struct spdk_nvmf_ns *ns;
|
||||
uint32_t new_num_channels, old_num_channels;
|
||||
void *buf;
|
||||
uint32_t i;
|
||||
struct spdk_nvmf_ns *ns;
|
||||
|
||||
if (subsystem->id >= group->num_sgroups) {
|
||||
void *buf;
|
||||
|
||||
|
||||
buf = realloc(group->sgroups, (subsystem->id + 1) * sizeof(*sgroup));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
@ -438,46 +439,92 @@ spdk_nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
/* Zero out the newly allocated memory */
|
||||
memset(&group->sgroups[group->num_sgroups],
|
||||
0,
|
||||
(subsystem->id + 1 - group->num_sgroups) * sizeof(struct spdk_nvmf_subsystem_poll_group));
|
||||
(subsystem->id + 1 - group->num_sgroups) * sizeof(group->sgroups[0]));
|
||||
|
||||
group->num_sgroups = subsystem->id + 1;
|
||||
}
|
||||
|
||||
sgroup = &group->sgroups[subsystem->id];
|
||||
|
||||
sgroup->num_channels = subsystem->max_nsid;
|
||||
sgroup->channels = calloc(sgroup->num_channels, sizeof(struct spdk_io_channel *));
|
||||
if (!sgroup->channels) {
|
||||
return -1;
|
||||
}
|
||||
new_num_channels = subsystem->max_nsid;
|
||||
old_num_channels = sgroup->num_channels;
|
||||
|
||||
for (i = 0; i < sgroup->num_channels; i++) {
|
||||
ns = &subsystem->ns[i];
|
||||
if (ns->allocated && sgroup->channels[i] == NULL) {
|
||||
sgroup->channels[i] = spdk_bdev_get_io_channel(ns->desc);
|
||||
if (sgroup->channels[i] == NULL) {
|
||||
return -1;
|
||||
if (new_num_channels == old_num_channels) {
|
||||
/* Nothing to do */
|
||||
} else if (old_num_channels == 0) {
|
||||
/* First allocation */
|
||||
sgroup->channels = calloc(new_num_channels, sizeof(sgroup->channels[0]));
|
||||
if (!sgroup->channels) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
sgroup->num_channels = new_num_channels;
|
||||
|
||||
/* Initialize new channels */
|
||||
for (i = old_num_channels; i < new_num_channels; i++) {
|
||||
ns = &subsystem->ns[i];
|
||||
if (ns->allocated) {
|
||||
sgroup->channels[i] = spdk_bdev_get_io_channel(ns->desc);
|
||||
} else {
|
||||
sgroup->channels[i] = NULL;
|
||||
}
|
||||
}
|
||||
} else if (new_num_channels < old_num_channels) {
|
||||
/* Free the extra I/O channels */
|
||||
for (i = new_num_channels; i < old_num_channels; i++) {
|
||||
if (sgroup->channels[i]) {
|
||||
spdk_put_io_channel(sgroup->channels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Shrink array */
|
||||
buf = realloc(sgroup->channels, new_num_channels * sizeof(sgroup->channels[0]));
|
||||
if (new_num_channels > 0 && !buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sgroup->channels = buf;
|
||||
sgroup->num_channels = new_num_channels;
|
||||
} else {
|
||||
/* Grow array */
|
||||
buf = realloc(sgroup->channels, new_num_channels * sizeof(sgroup->channels[0]));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sgroup->channels = buf;
|
||||
sgroup->num_channels = new_num_channels;
|
||||
|
||||
/* Initialize new channels */
|
||||
for (i = old_num_channels; i < new_num_channels; i++) {
|
||||
ns = &subsystem->ns[i];
|
||||
if (ns->allocated) {
|
||||
sgroup->channels[i] = spdk_bdev_get_io_channel(ns->desc);
|
||||
} else {
|
||||
sgroup->channels[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Handle namespaces where the bdev was swapped out */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_nvmf_poll_group_remove_ns(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_ns *ns)
|
||||
spdk_nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem)
|
||||
{
|
||||
struct spdk_nvmf_subsystem_poll_group *sgroup;
|
||||
uint32_t nsid = ns->id - 1;
|
||||
int rc;
|
||||
|
||||
sgroup = &group->sgroups[ns->subsystem->id];
|
||||
|
||||
if (sgroup->channels[nsid]) {
|
||||
spdk_put_io_channel(sgroup->channels[nsid]);
|
||||
sgroup->channels[nsid] = NULL;
|
||||
rc = poll_group_update_subsystem(group, subsystem);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
sgroup = &group->sgroups[subsystem->id];
|
||||
sgroup->state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -505,46 +552,52 @@ spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
}
|
||||
|
||||
int
|
||||
spdk_nvmf_poll_group_add_ns(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem,
|
||||
struct spdk_nvmf_ns *ns)
|
||||
spdk_nvmf_poll_group_pause_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem)
|
||||
{
|
||||
struct spdk_nvmf_subsystem_poll_group *sgroup;
|
||||
uint32_t ns_idx;
|
||||
|
||||
sgroup = &group->sgroups[subsystem->id];
|
||||
|
||||
/* The index into the channels array is (nsid - 1) */
|
||||
ns_idx = ns->id - 1;
|
||||
|
||||
if (ns_idx >= sgroup->num_channels) {
|
||||
void *buf;
|
||||
|
||||
buf = realloc(sgroup->channels,
|
||||
ns->id * sizeof(struct spdk_io_channel *));
|
||||
if (!buf) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Zero out the newly allocated memory */
|
||||
memset(&sgroup->channels[sgroup->num_channels],
|
||||
0,
|
||||
(ns->id - sgroup->num_channels) * sizeof(struct spdk_io_channel *));
|
||||
|
||||
sgroup->num_channels = ns->id;
|
||||
sgroup->channels = buf;
|
||||
}
|
||||
|
||||
/* The channel could have been created in response to a subsystem creation
|
||||
* event already propagating through the system */
|
||||
if (sgroup->channels[ns_idx] == NULL) {
|
||||
sgroup->channels[ns_idx] = spdk_bdev_get_io_channel(ns->desc);
|
||||
}
|
||||
|
||||
if (sgroup->channels[ns_idx] == NULL) {
|
||||
if (subsystem->id >= group->num_sgroups) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sgroup = &group->sgroups[subsystem->id];
|
||||
if (sgroup == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(sgroup->state == SPDK_NVMF_SUBSYSTEM_ACTIVE);
|
||||
/* TODO: This currently does not quiesce I/O */
|
||||
sgroup->state = SPDK_NVMF_SUBSYSTEM_PAUSED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_nvmf_poll_group_resume_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem)
|
||||
{
|
||||
struct spdk_nvmf_subsystem_poll_group *sgroup;
|
||||
int rc;
|
||||
|
||||
if (subsystem->id >= group->num_sgroups) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sgroup = &group->sgroups[subsystem->id];
|
||||
if (sgroup == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
assert(sgroup->state == SPDK_NVMF_SUBSYSTEM_PAUSED);
|
||||
|
||||
rc = poll_group_update_subsystem(group, subsystem);
|
||||
if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
sgroup->state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,16 @@
|
||||
|
||||
#define SPDK_NVMF_DEFAULT_NUM_CTRLRS_PER_LCORE 1
|
||||
|
||||
enum spdk_nvmf_subsystem_state {
|
||||
SPDK_NVMF_SUBSYSTEM_INACTIVE = 0,
|
||||
SPDK_NVMF_SUBSYSTEM_ACTIVATING,
|
||||
SPDK_NVMF_SUBSYSTEM_ACTIVE,
|
||||
SPDK_NVMF_SUBSYSTEM_PAUSING,
|
||||
SPDK_NVMF_SUBSYSTEM_PAUSED,
|
||||
SPDK_NVMF_SUBSYSTEM_RESUMING,
|
||||
SPDK_NVMF_SUBSYSTEM_DEACTIVATING,
|
||||
};
|
||||
|
||||
struct spdk_nvmf_tgt {
|
||||
struct spdk_nvmf_tgt_opts opts;
|
||||
|
||||
@ -81,6 +91,8 @@ struct spdk_nvmf_subsystem_poll_group {
|
||||
/* Array of channels for each namespace indexed by nsid - 1 */
|
||||
struct spdk_io_channel **channels;
|
||||
uint32_t num_channels;
|
||||
|
||||
enum spdk_nvmf_subsystem_state state;
|
||||
};
|
||||
|
||||
struct spdk_nvmf_poll_group {
|
||||
@ -91,7 +103,6 @@ struct spdk_nvmf_poll_group {
|
||||
/* Array of poll groups indexed by subsystem id (sid) */
|
||||
struct spdk_nvmf_subsystem_poll_group *sgroups;
|
||||
uint32_t num_sgroups;
|
||||
|
||||
};
|
||||
|
||||
typedef enum _spdk_nvmf_request_exec_status {
|
||||
@ -185,7 +196,9 @@ struct spdk_nvmf_ctrlr {
|
||||
};
|
||||
|
||||
struct spdk_nvmf_subsystem {
|
||||
uint32_t id;
|
||||
uint32_t id;
|
||||
enum spdk_nvmf_subsystem_state state;
|
||||
|
||||
char subnqn[SPDK_NVMF_NQN_MAX_LEN + 1];
|
||||
enum spdk_nvmf_subtype subtype;
|
||||
uint16_t next_cntlid;
|
||||
@ -218,11 +231,10 @@ int spdk_nvmf_poll_group_add_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem);
|
||||
int spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem);
|
||||
int spdk_nvmf_poll_group_add_ns(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem,
|
||||
struct spdk_nvmf_ns *ns);
|
||||
int spdk_nvmf_poll_group_remove_ns(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_ns *ns);
|
||||
int spdk_nvmf_poll_group_pause_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem);
|
||||
int spdk_nvmf_poll_group_resume_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem);
|
||||
void spdk_nvmf_request_exec(struct spdk_nvmf_request *req);
|
||||
int spdk_nvmf_request_complete(struct spdk_nvmf_request *req);
|
||||
int spdk_nvmf_request_abort(struct spdk_nvmf_request *req);
|
||||
|
@ -71,25 +71,8 @@ spdk_nvmf_valid_nqn(const char *nqn)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_nvmf_subsystem_create_done(struct spdk_io_channel_iter *i, int status)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_nvmf_subsystem_add_to_poll_group(struct spdk_io_channel_iter *i)
|
||||
{
|
||||
struct spdk_nvmf_subsystem *subsystem = spdk_io_channel_iter_get_ctx(i);
|
||||
struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
|
||||
struct spdk_nvmf_poll_group *group = spdk_io_channel_get_ctx(ch);
|
||||
int rc;
|
||||
|
||||
rc = spdk_nvmf_poll_group_add_subsystem(group, subsystem);
|
||||
spdk_for_each_channel_continue(i, rc);
|
||||
}
|
||||
|
||||
struct spdk_nvmf_subsystem *
|
||||
spdk_nvmf_create_subsystem(struct spdk_nvmf_tgt *tgt,
|
||||
spdk_nvmf_subsystem_create(struct spdk_nvmf_tgt *tgt,
|
||||
const char *nqn,
|
||||
enum spdk_nvmf_subtype type,
|
||||
uint32_t num_ns)
|
||||
@ -129,6 +112,7 @@ spdk_nvmf_create_subsystem(struct spdk_nvmf_tgt *tgt,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
subsystem->state = SPDK_NVMF_SUBSYSTEM_INACTIVE;
|
||||
subsystem->tgt = tgt;
|
||||
subsystem->id = sid;
|
||||
subsystem->subtype = type;
|
||||
@ -152,67 +136,23 @@ spdk_nvmf_create_subsystem(struct spdk_nvmf_tgt *tgt,
|
||||
tgt->subsystems[sid] = subsystem;
|
||||
tgt->discovery_genctr++;
|
||||
|
||||
/* Send a message to each poll group to notify it that a new subsystem
|
||||
* is available.
|
||||
* TODO: This call does not currently allow the user to wait for these
|
||||
* messages to propagate. It also does not protect against two calls
|
||||
* to this function overlapping
|
||||
*/
|
||||
spdk_for_each_channel(tgt,
|
||||
spdk_nvmf_subsystem_add_to_poll_group,
|
||||
subsystem,
|
||||
spdk_nvmf_subsystem_create_done);
|
||||
|
||||
return subsystem;
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_nvmf_subsystem_delete_done(struct spdk_io_channel_iter *i, int status)
|
||||
{
|
||||
struct spdk_nvmf_tgt *tgt = spdk_io_channel_iter_get_io_device(i);
|
||||
struct spdk_nvmf_subsystem *subsystem = spdk_io_channel_iter_get_ctx(i);
|
||||
struct spdk_nvmf_ns *ns;
|
||||
|
||||
for (ns = spdk_nvmf_subsystem_get_first_ns(subsystem); ns != NULL;
|
||||
ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns)) {
|
||||
if (ns->bdev == NULL) {
|
||||
continue;
|
||||
}
|
||||
spdk_bdev_close(ns->desc);
|
||||
}
|
||||
|
||||
free(subsystem->ns);
|
||||
|
||||
tgt->subsystems[subsystem->id] = NULL;
|
||||
tgt->discovery_genctr++;
|
||||
|
||||
free(subsystem);
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_nvmf_subsystem_remove_from_poll_group(struct spdk_io_channel_iter *i)
|
||||
{
|
||||
struct spdk_nvmf_subsystem *subsystem = spdk_io_channel_iter_get_ctx(i);
|
||||
struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
|
||||
struct spdk_nvmf_poll_group *group = spdk_io_channel_get_ctx(ch);
|
||||
int rc;
|
||||
|
||||
rc = spdk_nvmf_poll_group_remove_subsystem(group, subsystem);
|
||||
|
||||
spdk_for_each_channel_continue(i, rc);
|
||||
}
|
||||
|
||||
void
|
||||
spdk_nvmf_delete_subsystem(struct spdk_nvmf_subsystem *subsystem)
|
||||
spdk_nvmf_subsystem_destroy(struct spdk_nvmf_subsystem *subsystem)
|
||||
{
|
||||
struct spdk_nvmf_listener *listener, *listener_tmp;
|
||||
struct spdk_nvmf_host *host, *host_tmp;
|
||||
struct spdk_nvmf_ctrlr *ctrlr, *ctrlr_tmp;
|
||||
struct spdk_nvmf_ns *ns;
|
||||
|
||||
if (!subsystem) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE);
|
||||
|
||||
SPDK_DEBUGLOG(SPDK_LOG_NVMF, "subsystem is %p\n", subsystem);
|
||||
|
||||
TAILQ_FOREACH_SAFE(listener, &subsystem->listeners, link, listener_tmp) {
|
||||
@ -230,16 +170,210 @@ spdk_nvmf_delete_subsystem(struct spdk_nvmf_subsystem *subsystem)
|
||||
spdk_nvmf_ctrlr_destruct(ctrlr);
|
||||
}
|
||||
|
||||
/* Send a message to each poll group to notify it that a subsystem
|
||||
* is no longer available.
|
||||
* TODO: This call does not currently allow the user to wait for these
|
||||
* messages to propagate. It also does not protect against two calls
|
||||
* to this function overlapping
|
||||
*/
|
||||
for (ns = spdk_nvmf_subsystem_get_first_ns(subsystem); ns != NULL;
|
||||
ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns)) {
|
||||
if (ns->bdev == NULL) {
|
||||
continue;
|
||||
}
|
||||
spdk_bdev_close(ns->desc);
|
||||
}
|
||||
|
||||
free(subsystem->ns);
|
||||
|
||||
subsystem->tgt->subsystems[subsystem->id] = NULL;
|
||||
subsystem->tgt->discovery_genctr++;
|
||||
|
||||
free(subsystem);
|
||||
}
|
||||
|
||||
static int
|
||||
spdk_nvmf_subsystem_set_state(struct spdk_nvmf_subsystem *subsystem,
|
||||
enum spdk_nvmf_subsystem_state state)
|
||||
{
|
||||
enum spdk_nvmf_subsystem_state actual_old_state, expected_old_state;
|
||||
|
||||
switch (state) {
|
||||
case SPDK_NVMF_SUBSYSTEM_INACTIVE:
|
||||
expected_old_state = SPDK_NVMF_SUBSYSTEM_DEACTIVATING;
|
||||
break;
|
||||
case SPDK_NVMF_SUBSYSTEM_ACTIVATING:
|
||||
expected_old_state = SPDK_NVMF_SUBSYSTEM_INACTIVE;
|
||||
break;
|
||||
case SPDK_NVMF_SUBSYSTEM_ACTIVE:
|
||||
expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVATING;
|
||||
break;
|
||||
case SPDK_NVMF_SUBSYSTEM_PAUSING:
|
||||
expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
|
||||
break;
|
||||
case SPDK_NVMF_SUBSYSTEM_PAUSED:
|
||||
expected_old_state = SPDK_NVMF_SUBSYSTEM_PAUSING;
|
||||
break;
|
||||
case SPDK_NVMF_SUBSYSTEM_RESUMING:
|
||||
expected_old_state = SPDK_NVMF_SUBSYSTEM_PAUSED;
|
||||
break;
|
||||
case SPDK_NVMF_SUBSYSTEM_DEACTIVATING:
|
||||
expected_old_state = SPDK_NVMF_SUBSYSTEM_ACTIVE;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
actual_old_state = __sync_val_compare_and_swap(&subsystem->state, expected_old_state, state);
|
||||
if (actual_old_state != expected_old_state) {
|
||||
if (actual_old_state == SPDK_NVMF_SUBSYSTEM_RESUMING &&
|
||||
state == SPDK_NVMF_SUBSYSTEM_ACTIVE) {
|
||||
expected_old_state = SPDK_NVMF_SUBSYSTEM_RESUMING;
|
||||
}
|
||||
actual_old_state = __sync_val_compare_and_swap(&subsystem->state, expected_old_state, state);
|
||||
}
|
||||
assert(actual_old_state == expected_old_state);
|
||||
return actual_old_state - expected_old_state;
|
||||
}
|
||||
|
||||
struct subsystem_state_change_ctx {
|
||||
struct spdk_nvmf_subsystem *subsystem;
|
||||
|
||||
enum spdk_nvmf_subsystem_state requested_state;
|
||||
|
||||
spdk_nvmf_subsystem_state_change_done cb_fn;
|
||||
void *cb_arg;
|
||||
};
|
||||
|
||||
static void
|
||||
subsystem_state_change_done(struct spdk_io_channel_iter *i, int status)
|
||||
{
|
||||
struct subsystem_state_change_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
|
||||
|
||||
if (status == 0) {
|
||||
status = spdk_nvmf_subsystem_set_state(ctx->subsystem, ctx->requested_state);
|
||||
if (status) {
|
||||
status = -1;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->cb_fn(ctx->subsystem, ctx->cb_arg, status);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
subsystem_state_change_on_pg(struct spdk_io_channel_iter *i)
|
||||
{
|
||||
struct subsystem_state_change_ctx *ctx;
|
||||
struct spdk_io_channel *ch;
|
||||
struct spdk_nvmf_poll_group *group;
|
||||
int rc = -1;
|
||||
|
||||
ctx = spdk_io_channel_iter_get_ctx(i);
|
||||
ch = spdk_io_channel_iter_get_channel(i);
|
||||
group = spdk_io_channel_get_ctx(ch);
|
||||
|
||||
switch (ctx->requested_state) {
|
||||
case SPDK_NVMF_SUBSYSTEM_INACTIVE:
|
||||
rc = spdk_nvmf_poll_group_remove_subsystem(group, ctx->subsystem);
|
||||
break;
|
||||
case SPDK_NVMF_SUBSYSTEM_ACTIVE:
|
||||
if (ctx->subsystem->state == SPDK_NVMF_SUBSYSTEM_ACTIVATING) {
|
||||
rc = spdk_nvmf_poll_group_add_subsystem(group, ctx->subsystem);
|
||||
} else if (ctx->subsystem->state == SPDK_NVMF_SUBSYSTEM_RESUMING) {
|
||||
rc = spdk_nvmf_poll_group_resume_subsystem(group, ctx->subsystem);
|
||||
}
|
||||
break;
|
||||
case SPDK_NVMF_SUBSYSTEM_PAUSED:
|
||||
rc = spdk_nvmf_poll_group_pause_subsystem(group, ctx->subsystem);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
spdk_for_each_channel_continue(i, rc);
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_nvmf_subsystem_state_change(struct spdk_nvmf_subsystem *subsystem,
|
||||
enum spdk_nvmf_subsystem_state requested_state,
|
||||
spdk_nvmf_subsystem_state_change_done cb_fn,
|
||||
void *cb_arg)
|
||||
{
|
||||
struct subsystem_state_change_ctx *ctx;
|
||||
enum spdk_nvmf_subsystem_state intermediate_state;
|
||||
int rc;
|
||||
|
||||
switch (requested_state) {
|
||||
case SPDK_NVMF_SUBSYSTEM_INACTIVE:
|
||||
intermediate_state = SPDK_NVMF_SUBSYSTEM_DEACTIVATING;
|
||||
break;
|
||||
case SPDK_NVMF_SUBSYSTEM_ACTIVE:
|
||||
if (subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED) {
|
||||
intermediate_state = SPDK_NVMF_SUBSYSTEM_RESUMING;
|
||||
} else {
|
||||
intermediate_state = SPDK_NVMF_SUBSYSTEM_ACTIVATING;
|
||||
}
|
||||
break;
|
||||
case SPDK_NVMF_SUBSYSTEM_PAUSED:
|
||||
intermediate_state = SPDK_NVMF_SUBSYSTEM_PAUSING;
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
cb_fn(subsystem, cb_arg, -EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = calloc(1, sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
cb_fn(subsystem, cb_arg, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = spdk_nvmf_subsystem_set_state(subsystem, intermediate_state);
|
||||
if (rc) {
|
||||
free(ctx);
|
||||
cb_fn(subsystem, cb_arg, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->subsystem = subsystem;
|
||||
ctx->requested_state = requested_state;
|
||||
ctx->cb_fn = cb_fn;
|
||||
ctx->cb_arg = cb_arg;
|
||||
|
||||
spdk_for_each_channel(subsystem->tgt,
|
||||
spdk_nvmf_subsystem_remove_from_poll_group,
|
||||
subsystem,
|
||||
spdk_nvmf_subsystem_delete_done);
|
||||
subsystem_state_change_on_pg,
|
||||
ctx,
|
||||
subsystem_state_change_done);
|
||||
}
|
||||
|
||||
void
|
||||
spdk_nvmf_subsystem_start(struct spdk_nvmf_subsystem *subsystem,
|
||||
spdk_nvmf_subsystem_state_change_done cb_fn,
|
||||
void *cb_arg)
|
||||
{
|
||||
spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_ACTIVE, cb_fn, cb_arg);
|
||||
}
|
||||
|
||||
void
|
||||
spdk_nvmf_subsystem_stop(struct spdk_nvmf_subsystem *subsystem,
|
||||
spdk_nvmf_subsystem_state_change_done cb_fn,
|
||||
void *cb_arg)
|
||||
{
|
||||
spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_INACTIVE, cb_fn, cb_arg);
|
||||
}
|
||||
|
||||
void
|
||||
spdk_nvmf_subsystem_pause(struct spdk_nvmf_subsystem *subsystem,
|
||||
spdk_nvmf_subsystem_state_change_done cb_fn,
|
||||
void *cb_arg)
|
||||
{
|
||||
spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_PAUSED, cb_fn, cb_arg);
|
||||
}
|
||||
|
||||
void
|
||||
spdk_nvmf_subsystem_resume(struct spdk_nvmf_subsystem *subsystem,
|
||||
spdk_nvmf_subsystem_state_change_done cb_fn,
|
||||
void *cb_arg)
|
||||
{
|
||||
spdk_nvmf_subsystem_state_change(subsystem, SPDK_NVMF_SUBSYSTEM_ACTIVE, cb_fn, cb_arg);
|
||||
}
|
||||
|
||||
struct spdk_nvmf_subsystem *
|
||||
@ -427,29 +561,6 @@ spdk_nvmf_listener_get_trid(struct spdk_nvmf_listener *listener)
|
||||
return &listener->trid;
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_nvmf_remove_ns_done(struct spdk_io_channel_iter *i, int status)
|
||||
{
|
||||
struct spdk_nvmf_ns *ns = spdk_io_channel_iter_get_ctx(i);
|
||||
struct spdk_nvmf_subsystem *subsystem = ns->subsystem;
|
||||
|
||||
spdk_bdev_close(ns->desc);
|
||||
ns->allocated = false;
|
||||
subsystem->num_allocated_nsid--;
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_nvmf_subsystem_remove_ns_from_poll_group(struct spdk_io_channel_iter *i)
|
||||
{
|
||||
struct spdk_nvmf_ns *ns = spdk_io_channel_iter_get_ctx(i);
|
||||
struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
|
||||
struct spdk_nvmf_poll_group *group = spdk_io_channel_get_ctx(ch);
|
||||
int rc;
|
||||
|
||||
rc = spdk_nvmf_poll_group_remove_ns(group, ns);
|
||||
spdk_for_each_channel_continue(i, rc);
|
||||
}
|
||||
|
||||
int
|
||||
spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t nsid)
|
||||
{
|
||||
@ -464,31 +575,13 @@ spdk_nvmf_subsystem_remove_ns(struct spdk_nvmf_subsystem *subsystem, uint32_t ns
|
||||
return -1;
|
||||
}
|
||||
|
||||
spdk_for_each_channel(ns->subsystem->tgt,
|
||||
spdk_nvmf_subsystem_remove_ns_from_poll_group,
|
||||
ns,
|
||||
spdk_nvmf_remove_ns_done);
|
||||
spdk_bdev_close(ns->desc);
|
||||
ns->allocated = false;
|
||||
subsystem->num_allocated_nsid--;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_nvmf_subsystem_add_ns_done(struct spdk_io_channel_iter *i, int status)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
spdk_nvmf_subsystem_ns_update_poll_group(struct spdk_io_channel_iter *i)
|
||||
{
|
||||
struct spdk_nvmf_ns *ns = spdk_io_channel_iter_get_ctx(i);
|
||||
struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
|
||||
struct spdk_nvmf_poll_group *group = spdk_io_channel_get_ctx(ch);
|
||||
int rc;
|
||||
|
||||
rc = spdk_nvmf_poll_group_add_ns(group, ns->subsystem, ns);
|
||||
spdk_for_each_channel_continue(i, rc);
|
||||
}
|
||||
|
||||
static void
|
||||
_spdk_nvmf_ns_hot_remove(void *ctx)
|
||||
{
|
||||
@ -516,6 +609,9 @@ spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bd
|
||||
uint32_t i;
|
||||
int rc;
|
||||
|
||||
assert(subsystem->state == SPDK_NVMF_SUBSYSTEM_INACTIVE ||
|
||||
subsystem->state == SPDK_NVMF_SUBSYSTEM_PAUSED);
|
||||
|
||||
if (nsid == SPDK_NVME_GLOBAL_NS_TAG) {
|
||||
SPDK_ERRLOG("Invalid NSID %" PRIu32 "\n", nsid);
|
||||
return 0;
|
||||
@ -590,17 +686,6 @@ spdk_nvmf_subsystem_add_ns(struct spdk_nvmf_subsystem *subsystem, struct spdk_bd
|
||||
subsystem->max_nsid = spdk_max(subsystem->max_nsid, nsid);
|
||||
subsystem->num_allocated_nsid++;
|
||||
|
||||
/* Send a message to each poll group to notify it that a new namespace
|
||||
* is available.
|
||||
* TODO: This call does not currently allow the user to wait for these
|
||||
* messages to propagate. It also does not protect against two calls
|
||||
* to this function overlapping
|
||||
*/
|
||||
spdk_for_each_channel(subsystem->tgt,
|
||||
spdk_nvmf_subsystem_ns_update_poll_group,
|
||||
ns,
|
||||
spdk_nvmf_subsystem_add_ns_done);
|
||||
|
||||
return nsid;
|
||||
}
|
||||
|
||||
|
@ -160,16 +160,15 @@ spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
}
|
||||
|
||||
int
|
||||
spdk_nvmf_poll_group_remove_ns(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_ns *ns)
|
||||
spdk_nvmf_poll_group_pause_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_nvmf_poll_group_add_ns(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem,
|
||||
struct spdk_nvmf_ns *ns)
|
||||
spdk_nvmf_poll_group_resume_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -200,7 +199,7 @@ test_discovery_log(void)
|
||||
struct spdk_nvme_transport_id trid = {};
|
||||
|
||||
/* Add one subsystem and verify that the discovery log contains it */
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, "nqn.2016-06.io.spdk:subsystem1",
|
||||
subsystem = spdk_nvmf_subsystem_create(&tgt, "nqn.2016-06.io.spdk:subsystem1",
|
||||
SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem != NULL);
|
||||
|
||||
@ -249,7 +248,7 @@ test_discovery_log(void)
|
||||
offsetof(struct spdk_nvmf_discovery_log_page, entries[0]),
|
||||
sizeof(*entry));
|
||||
CU_ASSERT(entry->trtype == 42);
|
||||
spdk_nvmf_delete_subsystem(subsystem);
|
||||
spdk_nvmf_subsystem_destroy(subsystem);
|
||||
free(tgt.subsystems);
|
||||
free(tgt.discovery_log_page);
|
||||
}
|
||||
|
@ -117,16 +117,15 @@ spdk_nvmf_poll_group_remove_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
}
|
||||
|
||||
int
|
||||
spdk_nvmf_poll_group_remove_ns(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_ns *ns)
|
||||
spdk_nvmf_poll_group_pause_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_nvmf_poll_group_add_ns(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem,
|
||||
struct spdk_nvmf_ns *ns)
|
||||
spdk_nvmf_poll_group_resume_subsystem(struct spdk_nvmf_poll_group *group,
|
||||
struct spdk_nvmf_subsystem *subsystem)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -240,27 +239,27 @@ nvmf_test_create_subsystem(void)
|
||||
struct spdk_nvmf_subsystem *subsystem;
|
||||
|
||||
strncpy(nqn, "nqn.2016-06.io.spdk:subsystem1", sizeof(nqn));
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem != NULL);
|
||||
CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
|
||||
spdk_nvmf_delete_subsystem(subsystem);
|
||||
spdk_nvmf_subsystem_destroy(subsystem);
|
||||
|
||||
/* Longest valid name */
|
||||
strncpy(nqn, "nqn.2016-06.io.spdk:", sizeof(nqn));
|
||||
memset(nqn + strlen(nqn), 'a', 223 - strlen(nqn));
|
||||
nqn[223] = '\0';
|
||||
CU_ASSERT(strlen(nqn) == 223);
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
SPDK_CU_ASSERT_FATAL(subsystem != NULL);
|
||||
CU_ASSERT_STRING_EQUAL(subsystem->subnqn, nqn);
|
||||
spdk_nvmf_delete_subsystem(subsystem);
|
||||
spdk_nvmf_subsystem_destroy(subsystem);
|
||||
|
||||
/* Name that is one byte longer than allowed */
|
||||
strncpy(nqn, "nqn.2016-06.io.spdk:", sizeof(nqn));
|
||||
memset(nqn + strlen(nqn), 'a', 224 - strlen(nqn));
|
||||
nqn[224] = '\0';
|
||||
CU_ASSERT(strlen(nqn) == 224);
|
||||
subsystem = spdk_nvmf_create_subsystem(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
subsystem = spdk_nvmf_subsystem_create(&tgt, nqn, SPDK_NVMF_SUBTYPE_NVME, 0);
|
||||
CU_ASSERT(subsystem == NULL);
|
||||
|
||||
free(tgt.subsystems);
|
||||
|
Loading…
Reference in New Issue
Block a user