vhost: add virtio_blk abstraction

This patch adds virtio_blk abstraction for custom transports,
with the 'vhost_user_blk' first one being used.

Added spdk_virtio_blk_transport_ops describing the nessecary
callbacks to be implemented by each transport.
Please use SPDK_VIRTIO_BLK_TRANSPORT_REGISTER to register the transport.
Transports can use virtio_blk_process_request() to process the
incoming I/O from their queues.

virtio_blk_create_transport RPC was added to create one of the
registered transports, possibly with custom JSON arguments.

Added 'transport' argument to vhost_create_blk_controller RPC,
to specify which transport should create the controller.
By default the vhost_user_blk transport is used.

Signed-off-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
Change-Id: Ic9d93a6e0f483796eb56b7174a678e41a6ea4808
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/9540
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Tomasz Zawadzki 2021-09-17 10:23:35 +02:00
parent 2dd64cf962
commit b727e804d6
10 changed files with 460 additions and 59 deletions

View File

@ -7576,6 +7576,41 @@ Example response:
}
~~~
### virtio_blk_create_transport {#rpc_virtio_blk_create_transport}
Create virtio blk transport.
#### Parameters
Name | Optional | Type | Description
----------------------- | -------- | ----------- | -----------
name | Required | string | Transport name
#### Example
Example request:
~~~json
{
"params": {
"name": "vhost_user_blk"
},
"jsonrpc": "2.0",
"method": "virtio_blk_create_transport",
"id": 1
}
~~~
Example response:
~~~json
{
"jsonrpc": "2.0",
"id": 1,
"result": true
}
~~~
### vhost_create_blk_controller {#rpc_vhost_create_blk_controller}
Create vhost block controller
@ -7591,6 +7626,7 @@ ctrlr | Required | string | Controller name
bdev_name | Required | string | Name of bdev to expose block device
readonly | Optional | boolean | If true, this target will be read only (default: false)
cpumask | Optional | string | @ref cpu_mask for this controller
transport | Optional | string | virtio blk transport name (default: vhost_user_blk)
#### Example

View File

@ -332,6 +332,7 @@ int spdk_vhost_scsi_dev_remove_tgt(struct spdk_vhost_dev *vdev, unsigned scsi_tg
* is allowed but not required. The mask itself can be constructed as:
* ((1 << cpu0) | (1 << cpu1) | ... | (1 << cpuN)).
* \param dev_name bdev name to associate with this vhost device
* \param transport virtio blk transport name (default: vhost_user_blk)
* \param params JSON value object containing variables:
* readonly if set, all writes to the device will fail with
* \c VIRTIO_BLK_S_IOERR error code.
@ -341,7 +342,7 @@ int spdk_vhost_scsi_dev_remove_tgt(struct spdk_vhost_dev *vdev, unsigned scsi_tg
* \return 0 on success, negative errno on error.
*/
int spdk_vhost_blk_construct(const char *name, const char *cpumask, const char *dev_name,
const struct spdk_json_val *params);
const char *transport, const struct spdk_json_val *params);
/**
* Remove a vhost device. The device must not have any open connections on it's socket.

View File

@ -48,6 +48,9 @@ static TAILQ_HEAD(, spdk_vhost_dev) g_vhost_devices = TAILQ_HEAD_INITIALIZER(
g_vhost_devices);
static pthread_mutex_t g_vhost_mutex = PTHREAD_MUTEX_INITIALIZER;
static TAILQ_HEAD(, spdk_virtio_blk_transport) g_virtio_blk_transports = TAILQ_HEAD_INITIALIZER(
g_virtio_blk_transports);
struct spdk_vhost_dev *
spdk_vhost_dev_next(struct spdk_vhost_dev *vdev)
{
@ -114,8 +117,24 @@ vhost_parse_core_mask(const char *mask, struct spdk_cpuset *cpumask)
return 0;
}
TAILQ_HEAD(, virtio_blk_transport_ops_list_element)
g_spdk_virtio_blk_transport_ops = TAILQ_HEAD_INITIALIZER(g_spdk_virtio_blk_transport_ops);
const struct spdk_virtio_blk_transport_ops *
virtio_blk_get_transport_ops(const char *transport_name)
{
struct virtio_blk_transport_ops_list_element *ops;
TAILQ_FOREACH(ops, &g_spdk_virtio_blk_transport_ops, link) {
if (strcasecmp(transport_name, ops->ops.name) == 0) {
return &ops->ops;
}
}
return NULL;
}
int
vhost_dev_register(struct spdk_vhost_dev *vdev, const char *name, const char *mask_str,
const struct spdk_json_val *params,
const struct spdk_vhost_dev_backend *backend,
const struct spdk_vhost_user_dev_backend *user_backend)
{
@ -145,8 +164,11 @@ vhost_dev_register(struct spdk_vhost_dev *vdev, const char *name, const char *ma
}
vdev->backend = backend;
if (vdev->backend->type == VHOST_BACKEND_SCSI) {
rc = vhost_user_dev_register(vdev, name, &cpumask, user_backend);
} else {
rc = virtio_blk_construct_ctrlr(vdev, name, &cpumask, params, user_backend);
}
if (rc != 0) {
free(vdev->name);
return rc;
@ -163,7 +185,11 @@ vhost_dev_unregister(struct spdk_vhost_dev *vdev)
{
int rc;
if (vdev->backend->type == VHOST_BACKEND_SCSI) {
rc = vhost_user_dev_unregister(vdev);
} else {
rc = virtio_blk_destroy_ctrlr(vdev);
}
if (rc != 0) {
return rc;
}
@ -265,7 +291,7 @@ spdk_vhost_blk_init(spdk_vhost_init_cb init_cb)
uint32_t i;
int ret = 0;
ret = vhost_user_init();
ret = virtio_blk_transport_create("vhost_user_blk", NULL);
if (ret != 0) {
goto out;
}
@ -286,12 +312,25 @@ spdk_vhost_scsi_fini(spdk_vhost_fini_cb fini_cb)
vhost_user_fini(vhost_fini);
}
static void
virtio_blk_transports_destroy(void)
{
struct spdk_virtio_blk_transport *transport = TAILQ_FIRST(&g_virtio_blk_transports);
if (transport == NULL) {
g_fini_cb();
return;
}
TAILQ_REMOVE(&g_virtio_blk_transports, transport, tailq);
virtio_blk_transport_destroy(transport, virtio_blk_transports_destroy);
}
void
spdk_vhost_blk_fini(spdk_vhost_fini_cb fini_cb)
{
g_fini_cb = fini_cb;
vhost_user_fini(vhost_fini);
virtio_blk_transports_destroy();
}
static void
@ -355,5 +394,65 @@ spdk_vhost_blk_config_json(struct spdk_json_write_ctx *w)
spdk_json_write_array_end(w);
}
void
virtio_blk_transport_register(const struct spdk_virtio_blk_transport_ops *ops)
{
struct virtio_blk_transport_ops_list_element *new_ops;
if (virtio_blk_get_transport_ops(ops->name) != NULL) {
SPDK_ERRLOG("Double registering virtio blk transport type %s.\n", ops->name);
assert(false);
return;
}
new_ops = calloc(1, sizeof(*new_ops));
if (new_ops == NULL) {
SPDK_ERRLOG("Unable to allocate memory to register new transport type %s.\n", ops->name);
assert(false);
return;
}
new_ops->ops = *ops;
TAILQ_INSERT_TAIL(&g_spdk_virtio_blk_transport_ops, new_ops, link);
}
int
virtio_blk_transport_create(const char *transport_name,
const struct spdk_json_val *params)
{
const struct spdk_virtio_blk_transport_ops *ops = NULL;
struct spdk_virtio_blk_transport *transport;
TAILQ_FOREACH(transport, &g_virtio_blk_transports, tailq) {
if (strcasecmp(transport->ops->name, transport_name) == 0) {
return -EEXIST;
}
}
ops = virtio_blk_get_transport_ops(transport_name);
if (!ops) {
SPDK_ERRLOG("Transport type '%s' unavailable.\n", transport_name);
return -ENOENT;
}
transport = ops->create(params);
if (!transport) {
SPDK_ERRLOG("Unable to create new transport of type %s\n", transport_name);
return -EPERM;
}
transport->ops = ops;
TAILQ_INSERT_TAIL(&g_virtio_blk_transports, transport, tailq);
return 0;
}
int
virtio_blk_transport_destroy(struct spdk_virtio_blk_transport *transport,
spdk_vhost_fini_cb cb_fn)
{
return transport->ops->destroy(transport, cb_fn);
}
SPDK_LOG_REGISTER_COMPONENT(vhost)
SPDK_LOG_REGISTER_COMPONENT(vhost_ring)

View File

@ -62,6 +62,8 @@
#define SPDK_VHOST_BLK_PROTOCOL_FEATURES ((1ULL << VHOST_USER_PROTOCOL_F_CONFIG) | \
(1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD))
#define VIRTIO_BLK_DEFAULT_TRANSPORT "vhost_user_blk"
struct spdk_vhost_user_blk_task {
struct spdk_vhost_blk_task blk_task;
struct spdk_vhost_blk_session *bvsession;
@ -80,6 +82,8 @@ struct spdk_vhost_blk_dev {
struct spdk_vhost_dev vdev;
struct spdk_bdev *bdev;
struct spdk_bdev_desc *bdev_desc;
const struct spdk_virtio_blk_transport_ops *ops;
/* dummy_io_channel is used to hold a bdev reference */
struct spdk_io_channel *dummy_io_channel;
bool readonly;
@ -94,24 +98,11 @@ struct spdk_vhost_blk_session {
struct spdk_poller *stop_poller;
};
struct rpc_vhost_blk {
bool readonly;
bool packed_ring;
bool packed_ring_recovery;
};
static const struct spdk_json_object_decoder rpc_construct_vhost_blk[] = {
{"readonly", offsetof(struct rpc_vhost_blk, readonly), spdk_json_decode_bool, true},
{"packed_ring", offsetof(struct rpc_vhost_blk, packed_ring), spdk_json_decode_bool, true},
{"packed_ring_recovery", offsetof(struct rpc_vhost_blk, packed_ring_recovery), spdk_json_decode_bool, true},
};
/* forward declaration */
static const struct spdk_vhost_dev_backend vhost_blk_device_backend;
static int
virtio_blk_process_request(struct spdk_vhost_dev *vdev, struct spdk_io_channel *ch,
struct spdk_vhost_blk_task *task);
static void
vhost_user_blk_request_finish(uint8_t status, struct spdk_vhost_blk_task *task, void *cb_arg);
static int
vhost_user_process_blk_request(struct spdk_vhost_user_blk_task *user_task)
@ -119,7 +110,8 @@ vhost_user_process_blk_request(struct spdk_vhost_user_blk_task *user_task)
struct spdk_vhost_blk_session *bvsession = user_task->bvsession;
struct spdk_vhost_dev *vdev = &bvsession->bvdev->vdev;
return virtio_blk_process_request(vdev, bvsession->io_channel, &user_task->blk_task);
return virtio_blk_process_request(vdev, bvsession->io_channel, &user_task->blk_task,
vhost_user_blk_request_finish, NULL);
}
static struct spdk_vhost_blk_dev *
@ -189,7 +181,7 @@ blk_task_enqueue(struct spdk_vhost_user_blk_task *task)
}
static void
vhost_user_blk_request_finish(uint8_t status, struct spdk_vhost_blk_task *task)
vhost_user_blk_request_finish(uint8_t status, struct spdk_vhost_blk_task *task, void *cb_arg)
{
struct spdk_vhost_user_blk_task *user_task;
@ -210,7 +202,7 @@ blk_request_finish(uint8_t status, struct spdk_vhost_blk_task *task)
*task->status = status;
}
vhost_user_blk_request_finish(status, task);
task->cb(status, task, task->cb_arg);
}
/*
@ -457,7 +449,8 @@ blk_request_resubmit(void *arg)
struct spdk_vhost_blk_task *task = arg;
int rc = 0;
rc = virtio_blk_process_request(task->bdev_io_wait_vdev, task->bdev_io_wait_ch, task);
rc = virtio_blk_process_request(task->bdev_io_wait_vdev, task->bdev_io_wait_ch, task,
task->cb, task->cb_arg);
if (rc == 0) {
SPDK_DEBUGLOG(vhost_blk, "====== Task %p resubmitted ======\n", task);
} else {
@ -484,9 +477,9 @@ blk_request_queue_io(struct spdk_vhost_dev *vdev, struct spdk_io_channel *ch,
}
}
static int
int
virtio_blk_process_request(struct spdk_vhost_dev *vdev, struct spdk_io_channel *ch,
struct spdk_vhost_blk_task *task)
struct spdk_vhost_blk_task *task, virtio_blk_request_cb cb, void *cb_arg)
{
struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
struct virtio_blk_outhdr req;
@ -498,6 +491,9 @@ virtio_blk_process_request(struct spdk_vhost_dev *vdev, struct spdk_io_channel *
uint16_t iovcnt;
int rc;
task->cb = cb;
task->cb_arg = cb_arg;
iov = &task->iovs[0];
if (spdk_unlikely(iov->iov_len != sizeof(req))) {
SPDK_DEBUGLOG(vhost_blk,
@ -693,7 +689,7 @@ process_blk_task(struct spdk_vhost_virtqueue *vq, uint16_t req_idx)
if (rc) {
SPDK_DEBUGLOG(vhost_blk, "Invalid request (req_idx = %"PRIu16").\n", task->req_idx);
/* Only READ and WRITE are supported for now. */
vhost_user_blk_request_finish(VIRTIO_BLK_S_UNSUPP, blk_task);
vhost_user_blk_request_finish(VIRTIO_BLK_S_UNSUPP, blk_task, NULL);
return;
}
@ -758,7 +754,7 @@ process_packed_blk_task(struct spdk_vhost_virtqueue *vq, uint16_t req_idx)
if (rc) {
SPDK_DEBUGLOG(vhost_blk, "Invalid request (req_idx = %"PRIu16").\n", task->req_idx);
/* Only READ and WRITE are supported for now. */
vhost_user_blk_request_finish(VIRTIO_BLK_S_UNSUPP, blk_task);
vhost_user_blk_request_finish(VIRTIO_BLK_S_UNSUPP, blk_task, NULL);
return;
}
@ -819,7 +815,7 @@ process_packed_inflight_blk_task(struct spdk_vhost_virtqueue *vq,
if (rc) {
SPDK_DEBUGLOG(vhost_blk, "Invalid request (req_idx = %"PRIu16").\n", task->req_idx);
/* Only READ and WRITE are supported for now. */
vhost_user_blk_request_finish(VIRTIO_BLK_S_UNSUPP, blk_task);
vhost_user_blk_request_finish(VIRTIO_BLK_S_UNSUPP, blk_task, NULL);
return;
}
@ -1134,8 +1130,6 @@ vhost_blk_poller_set_interrupt_mode(struct spdk_poller *poller, void *cb_arg, bo
vhost_user_session_set_interrupt_mode(&bvsession->vsession, interrupt_mode);
}
typedef void (*bdev_event_cb_complete)(struct spdk_vhost_dev *vdev, void *ctx);
static void
bdev_event_cpl_cb(struct spdk_vhost_dev *vdev, void *ctx)
{
@ -1240,6 +1234,7 @@ bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
void *event_ctx)
{
struct spdk_vhost_dev *vdev = (struct spdk_vhost_dev *)event_ctx;
struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
SPDK_DEBUGLOG(vhost_blk, "Bdev event: type %d, name %s\n",
type,
@ -1248,7 +1243,7 @@ bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
switch (type) {
case SPDK_BDEV_EVENT_REMOVE:
case SPDK_BDEV_EVENT_RESIZE:
vhost_user_bdev_event_cb(type, vdev, bdev_event_cpl_cb, (void *)type);
bvdev->ops->bdev_event(type, vdev, bdev_event_cpl_cb, (void *)type);
break;
default:
SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type);
@ -1484,6 +1479,7 @@ vhost_blk_dump_info_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx
} else {
spdk_json_write_null(w);
}
spdk_json_write_named_string(w, "transport", bvdev->ops->name);
spdk_json_write_object_end(w);
}
@ -1509,6 +1505,7 @@ vhost_blk_write_config_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_
spdk_json_write_named_string(w, "cpumask",
spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)));
spdk_json_write_named_bool(w, "readonly", bvdev->readonly);
spdk_json_write_named_string(w, "transport", bvdev->ops->name);
spdk_json_write_object_end(w);
spdk_json_write_object_end(w);
@ -1593,31 +1590,44 @@ static const struct spdk_vhost_dev_backend vhost_blk_device_backend = {
};
int
spdk_vhost_blk_construct(const char *name, const char *cpumask, const char *dev_name,
const struct spdk_json_val *params)
virtio_blk_construct_ctrlr(struct spdk_vhost_dev *vdev, const char *address,
struct spdk_cpuset *cpumask, const struct spdk_json_val *params,
const struct spdk_vhost_user_dev_backend *user_backend)
{
struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
return bvdev->ops->create_ctrlr(vdev, cpumask, address, params, (void *)user_backend);
}
int
spdk_vhost_blk_construct(const char *name, const char *cpumask, const char *dev_name,
const char *transport, const struct spdk_json_val *params)
{
struct rpc_vhost_blk req = {0};
struct spdk_vhost_blk_dev *bvdev = NULL;
struct spdk_vhost_dev *vdev;
struct spdk_bdev *bdev;
const char *transport_name = VIRTIO_BLK_DEFAULT_TRANSPORT;
int ret = 0;
spdk_vhost_lock();
if (spdk_json_decode_object_relaxed(params, rpc_construct_vhost_blk,
SPDK_COUNTOF(rpc_construct_vhost_blk),
&req)) {
SPDK_DEBUGLOG(vhost_blk, "spdk_json_decode_object failed\n");
ret = -EINVAL;
goto out;
}
bvdev = calloc(1, sizeof(*bvdev));
if (bvdev == NULL) {
ret = -ENOMEM;
goto out;
}
if (transport != NULL) {
transport_name = transport;
}
bvdev->ops = virtio_blk_get_transport_ops(transport_name);
if (!bvdev->ops) {
ret = -EINVAL;
SPDK_ERRLOG("Transport type '%s' unavailable.\n", transport_name);
goto out;
}
ret = spdk_bdev_open_ext(dev_name, true, bdev_event_cb, bvdev, &bvdev->bdev_desc);
if (ret != 0) {
SPDK_ERRLOG("%s: could not open bdev '%s', error=%d\n",
@ -1630,12 +1640,6 @@ spdk_vhost_blk_construct(const char *name, const char *cpumask, const char *dev_
vdev->virtio_features = SPDK_VHOST_BLK_FEATURES_BASE;
vdev->disabled_features = SPDK_VHOST_BLK_DISABLED_FEATURES;
vdev->protocol_features = SPDK_VHOST_BLK_PROTOCOL_FEATURES;
vdev->packed_ring_recovery = false;
if (req.packed_ring) {
vdev->virtio_features |= (uint64_t)req.packed_ring << VIRTIO_F_RING_PACKED;
vdev->packed_ring_recovery = req.packed_ring_recovery;
}
if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_UNMAP)) {
vdev->virtio_features |= (1ULL << VIRTIO_BLK_F_DISCARD);
@ -1643,9 +1647,7 @@ spdk_vhost_blk_construct(const char *name, const char *cpumask, const char *dev_
if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE_ZEROES)) {
vdev->virtio_features |= (1ULL << VIRTIO_BLK_F_WRITE_ZEROES);
}
if (req.readonly) {
vdev->virtio_features |= (1ULL << VIRTIO_BLK_F_RO);
}
if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_FLUSH)) {
vdev->virtio_features |= (1ULL << VIRTIO_BLK_F_FLUSH);
}
@ -1663,8 +1665,8 @@ spdk_vhost_blk_construct(const char *name, const char *cpumask, const char *dev_
bvdev->dummy_io_channel = spdk_bdev_get_io_channel(bvdev->bdev_desc);
bvdev->bdev = bdev;
bvdev->readonly = req.readonly;
ret = vhost_dev_register(vdev, name, cpumask, &vhost_blk_device_backend,
bvdev->readonly = false;
ret = vhost_dev_register(vdev, name, cpumask, params, &vhost_blk_device_backend,
&vhost_blk_user_device_backend);
if (ret != 0) {
spdk_put_io_channel(bvdev->dummy_io_channel);
@ -1681,6 +1683,14 @@ out:
return ret;
}
int
virtio_blk_destroy_ctrlr(struct spdk_vhost_dev *vdev)
{
struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
return bvdev->ops->destroy_ctrlr(vdev);
}
static int
vhost_blk_destroy(struct spdk_vhost_dev *vdev)
{
@ -1723,5 +1733,96 @@ vhost_blk_put_io_channel(struct spdk_io_channel *ch)
spdk_put_io_channel(ch);
}
static struct spdk_virtio_blk_transport *
vhost_user_blk_create(const struct spdk_json_val *params)
{
int ret;
struct spdk_virtio_blk_transport *vhost_user_blk;
vhost_user_blk = calloc(1, sizeof(*vhost_user_blk));
if (!vhost_user_blk) {
return NULL;
}
ret = vhost_user_init();
if (ret != 0) {
free(vhost_user_blk);
return NULL;
}
return vhost_user_blk;
}
static int
vhost_user_blk_destroy(struct spdk_virtio_blk_transport *transport,
spdk_vhost_fini_cb cb_fn)
{
vhost_user_fini(cb_fn);
free(transport);
return 0;
}
struct rpc_vhost_blk {
bool readonly;
bool packed_ring;
bool packed_ring_recovery;
};
static const struct spdk_json_object_decoder rpc_construct_vhost_blk[] = {
{"readonly", offsetof(struct rpc_vhost_blk, readonly), spdk_json_decode_bool, true},
{"packed_ring", offsetof(struct rpc_vhost_blk, packed_ring), spdk_json_decode_bool, true},
{"packed_ring_recovery", offsetof(struct rpc_vhost_blk, packed_ring_recovery), spdk_json_decode_bool, true},
};
static int
vhost_user_blk_create_ctrlr(struct spdk_vhost_dev *vdev, struct spdk_cpuset *cpumask,
const char *address, const struct spdk_json_val *params, void *custom_opts)
{
struct rpc_vhost_blk req = {0};
struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
if (spdk_json_decode_object_relaxed(params, rpc_construct_vhost_blk,
SPDK_COUNTOF(rpc_construct_vhost_blk),
&req)) {
SPDK_DEBUGLOG(vhost_blk, "spdk_json_decode_object failed\n");
return -EINVAL;
}
vdev->packed_ring_recovery = false;
if (req.packed_ring) {
vdev->virtio_features |= (uint64_t)req.packed_ring << VIRTIO_F_RING_PACKED;
vdev->packed_ring_recovery = req.packed_ring_recovery;
}
if (req.readonly) {
vdev->virtio_features |= (1ULL << VIRTIO_BLK_F_RO);
bvdev->readonly = req.readonly;
}
return vhost_user_dev_register(vdev, address, cpumask, custom_opts);
}
static int
vhost_user_blk_destroy_ctrlr(struct spdk_vhost_dev *vdev)
{
return vhost_user_dev_unregister(vdev);
}
static const struct spdk_virtio_blk_transport_ops vhost_user_blk = {
.name = "vhost_user_blk",
.dump_opts = NULL,
.create = vhost_user_blk_create,
.destroy = vhost_user_blk_destroy,
.create_ctrlr = vhost_user_blk_create_ctrlr,
.destroy_ctrlr = vhost_user_blk_destroy_ctrlr,
.bdev_event = vhost_user_bdev_event_cb,
};
SPDK_VIRTIO_BLK_TRANSPORT_REGISTER(vhost_user_blk, &vhost_user_blk);
SPDK_LOG_REGISTER_COMPONENT(vhost_blk)
SPDK_LOG_REGISTER_COMPONENT(vhost_blk_data)

View File

@ -424,6 +424,7 @@ vhost_dev_has_feature(struct spdk_vhost_session *vsession, unsigned feature_id)
}
int vhost_dev_register(struct spdk_vhost_dev *vdev, const char *name, const char *mask_str,
const struct spdk_json_val *params,
const struct spdk_vhost_dev_backend *backend,
const struct spdk_vhost_user_dev_backend *user_backend);
int vhost_dev_unregister(struct spdk_vhost_dev *vdev);
@ -537,8 +538,20 @@ int vhost_user_dev_unregister(struct spdk_vhost_dev *vdev);
int vhost_user_init(void);
void vhost_user_fini(spdk_vhost_fini_cb vhost_cb);
int virtio_blk_construct_ctrlr(struct spdk_vhost_dev *vdev, const char *address,
struct spdk_cpuset *cpumask, const struct spdk_json_val *params,
const struct spdk_vhost_user_dev_backend *user_backend);
int virtio_blk_destroy_ctrlr(struct spdk_vhost_dev *vdev);
struct spdk_vhost_blk_task;
typedef void (*virtio_blk_request_cb)(uint8_t status, struct spdk_vhost_blk_task *task,
void *cb_arg);
struct spdk_vhost_blk_task {
struct spdk_bdev_io *bdev_io;
virtio_blk_request_cb cb;
void *cb_arg;
volatile uint8_t *status;
@ -556,4 +569,80 @@ struct spdk_vhost_blk_task {
uint32_t payload_size;
};
int virtio_blk_process_request(struct spdk_vhost_dev *vdev, struct spdk_io_channel *ch,
struct spdk_vhost_blk_task *task, virtio_blk_request_cb cb, void *cb_arg);
typedef void (*bdev_event_cb_complete)(struct spdk_vhost_dev *vdev, void *ctx);
#define SPDK_VIRTIO_BLK_TRSTRING_MAX_LEN 32
struct spdk_virtio_blk_transport_ops {
/**
* Transport name
*/
char name[SPDK_VIRTIO_BLK_TRSTRING_MAX_LEN];
/**
* Create a transport for the given transport opts
*/
struct spdk_virtio_blk_transport *(*create)(const struct spdk_json_val *params);
/**
* Dump transport-specific opts into JSON
*/
void (*dump_opts)(struct spdk_virtio_blk_transport *transport, struct spdk_json_write_ctx *w);
/**
* Destroy the transport
*/
int (*destroy)(struct spdk_virtio_blk_transport *transport,
spdk_vhost_fini_cb cb_fn);
/**
* Create vhost block controller
*/
int (*create_ctrlr)(struct spdk_vhost_dev *vdev, struct spdk_cpuset *cpumask,
const char *address, const struct spdk_json_val *params,
void *custom_opts);
/**
* Destroy vhost block controller
*/
int (*destroy_ctrlr)(struct spdk_vhost_dev *vdev);
/*
* Signal removal of the bdev.
*/
void (*bdev_event)(enum spdk_bdev_event_type type, struct spdk_vhost_dev *vdev,
bdev_event_cb_complete cb, void *cb_arg);
};
struct spdk_virtio_blk_transport {
const struct spdk_virtio_blk_transport_ops *ops;
TAILQ_ENTRY(spdk_virtio_blk_transport) tailq;
};
struct virtio_blk_transport_ops_list_element {
struct spdk_virtio_blk_transport_ops ops;
TAILQ_ENTRY(virtio_blk_transport_ops_list_element) link;
};
void virtio_blk_transport_register(const struct spdk_virtio_blk_transport_ops *ops);
int virtio_blk_transport_create(const char *transport_name, const struct spdk_json_val *params);
int virtio_blk_transport_destroy(struct spdk_virtio_blk_transport *transport,
spdk_vhost_fini_cb cb_fn);
const struct spdk_virtio_blk_transport_ops *
virtio_blk_get_transport_ops(const char *transport_name);
/*
* Macro used to register new transports.
*/
#define SPDK_VIRTIO_BLK_TRANSPORT_REGISTER(name, transport_ops) \
static void __attribute__((constructor)) _virtio_blk_transport_register_##name(void) \
{ \
virtio_blk_transport_register(transport_ops); \
}\
#endif /* SPDK_VHOST_INTERNAL_H */

View File

@ -232,12 +232,14 @@ struct rpc_vhost_blk_ctrlr {
char *ctrlr;
char *dev_name;
char *cpumask;
char *transport;
};
static const struct spdk_json_object_decoder rpc_construct_vhost_blk_ctrlr[] = {
{"ctrlr", offsetof(struct rpc_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string },
{"dev_name", offsetof(struct rpc_vhost_blk_ctrlr, dev_name), spdk_json_decode_string },
{"cpumask", offsetof(struct rpc_vhost_blk_ctrlr, cpumask), spdk_json_decode_string, true},
{"transport", offsetof(struct rpc_vhost_blk_ctrlr, transport), spdk_json_decode_string, true},
};
static void
@ -246,6 +248,7 @@ free_rpc_vhost_blk_ctrlr(struct rpc_vhost_blk_ctrlr *req)
free(req->ctrlr);
free(req->dev_name);
free(req->cpumask);
free(req->transport);
}
static void
@ -263,7 +266,7 @@ rpc_vhost_create_blk_controller(struct spdk_jsonrpc_request *request,
goto invalid;
}
rc = spdk_vhost_blk_construct(req.ctrlr, req.cpumask, req.dev_name, params);
rc = spdk_vhost_blk_construct(req.ctrlr, req.cpumask, req.dev_name, req.transport, params);
if (rc < 0) {
goto invalid;
}
@ -497,4 +500,51 @@ invalid:
SPDK_RPC_REGISTER("vhost_controller_set_coalescing", rpc_vhost_controller_set_coalescing,
SPDK_RPC_RUNTIME)
struct rpc_virtio_blk_create_transport {
char *name;
};
static const struct spdk_json_object_decoder rpc_create_virtio_blk_transport[] = {
{"name", offsetof(struct rpc_virtio_blk_create_transport, name), spdk_json_decode_string},
};
static void
free_rpc_virtio_blk_create_transport(struct rpc_virtio_blk_create_transport *req)
{
free(req->name);
}
static void
rpc_virtio_blk_create_transport(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct rpc_virtio_blk_create_transport req = {0};
int rc;
if (spdk_json_decode_object_relaxed(params, rpc_create_virtio_blk_transport,
SPDK_COUNTOF(rpc_create_virtio_blk_transport), &req)) {
SPDK_DEBUGLOG(vhost_rpc, "spdk_json_decode_object failed\n");
rc = -EINVAL;
goto invalid;
}
spdk_vhost_lock();
rc = virtio_blk_transport_create(req.name, params);
spdk_vhost_unlock();
if (rc != 0) {
goto invalid;
}
free_rpc_virtio_blk_create_transport(&req);
spdk_jsonrpc_send_bool_response(request, true);
return;
invalid:
free_rpc_virtio_blk_create_transport(&req);
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
spdk_strerror(-rc));
}
SPDK_RPC_REGISTER("virtio_blk_create_transport", rpc_virtio_blk_create_transport,
SPDK_RPC_RUNTIME)
SPDK_LOG_REGISTER_COMPONENT(vhost_rpc)

View File

@ -882,7 +882,7 @@ spdk_vhost_scsi_dev_construct(const char *name, const char *cpumask)
svdev->vdev.protocol_features = SPDK_VHOST_SCSI_PROTOCOL_FEATURES;
spdk_vhost_lock();
rc = vhost_dev_register(&svdev->vdev, name, cpumask,
rc = vhost_dev_register(&svdev->vdev, name, cpumask, NULL,
&spdk_vhost_scsi_device_backend,
&spdk_vhost_scsi_user_device_backend);
if (rc) {

View File

@ -16,6 +16,15 @@ def vhost_controller_set_coalescing(client, ctrlr, delay_base_us, iops_threshold
return client.call('vhost_controller_set_coalescing', params)
def virtio_blk_create_transport(client, name, opts):
"""Create virtio blk transport.
Args:
name: transport name
"""
params = {'name': name}
return client.call('virtio_blk_create_transport', params)
def vhost_create_scsi_controller(client, ctrlr, cpumask=None):
"""Create a vhost scsi controller.
Args:
@ -58,12 +67,14 @@ def vhost_scsi_controller_remove_target(client, ctrlr, scsi_target_num):
return client.call('vhost_scsi_controller_remove_target', params)
def vhost_create_blk_controller(client, ctrlr, dev_name, cpumask=None, readonly=None, packed_ring=None, packed_ring_recovery=None):
def vhost_create_blk_controller(
client, ctrlr, dev_name, cpumask=None, transport=None, readonly=None, packed_ring=None, packed_ring_recovery=None):
"""Create vhost BLK controller.
Args:
ctrlr: controller name
dev_name: device name to add to controller
cpumask: cpu mask for this controller
transport: virtio blk transport name (default: vhost_user_blk)
readonly: set controller as read-only
packed_ring: support controller packed_ring
packed_ring_recovery: enable packed ring live recovery
@ -74,6 +85,8 @@ def vhost_create_blk_controller(client, ctrlr, dev_name, cpumask=None, readonly=
}
if cpumask:
params['cpumask'] = cpumask
if transport:
params['transport'] = transport
if readonly:
params['readonly'] = readonly
if packed_ring:

View File

@ -2417,6 +2417,16 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse
p.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
p.set_defaults(func=vhost_controller_set_coalescing)
def virtio_blk_create_transport(args):
rpc.vhost.virtio_blk_create_transport(args.client,
name=args.name,
opts=args.opts)
p = subparsers.add_parser('virtio_blk_create_transport',
help='Create virtio blk transport')
p.add_argument('name', help='transport name')
p.set_defaults(func=virtio_blk_create_transport)
def vhost_create_scsi_controller(args):
rpc.vhost.vhost_create_scsi_controller(args.client,
ctrlr=args.ctrlr,
@ -2455,6 +2465,7 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse
ctrlr=args.ctrlr,
dev_name=args.dev_name,
cpumask=args.cpumask,
transport=args.transport,
readonly=args.readonly,
packed_ring=args.packed_ring,
packed_ring_recovery=args.packed_ring_recovery)
@ -2463,6 +2474,7 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse
p.add_argument('ctrlr', help='controller name')
p.add_argument('dev_name', help='device name')
p.add_argument('--cpumask', help='cpu mask for this controller')
p.add_argument('--transport', help='virtio blk transport name (default: vhost_user_blk)')
p.add_argument("-r", "--readonly", action='store_true', help='Set controller as read-only')
p.add_argument("-p", "--packed_ring", action='store_true', help='Set controller as packed ring supported')
p.add_argument("-l", "--packed_ring_recovery", action='store_true', help='Enable packed ring live recovery')

View File

@ -232,7 +232,7 @@ alloc_vdev(struct spdk_vhost_dev **vdev_p, const char *name, const char *cpumask
CU_ASSERT(rc == 0);
SPDK_CU_ASSERT_FATAL(vdev != NULL);
memset(vdev, 0, sizeof(*vdev));
rc = vhost_dev_register(vdev, name, cpumask, &g_vdev_backend, &g_vdev_user_backend);
rc = vhost_dev_register(vdev, name, cpumask, NULL, &g_vdev_backend, &g_vdev_user_backend);
if (rc == 0) {
*vdev_p = vdev;
} else {