nbd: Make spdk_nbd_start asynchronous

Add a callback to spdk_nbd_start so that it can complete
asynchronously. As of this patch, it always calls the
callback immediately.

Change-Id: I6156fb203145362afa5e4102183b6cf143051c0c
Signed-off-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-on: https://review.gerrithub.io/433937
Tested-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Ben Walker 2018-11-19 13:44:03 -07:00 committed by Darek Stojaczyk
parent 027a8e4b54
commit 2fe6d1d5d4
3 changed files with 60 additions and 24 deletions

View File

@ -59,16 +59,24 @@ int spdk_nbd_init(void);
*/
void spdk_nbd_fini(void);
/**
* Called when an NBD device has been started.
*/
typedef void (*spdk_nbd_start_cb)(void *cb_arg, struct spdk_nbd_disk *nbd,
int rc);
/**
* Start a network block device backed by the bdev.
*
* \param bdev_name Name of bdev exposed as a network block device.
* \param nbd_path Path to the registered network block device.
* \param cb_fn Called when the device has been started.
* \param cb_arg Passed to cb_fn.
*
* \return a pointer to the configuration of the registered network block device
* on success, or NULL on failure.
* \return A negated error number is passed to cb_fn on failure.
*/
struct spdk_nbd_disk *spdk_nbd_start(const char *bdev_name, const char *nbd_path);
void spdk_nbd_start(const char *bdev_name, const char *nbd_path,
spdk_nbd_start_cb cb_fn, void *cb_arg);
/**
* Stop the running network block device safely.

View File

@ -837,10 +837,11 @@ spdk_nbd_bdev_hot_remove(void *remove_ctx)
spdk_nbd_stop(nbd);
}
struct spdk_nbd_disk *
spdk_nbd_start(const char *bdev_name, const char *nbd_path)
void
spdk_nbd_start(const char *bdev_name, const char *nbd_path,
spdk_nbd_start_cb cb_fn, void *cb_arg)
{
struct spdk_nbd_disk *nbd;
struct spdk_nbd_disk *nbd = NULL;
struct spdk_bdev *bdev;
pthread_t tid;
int rc;
@ -850,12 +851,14 @@ spdk_nbd_start(const char *bdev_name, const char *nbd_path)
bdev = spdk_bdev_get_by_name(bdev_name);
if (bdev == NULL) {
SPDK_ERRLOG("no bdev %s exists\n", bdev_name);
return NULL;
rc = -EINVAL;
goto err;
}
nbd = calloc(1, sizeof(*nbd));
if (nbd == NULL) {
return NULL;
rc = -ENOMEM;
goto err;
}
nbd->dev_fd = -1;
@ -884,6 +887,7 @@ spdk_nbd_start(const char *bdev_name, const char *nbd_path)
nbd->nbd_path = strdup(nbd_path);
if (!nbd->nbd_path) {
SPDK_ERRLOG("strdup allocation failure\n");
rc = -ENOMEM;
goto err;
}
@ -899,24 +903,28 @@ spdk_nbd_start(const char *bdev_name, const char *nbd_path)
nbd->dev_fd = open(nbd_path, O_RDWR);
if (nbd->dev_fd == -1) {
SPDK_ERRLOG("open(\"%s\") failed: %s\n", nbd_path, spdk_strerror(errno));
rc = -errno;
goto err;
}
rc = ioctl(nbd->dev_fd, NBD_SET_BLKSIZE, spdk_bdev_get_block_size(bdev));
if (rc == -1) {
SPDK_ERRLOG("ioctl(NBD_SET_BLKSIZE) failed: %s\n", spdk_strerror(errno));
rc = -errno;
goto err;
}
rc = ioctl(nbd->dev_fd, NBD_SET_SIZE_BLOCKS, spdk_bdev_get_num_blocks(bdev));
if (rc == -1) {
SPDK_ERRLOG("ioctl(NBD_SET_SIZE_BLOCKS) failed: %s\n", spdk_strerror(errno));
rc = -errno;
goto err;
}
rc = ioctl(nbd->dev_fd, NBD_CLEAR_SOCK);
if (rc == -1) {
SPDK_ERRLOG("ioctl(NBD_CLEAR_SOCK) failed: %s\n", spdk_strerror(errno));
rc = -errno;
goto err;
}
@ -926,6 +934,7 @@ spdk_nbd_start(const char *bdev_name, const char *nbd_path)
rc = ioctl(nbd->dev_fd, NBD_SET_SOCK, nbd->kernel_sp_fd);
if (rc == -1) {
SPDK_ERRLOG("ioctl(NBD_SET_SOCK) failed: %s\n", spdk_strerror(errno));
rc = -errno;
goto err;
}
@ -933,6 +942,7 @@ spdk_nbd_start(const char *bdev_name, const char *nbd_path)
rc = ioctl(nbd->dev_fd, NBD_SET_FLAGS, NBD_FLAG_SEND_TRIM);
if (rc == -1) {
SPDK_ERRLOG("ioctl(NBD_SET_FLAGS) failed: %s\n", spdk_strerror(errno));
rc = -errno;
goto err;
}
#endif
@ -953,17 +963,26 @@ spdk_nbd_start(const char *bdev_name, const char *nbd_path)
if (fcntl(nbd->spdk_sp_fd, F_SETFL, flag | O_NONBLOCK) < 0) {
SPDK_ERRLOG("fcntl can't set nonblocking mode for socket, fd: %d (%s)\n",
nbd->spdk_sp_fd, spdk_strerror(errno));
rc = -errno;
goto err;
}
nbd->nbd_poller = spdk_poller_register(spdk_nbd_poll, nbd, 0);
return nbd;
if (cb_fn) {
cb_fn(cb_arg, nbd, 0);
}
return;
err:
spdk_nbd_stop(nbd);
if (nbd) {
spdk_nbd_stop(nbd);
}
return NULL;
if (cb_fn) {
cb_fn(cb_arg, NULL, rc);
}
}
const char *

View File

@ -58,12 +58,31 @@ static const struct spdk_json_object_decoder rpc_start_nbd_disk_decoders[] = {
{"nbd_device", offsetof(struct rpc_start_nbd_disk, nbd_device), spdk_json_decode_string},
};
static void
spdk_rpc_start_nbd_done(void *cb_arg, struct spdk_nbd_disk *nbd, int rc)
{
struct spdk_jsonrpc_request *request = cb_arg;
struct spdk_json_write_ctx *w;
if (rc) {
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
return;
}
w = spdk_jsonrpc_begin_result(request);
if (w == NULL) {
return;
}
spdk_json_write_string(w, spdk_nbd_get_path(nbd));
spdk_jsonrpc_end_result(request, w);
}
static void
spdk_rpc_start_nbd_disk(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct rpc_start_nbd_disk req = {};
struct spdk_json_write_ctx *w;
struct spdk_nbd_disk *nbd;
if (spdk_json_decode_object(params, rpc_start_nbd_disk_decoders,
@ -83,19 +102,9 @@ spdk_rpc_start_nbd_disk(struct spdk_jsonrpc_request *request,
goto invalid;
}
nbd = spdk_nbd_start(req.bdev_name, req.nbd_device);
if (!nbd) {
goto invalid;
}
spdk_nbd_start(req.bdev_name, req.nbd_device,
spdk_rpc_start_nbd_done, request);
w = spdk_jsonrpc_begin_result(request);
if (w == NULL) {
free_rpc_start_nbd_disk(&req);
return;
}
spdk_json_write_string(w, req.nbd_device);
spdk_jsonrpc_end_result(request, w);
free_rpc_start_nbd_disk(&req);
return;