bdev: add timeout option to bdev_get_bdevs RPC

This opption allows the bdev_get_bdevs RPC to block until a bdev with
specified name appears.  It can be useful, when a bdev is created
asynchronously and the exact moment at which it appears is not known.
For instance, with a discovery service, a bdev is created when a
namespace on a remote NVMeoF target is added, but it's not possible to
specify when that happens exactly.

Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com>
Change-Id: I6c1f974fba445376ca9d45aac2639202547410cc
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/11960
Community-CI: Mellanox Build Bot
Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
This commit is contained in:
Konrad Sztyber 2022-03-16 12:51:50 +01:00 committed by Tomasz Zawadzki
parent c0415feda3
commit fa649869b9
5 changed files with 87 additions and 7 deletions

View File

@ -34,6 +34,11 @@ bdev_crypto_create RPC now requires hexlified 'key' and 'key2' params for all pm
Unhexlifying is performed during RPC command processing and the vbdev crypto module runs on
binary keys as before.
### bdev
Added a timeout option to the `bdev_get_bdevs` RPC. It allows the user to specify the amount of
time to wait until a bdev with a given name appears in the system.
### bdev_nvme
Added `bdev_nvme_add_error_injection` and `bdev_nvme_remove_error_injection` RPCs to add and

View File

@ -1607,11 +1607,14 @@ Get information about block devices (bdevs).
#### Parameters
The user may specify no parameters in order to list all block devices, or a block device may be
specified by name.
specified by name. If a timeout is specified, the method will block until a bdev with a specified
name appears or the timeout expires. By default, the timeout is zero, meaning the method returns
immediately whether the bdev exists or not.
Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
name | Optional | string | Block device name
timeout | Optional | number | Time (ms) to wait for a bdev with specified name to appear
#### Response

View File

@ -441,7 +441,15 @@ rpc_dump_bdev_info(struct spdk_json_write_ctx *w,
}
struct rpc_bdev_get_bdevs {
char *name;
char *name;
uint64_t timeout;
};
struct rpc_bdev_get_bdevs_ctx {
struct rpc_bdev_get_bdevs rpc;
struct spdk_jsonrpc_request *request;
struct spdk_poller *poller;
uint64_t timeout_ticks;
};
static void
@ -452,13 +460,45 @@ free_rpc_bdev_get_bdevs(struct rpc_bdev_get_bdevs *r)
static const struct spdk_json_object_decoder rpc_bdev_get_bdevs_decoders[] = {
{"name", offsetof(struct rpc_bdev_get_bdevs, name), spdk_json_decode_string, true},
{"timeout", offsetof(struct rpc_bdev_get_bdevs, timeout), spdk_json_decode_uint64, true},
};
static int
get_bdevs_poller(void *_ctx)
{
struct rpc_bdev_get_bdevs_ctx *ctx = _ctx;
struct spdk_json_write_ctx *w;
struct spdk_bdev *bdev;
bdev = spdk_bdev_get_by_name(ctx->rpc.name);
if (bdev == NULL && spdk_get_ticks() < ctx->timeout_ticks) {
return SPDK_POLLER_BUSY;
}
if (bdev == NULL) {
SPDK_ERRLOG("Timed out while waiting for bdev '%s' to appear\n", ctx->rpc.name);
spdk_jsonrpc_send_error_response(ctx->request, -ENODEV, spdk_strerror(ENODEV));
} else {
w = spdk_jsonrpc_begin_result(ctx->request);
spdk_json_write_array_begin(w);
rpc_dump_bdev_info(w, bdev);
spdk_json_write_array_end(w);
spdk_jsonrpc_end_result(ctx->request, w);
}
spdk_poller_unregister(&ctx->poller);
free_rpc_bdev_get_bdevs(&ctx->rpc);
free(ctx);
return SPDK_POLLER_BUSY;
}
static void
rpc_bdev_get_bdevs(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct rpc_bdev_get_bdevs req = {};
struct rpc_bdev_get_bdevs_ctx *ctx;
struct spdk_json_write_ctx *w;
struct spdk_bdev *bdev = NULL;
@ -475,9 +515,34 @@ rpc_bdev_get_bdevs(struct spdk_jsonrpc_request *request,
if (req.name) {
bdev = spdk_bdev_get_by_name(req.name);
if (bdev == NULL) {
SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
free_rpc_bdev_get_bdevs(&req);
if (req.timeout == 0) {
SPDK_ERRLOG("bdev '%s' does not exist\n", req.name);
spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
free_rpc_bdev_get_bdevs(&req);
return;
}
ctx = calloc(1, sizeof(*ctx));
if (ctx == NULL) {
SPDK_ERRLOG("Failed to allocate bdev_get_bdevs context\n");
spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
free_rpc_bdev_get_bdevs(&req);
return;
}
ctx->poller = SPDK_POLLER_REGISTER(get_bdevs_poller, ctx, 10 * 1000);
if (ctx->poller == NULL) {
SPDK_ERRLOG("Failed to register bdev_get_bdevs poller\n");
spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
free_rpc_bdev_get_bdevs(&req);
free(ctx);
return;
}
memcpy(&ctx->rpc, &req, sizeof(req));
ctx->timeout_ticks = spdk_get_ticks() + req.timeout *
spdk_get_ticks_hz() / 1000ull;
ctx->request = request;
return;
}
}

View File

@ -1003,11 +1003,15 @@ if __name__ == "__main__":
def bdev_get_bdevs(args):
print_dict(rpc.bdev.bdev_get_bdevs(args.client,
name=args.name))
name=args.name, timeout=args.timeout_ms))
p = subparsers.add_parser('bdev_get_bdevs', aliases=['get_bdevs'],
help='Display current blockdev list or required blockdev')
p.add_argument('-b', '--name', help="Name of the Blockdev. Example: Nvme0n1", required=False)
p.add_argument('-t', '--timeout-ms', help="""Time in ms to wait for the bdev to appear (only used
with the -b|--name option). The default timeout is 0, meaning the RPC returns immediately
whether the bdev exists or not.""",
type=int, required=False)
p.set_defaults(func=bdev_get_bdevs)
def bdev_get_iostat(args):

View File

@ -1281,11 +1281,12 @@ def bdev_ftl_delete(client, name):
@deprecated_alias('get_bdevs')
def bdev_get_bdevs(client, name=None):
def bdev_get_bdevs(client, name=None, timeout=None):
"""Get information about block devices.
Args:
name: bdev name to query (optional; if omitted, query all bdevs)
timeout: time in ms to wait for the bdev with specified name to appear
Returns:
List of bdev information objects.
@ -1293,6 +1294,8 @@ def bdev_get_bdevs(client, name=None):
params = {}
if name:
params['name'] = name
if timeout:
params['timeout'] = timeout
return client.call('bdev_get_bdevs', params)