Commit 6f2e8fa5 authored by Shuhei Matsumoto's avatar Shuhei Matsumoto Committed by Tomasz Zawadzki
Browse files

bdev/nvme: Add nvme_bdev_ctrlr_op_rpc() to operate all ctrlrs in a nbdev_ctrlr



The bdev_nvme_reset_controller RPC was convenient but did not support
multipath configuration. Support multipath configuration in this patch.

Add nvme_bdev_ctrlr_op_rpc() to operate all ctrlrs in a nbdev_ctrlr.

Add a new parameter cntlid to the bdev_nvme_reset_controller RPC.

The bdev_nvme_reset_controller RPC calls nvme_ctrlr_op_rpc() if cntlid
is omitted or nvme_bdev_ctrlr_op_rpc() otherwise.

Signed-off-by: default avatarShuhei Matsumoto <smatsumoto@nvidia.com>
Change-Id: I9e71db79ad395428bb07c4bbf64d615fda711420
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/16744


Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarRichael <richael.zhuang@arm.com>
Community-CI: Mellanox Build Bot
Reviewed-by: default avatarAleksey Marchuk <alexeymar@nvidia.com>
parent 462ad02f
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -4119,7 +4119,12 @@ Example response:

### bdev_nvme_reset_controller {#rpc_bdev_nvme_reset_controller}

Reset NVMe controller.
For non NVMe multipath, reset an NVMe controller whose name is given by the `name` parameter.

For NVMe multipath, an NVMe bdev controller is created and it aggregates multiple NVMe controllers.
The `name` parameter is an NVMe bdev controller name and the `cntlid` parameter is used to identify
an NVMe controller in the NVMe bdev controller. Reset only one NVMe-oF controlelr if the `cntlid`
parameter is specified, or all NVMe-oF controllers in an NVMe bdev controller if it is omitted.

Returns true if the controller reset was successful, false otherwise.

@@ -4127,7 +4132,8 @@ Returns true if the controller reset was successful, false otherwise.

Name                    | Optional | Type        | Description
----------------------- | -------- | ----------- | -----------
name                    | Required | string      | NVMe controller name
name                    | Required | string      | NVMe controller name (or NVMe bdev controller name for multipath)
cntlid                  | Optional | number      | NVMe controller ID (used as NVMe controller name for multipath)

#### Example

+80 −0
Original line number Diff line number Diff line
@@ -2326,7 +2326,9 @@ nvme_ctrlr_op(struct nvme_ctrlr *nvme_ctrlr, enum nvme_ctrlr_op op,
}

struct nvme_ctrlr_op_rpc_ctx {
	struct nvme_ctrlr *nvme_ctrlr;
	struct spdk_thread *orig_thread;
	enum nvme_ctrlr_op op;
	int rc;
	bdev_nvme_ctrlr_op_cb cb_fn;
	void *cb_arg;
@@ -2383,6 +2385,84 @@ nvme_ctrlr_op_rpc(struct nvme_ctrlr *nvme_ctrlr, enum nvme_ctrlr_op op,
	nvme_ctrlr_op_rpc_complete(ctx, rc);
}

static void nvme_bdev_ctrlr_op_rpc_continue(void *cb_arg, int rc);

static void
_nvme_bdev_ctrlr_op_rpc_continue(void *_ctx)
{
	struct nvme_ctrlr_op_rpc_ctx *ctx = _ctx;
	struct nvme_ctrlr *prev_nvme_ctrlr, *next_nvme_ctrlr;
	int rc;

	prev_nvme_ctrlr = ctx->nvme_ctrlr;
	ctx->nvme_ctrlr = NULL;

	if (ctx->rc != 0) {
		goto complete;
	}

	next_nvme_ctrlr = TAILQ_NEXT(prev_nvme_ctrlr, tailq);
	if (next_nvme_ctrlr == NULL) {
		goto complete;
	}

	rc = nvme_ctrlr_op(next_nvme_ctrlr, ctx->op, nvme_bdev_ctrlr_op_rpc_continue, ctx);
	if (rc == 0) {
		ctx->nvme_ctrlr = next_nvme_ctrlr;
		return;
	}

	ctx->rc = rc;

complete:
	ctx->cb_fn(ctx->cb_arg, ctx->rc);
	free(ctx);
}

static void
nvme_bdev_ctrlr_op_rpc_continue(void *cb_arg, int rc)
{
	struct nvme_ctrlr_op_rpc_ctx *ctx = cb_arg;

	ctx->rc = rc;

	spdk_thread_send_msg(ctx->orig_thread, _nvme_bdev_ctrlr_op_rpc_continue, ctx);
}

void
nvme_bdev_ctrlr_op_rpc(struct nvme_bdev_ctrlr *nbdev_ctrlr, enum nvme_ctrlr_op op,
		       bdev_nvme_ctrlr_op_cb cb_fn, void *cb_arg)
{
	struct nvme_ctrlr_op_rpc_ctx *ctx;
	struct nvme_ctrlr *nvme_ctrlr;
	int rc;

	assert(cb_fn != NULL);

	ctx = calloc(1, sizeof(*ctx));
	if (ctx == NULL) {
		SPDK_ERRLOG("Failed to allocate nvme_ctrlr_op_rpc_ctx.\n");
		cb_fn(cb_arg, -ENOMEM);
		return;
	}

	ctx->orig_thread = spdk_get_thread();
	ctx->op = op;
	ctx->cb_fn = cb_fn;
	ctx->cb_arg = cb_arg;

	nvme_ctrlr = TAILQ_FIRST(&nbdev_ctrlr->ctrlrs);
	assert(nvme_ctrlr != NULL);

	rc = nvme_ctrlr_op(nvme_ctrlr, op, nvme_bdev_ctrlr_op_rpc_continue, ctx);
	if (rc == 0) {
		ctx->nvme_ctrlr = nvme_ctrlr;
		return;
	}

	nvme_bdev_ctrlr_op_rpc_continue(ctx, rc);
}

static int _bdev_nvme_reset_io(struct nvme_io_path *io_path, struct nvme_bdev_io *bio);

static void
+15 −1
Original line number Diff line number Diff line
@@ -344,7 +344,7 @@ enum nvme_ctrlr_op {
};

/**
 * Operate NVMe controller for the specified code.
 * Perform specified operation on an NVMe controller.
 *
 * NOTE: The callback function is always called after this function returns except for
 * out of memory cases.
@@ -357,6 +357,20 @@ enum nvme_ctrlr_op {
void nvme_ctrlr_op_rpc(struct nvme_ctrlr *nvme_ctrlr, enum nvme_ctrlr_op op,
		       bdev_nvme_ctrlr_op_cb cb_fn, void *cb_arg);

/**
 * Perform specified operation on all NVMe controllers in an NVMe bdev controller.
 *
 * NOTE: The callback function is always called after this function returns except for
 * out of memory cases.
 *
 * \param nbdev_ctrlr The specified NVMe bdev controller to operate
 * \param op Operation code
 * \param cb_fn Function to be called back after operation completes
 * \param cb_arg Argument for callback function
 */
void nvme_bdev_ctrlr_op_rpc(struct nvme_bdev_ctrlr *nbdev_ctrlr, enum nvme_ctrlr_op op,
			    bdev_nvme_ctrlr_op_cb cb_fn, void *cb_arg);

typedef void (*bdev_nvme_set_preferred_path_cb)(void *cb_arg, int rc);

/**
+19 −4
Original line number Diff line number Diff line
@@ -1266,6 +1266,7 @@ SPDK_RPC_REGISTER("bdev_nvme_get_transport_statistics", rpc_bdev_nvme_get_transp

struct rpc_bdev_nvme_reset_controller_req {
	char *name;
	uint16_t cntlid;
};

static void
@@ -1276,6 +1277,7 @@ free_rpc_bdev_nvme_reset_controller_req(struct rpc_bdev_nvme_reset_controller_re

static const struct spdk_json_object_decoder rpc_bdev_nvme_reset_controller_req_decoders[] = {
	{"name", offsetof(struct rpc_bdev_nvme_reset_controller_req, name), spdk_json_decode_string},
	{"cntlid", offsetof(struct rpc_bdev_nvme_reset_controller_req, cntlid), spdk_json_decode_uint16, true},
};

static void
@@ -1295,6 +1297,7 @@ rpc_bdev_nvme_reset_controller(struct spdk_jsonrpc_request *request,
			       const struct spdk_json_val *params)
{
	struct rpc_bdev_nvme_reset_controller_req req = {NULL};
	struct nvme_bdev_ctrlr *nbdev_ctrlr;
	struct nvme_ctrlr *nvme_ctrlr;

	if (spdk_json_decode_object(params, rpc_bdev_nvme_reset_controller_req_decoders,
@@ -1305,14 +1308,26 @@ rpc_bdev_nvme_reset_controller(struct spdk_jsonrpc_request *request,
		goto exit;
	}

	nvme_ctrlr = nvme_ctrlr_get_by_name(req.name);
	if (nvme_ctrlr == NULL) {
		SPDK_ERRLOG("Failed at device lookup\n");
	nbdev_ctrlr = nvme_bdev_ctrlr_get_by_name(req.name);
	if (nbdev_ctrlr == NULL) {
		SPDK_ERRLOG("Failed at NVMe bdev controller lookup\n");
		spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
		goto exit;
	}

	nvme_ctrlr_op_rpc(nvme_ctrlr, NVME_CTRLR_OP_RESET, rpc_bdev_nvme_reset_controller_cb, request);
	if (req.cntlid == 0) {
		nvme_bdev_ctrlr_op_rpc(nbdev_ctrlr, NVME_CTRLR_OP_RESET,
				       rpc_bdev_nvme_reset_controller_cb, request);
	} else {
		nvme_ctrlr = nvme_bdev_ctrlr_get_ctrlr_by_id(nbdev_ctrlr, req.cntlid);
		if (nvme_ctrlr == NULL) {
			SPDK_ERRLOG("Failed at NVMe controller lookup\n");
			spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
			goto exit;
		}
		nvme_ctrlr_op_rpc(nvme_ctrlr, NVME_CTRLR_OP_RESET,
				  rpc_bdev_nvme_reset_controller_cb, request);
	}

exit:
	free_rpc_bdev_nvme_reset_controller_req(&req);
+6 −2
Original line number Diff line number Diff line
@@ -849,15 +849,19 @@ def bdev_nvme_detach_controller(client, name, trtype=None, traddr=None,
    return client.call('bdev_nvme_detach_controller', params)


def bdev_nvme_reset_controller(client, name):
    """Reset NVMe controller.
def bdev_nvme_reset_controller(client, name, cntlid):
    """Reset an NVMe controller or all NVMe controllers in an NVMe bdev controller.

    Args:
        name: controller name
        cntlid: NVMe controller ID (optional)
    """

    params = {'name': name}

    if cntlid is not None:
        params['cntlid'] = cntlid

    return client.call('bdev_nvme_reset_controller', params)


Loading