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:
parent
2dd64cf962
commit
b727e804d6
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
rc = vhost_user_dev_register(vdev, name, &cpumask, user_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;
|
||||
|
||||
rc = vhost_user_dev_unregister(vdev);
|
||||
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)
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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:
|
||||
|
@ -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')
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user