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}
|
### vhost_create_blk_controller {#rpc_vhost_create_blk_controller}
|
||||||
|
|
||||||
Create vhost block 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
|
bdev_name | Required | string | Name of bdev to expose block device
|
||||||
readonly | Optional | boolean | If true, this target will be read only (default: false)
|
readonly | Optional | boolean | If true, this target will be read only (default: false)
|
||||||
cpumask | Optional | string | @ref cpu_mask for this controller
|
cpumask | Optional | string | @ref cpu_mask for this controller
|
||||||
|
transport | Optional | string | virtio blk transport name (default: vhost_user_blk)
|
||||||
|
|
||||||
#### Example
|
#### 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:
|
* is allowed but not required. The mask itself can be constructed as:
|
||||||
* ((1 << cpu0) | (1 << cpu1) | ... | (1 << cpuN)).
|
* ((1 << cpu0) | (1 << cpu1) | ... | (1 << cpuN)).
|
||||||
* \param dev_name bdev name to associate with this vhost device
|
* \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:
|
* \param params JSON value object containing variables:
|
||||||
* readonly if set, all writes to the device will fail with
|
* readonly if set, all writes to the device will fail with
|
||||||
* \c VIRTIO_BLK_S_IOERR error code.
|
* \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.
|
* \return 0 on success, negative errno on error.
|
||||||
*/
|
*/
|
||||||
int spdk_vhost_blk_construct(const char *name, const char *cpumask, const char *dev_name,
|
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.
|
* 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);
|
g_vhost_devices);
|
||||||
static pthread_mutex_t g_vhost_mutex = PTHREAD_MUTEX_INITIALIZER;
|
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 *
|
struct spdk_vhost_dev *
|
||||||
spdk_vhost_dev_next(struct spdk_vhost_dev *vdev)
|
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;
|
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
|
int
|
||||||
vhost_dev_register(struct spdk_vhost_dev *vdev, const char *name, const char *mask_str,
|
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_dev_backend *backend,
|
||||||
const struct spdk_vhost_user_dev_backend *user_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;
|
vdev->backend = backend;
|
||||||
|
if (vdev->backend->type == VHOST_BACKEND_SCSI) {
|
||||||
rc = vhost_user_dev_register(vdev, name, &cpumask, user_backend);
|
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) {
|
if (rc != 0) {
|
||||||
free(vdev->name);
|
free(vdev->name);
|
||||||
return rc;
|
return rc;
|
||||||
@ -163,7 +185,11 @@ vhost_dev_unregister(struct spdk_vhost_dev *vdev)
|
|||||||
{
|
{
|
||||||
int rc;
|
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) {
|
if (rc != 0) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -265,7 +291,7 @@ spdk_vhost_blk_init(spdk_vhost_init_cb init_cb)
|
|||||||
uint32_t i;
|
uint32_t i;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
ret = vhost_user_init();
|
ret = virtio_blk_transport_create("vhost_user_blk", NULL);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -286,12 +312,25 @@ spdk_vhost_scsi_fini(spdk_vhost_fini_cb fini_cb)
|
|||||||
vhost_user_fini(vhost_fini);
|
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
|
void
|
||||||
spdk_vhost_blk_fini(spdk_vhost_fini_cb fini_cb)
|
spdk_vhost_blk_fini(spdk_vhost_fini_cb fini_cb)
|
||||||
{
|
{
|
||||||
g_fini_cb = fini_cb;
|
g_fini_cb = fini_cb;
|
||||||
|
|
||||||
vhost_user_fini(vhost_fini);
|
virtio_blk_transports_destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -355,5 +394,65 @@ spdk_vhost_blk_config_json(struct spdk_json_write_ctx *w)
|
|||||||
spdk_json_write_array_end(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)
|
||||||
SPDK_LOG_REGISTER_COMPONENT(vhost_ring)
|
SPDK_LOG_REGISTER_COMPONENT(vhost_ring)
|
||||||
|
@ -62,6 +62,8 @@
|
|||||||
#define SPDK_VHOST_BLK_PROTOCOL_FEATURES ((1ULL << VHOST_USER_PROTOCOL_F_CONFIG) | \
|
#define SPDK_VHOST_BLK_PROTOCOL_FEATURES ((1ULL << VHOST_USER_PROTOCOL_F_CONFIG) | \
|
||||||
(1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD))
|
(1ULL << VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD))
|
||||||
|
|
||||||
|
#define VIRTIO_BLK_DEFAULT_TRANSPORT "vhost_user_blk"
|
||||||
|
|
||||||
struct spdk_vhost_user_blk_task {
|
struct spdk_vhost_user_blk_task {
|
||||||
struct spdk_vhost_blk_task blk_task;
|
struct spdk_vhost_blk_task blk_task;
|
||||||
struct spdk_vhost_blk_session *bvsession;
|
struct spdk_vhost_blk_session *bvsession;
|
||||||
@ -80,6 +82,8 @@ struct spdk_vhost_blk_dev {
|
|||||||
struct spdk_vhost_dev vdev;
|
struct spdk_vhost_dev vdev;
|
||||||
struct spdk_bdev *bdev;
|
struct spdk_bdev *bdev;
|
||||||
struct spdk_bdev_desc *bdev_desc;
|
struct spdk_bdev_desc *bdev_desc;
|
||||||
|
const struct spdk_virtio_blk_transport_ops *ops;
|
||||||
|
|
||||||
/* dummy_io_channel is used to hold a bdev reference */
|
/* dummy_io_channel is used to hold a bdev reference */
|
||||||
struct spdk_io_channel *dummy_io_channel;
|
struct spdk_io_channel *dummy_io_channel;
|
||||||
bool readonly;
|
bool readonly;
|
||||||
@ -94,24 +98,11 @@ struct spdk_vhost_blk_session {
|
|||||||
struct spdk_poller *stop_poller;
|
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 */
|
/* forward declaration */
|
||||||
static const struct spdk_vhost_dev_backend vhost_blk_device_backend;
|
static const struct spdk_vhost_dev_backend vhost_blk_device_backend;
|
||||||
|
|
||||||
static int
|
static void
|
||||||
virtio_blk_process_request(struct spdk_vhost_dev *vdev, struct spdk_io_channel *ch,
|
vhost_user_blk_request_finish(uint8_t status, struct spdk_vhost_blk_task *task, void *cb_arg);
|
||||||
struct spdk_vhost_blk_task *task);
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vhost_user_process_blk_request(struct spdk_vhost_user_blk_task *user_task)
|
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_blk_session *bvsession = user_task->bvsession;
|
||||||
struct spdk_vhost_dev *vdev = &bvsession->bvdev->vdev;
|
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 *
|
static struct spdk_vhost_blk_dev *
|
||||||
@ -189,7 +181,7 @@ blk_task_enqueue(struct spdk_vhost_user_blk_task *task)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
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;
|
*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;
|
struct spdk_vhost_blk_task *task = arg;
|
||||||
int rc = 0;
|
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) {
|
if (rc == 0) {
|
||||||
SPDK_DEBUGLOG(vhost_blk, "====== Task %p resubmitted ======\n", task);
|
SPDK_DEBUGLOG(vhost_blk, "====== Task %p resubmitted ======\n", task);
|
||||||
} else {
|
} 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,
|
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 spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
|
||||||
struct virtio_blk_outhdr req;
|
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;
|
uint16_t iovcnt;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
task->cb = cb;
|
||||||
|
task->cb_arg = cb_arg;
|
||||||
|
|
||||||
iov = &task->iovs[0];
|
iov = &task->iovs[0];
|
||||||
if (spdk_unlikely(iov->iov_len != sizeof(req))) {
|
if (spdk_unlikely(iov->iov_len != sizeof(req))) {
|
||||||
SPDK_DEBUGLOG(vhost_blk,
|
SPDK_DEBUGLOG(vhost_blk,
|
||||||
@ -693,7 +689,7 @@ process_blk_task(struct spdk_vhost_virtqueue *vq, uint16_t req_idx)
|
|||||||
if (rc) {
|
if (rc) {
|
||||||
SPDK_DEBUGLOG(vhost_blk, "Invalid request (req_idx = %"PRIu16").\n", task->req_idx);
|
SPDK_DEBUGLOG(vhost_blk, "Invalid request (req_idx = %"PRIu16").\n", task->req_idx);
|
||||||
/* Only READ and WRITE are supported for now. */
|
/* 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -758,7 +754,7 @@ process_packed_blk_task(struct spdk_vhost_virtqueue *vq, uint16_t req_idx)
|
|||||||
if (rc) {
|
if (rc) {
|
||||||
SPDK_DEBUGLOG(vhost_blk, "Invalid request (req_idx = %"PRIu16").\n", task->req_idx);
|
SPDK_DEBUGLOG(vhost_blk, "Invalid request (req_idx = %"PRIu16").\n", task->req_idx);
|
||||||
/* Only READ and WRITE are supported for now. */
|
/* 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -819,7 +815,7 @@ process_packed_inflight_blk_task(struct spdk_vhost_virtqueue *vq,
|
|||||||
if (rc) {
|
if (rc) {
|
||||||
SPDK_DEBUGLOG(vhost_blk, "Invalid request (req_idx = %"PRIu16").\n", task->req_idx);
|
SPDK_DEBUGLOG(vhost_blk, "Invalid request (req_idx = %"PRIu16").\n", task->req_idx);
|
||||||
/* Only READ and WRITE are supported for now. */
|
/* 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;
|
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);
|
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
|
static void
|
||||||
bdev_event_cpl_cb(struct spdk_vhost_dev *vdev, void *ctx)
|
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)
|
void *event_ctx)
|
||||||
{
|
{
|
||||||
struct spdk_vhost_dev *vdev = (struct spdk_vhost_dev *)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",
|
SPDK_DEBUGLOG(vhost_blk, "Bdev event: type %d, name %s\n",
|
||||||
type,
|
type,
|
||||||
@ -1248,7 +1243,7 @@ bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case SPDK_BDEV_EVENT_REMOVE:
|
case SPDK_BDEV_EVENT_REMOVE:
|
||||||
case SPDK_BDEV_EVENT_RESIZE:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type);
|
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 {
|
} else {
|
||||||
spdk_json_write_null(w);
|
spdk_json_write_null(w);
|
||||||
}
|
}
|
||||||
|
spdk_json_write_named_string(w, "transport", bvdev->ops->name);
|
||||||
|
|
||||||
spdk_json_write_object_end(w);
|
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_json_write_named_string(w, "cpumask",
|
||||||
spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)));
|
spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)));
|
||||||
spdk_json_write_named_bool(w, "readonly", bvdev->readonly);
|
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);
|
||||||
|
|
||||||
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
|
int
|
||||||
spdk_vhost_blk_construct(const char *name, const char *cpumask, const char *dev_name,
|
virtio_blk_construct_ctrlr(struct spdk_vhost_dev *vdev, const char *address,
|
||||||
const struct spdk_json_val *params)
|
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_blk_dev *bvdev = NULL;
|
||||||
struct spdk_vhost_dev *vdev;
|
struct spdk_vhost_dev *vdev;
|
||||||
struct spdk_bdev *bdev;
|
struct spdk_bdev *bdev;
|
||||||
|
const char *transport_name = VIRTIO_BLK_DEFAULT_TRANSPORT;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
spdk_vhost_lock();
|
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));
|
bvdev = calloc(1, sizeof(*bvdev));
|
||||||
if (bvdev == NULL) {
|
if (bvdev == NULL) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto out;
|
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);
|
ret = spdk_bdev_open_ext(dev_name, true, bdev_event_cb, bvdev, &bvdev->bdev_desc);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
SPDK_ERRLOG("%s: could not open bdev '%s', error=%d\n",
|
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->virtio_features = SPDK_VHOST_BLK_FEATURES_BASE;
|
||||||
vdev->disabled_features = SPDK_VHOST_BLK_DISABLED_FEATURES;
|
vdev->disabled_features = SPDK_VHOST_BLK_DISABLED_FEATURES;
|
||||||
vdev->protocol_features = SPDK_VHOST_BLK_PROTOCOL_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)) {
|
if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_UNMAP)) {
|
||||||
vdev->virtio_features |= (1ULL << VIRTIO_BLK_F_DISCARD);
|
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)) {
|
if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_WRITE_ZEROES)) {
|
||||||
vdev->virtio_features |= (1ULL << VIRTIO_BLK_F_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)) {
|
if (spdk_bdev_io_type_supported(bdev, SPDK_BDEV_IO_TYPE_FLUSH)) {
|
||||||
vdev->virtio_features |= (1ULL << VIRTIO_BLK_F_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->dummy_io_channel = spdk_bdev_get_io_channel(bvdev->bdev_desc);
|
||||||
|
|
||||||
bvdev->bdev = bdev;
|
bvdev->bdev = bdev;
|
||||||
bvdev->readonly = req.readonly;
|
bvdev->readonly = false;
|
||||||
ret = vhost_dev_register(vdev, name, cpumask, &vhost_blk_device_backend,
|
ret = vhost_dev_register(vdev, name, cpumask, params, &vhost_blk_device_backend,
|
||||||
&vhost_blk_user_device_backend);
|
&vhost_blk_user_device_backend);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
spdk_put_io_channel(bvdev->dummy_io_channel);
|
spdk_put_io_channel(bvdev->dummy_io_channel);
|
||||||
@ -1681,6 +1683,14 @@ out:
|
|||||||
return ret;
|
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
|
static int
|
||||||
vhost_blk_destroy(struct spdk_vhost_dev *vdev)
|
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);
|
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)
|
||||||
SPDK_LOG_REGISTER_COMPONENT(vhost_blk_data)
|
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,
|
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_dev_backend *backend,
|
||||||
const struct spdk_vhost_user_dev_backend *user_backend);
|
const struct spdk_vhost_user_dev_backend *user_backend);
|
||||||
int vhost_dev_unregister(struct spdk_vhost_dev *vdev);
|
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);
|
int vhost_user_init(void);
|
||||||
void vhost_user_fini(spdk_vhost_fini_cb vhost_cb);
|
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_vhost_blk_task {
|
||||||
struct spdk_bdev_io *bdev_io;
|
struct spdk_bdev_io *bdev_io;
|
||||||
|
virtio_blk_request_cb cb;
|
||||||
|
void *cb_arg;
|
||||||
|
|
||||||
volatile uint8_t *status;
|
volatile uint8_t *status;
|
||||||
|
|
||||||
@ -556,4 +569,80 @@ struct spdk_vhost_blk_task {
|
|||||||
uint32_t payload_size;
|
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 */
|
#endif /* SPDK_VHOST_INTERNAL_H */
|
||||||
|
@ -232,12 +232,14 @@ struct rpc_vhost_blk_ctrlr {
|
|||||||
char *ctrlr;
|
char *ctrlr;
|
||||||
char *dev_name;
|
char *dev_name;
|
||||||
char *cpumask;
|
char *cpumask;
|
||||||
|
char *transport;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct spdk_json_object_decoder rpc_construct_vhost_blk_ctrlr[] = {
|
static const struct spdk_json_object_decoder rpc_construct_vhost_blk_ctrlr[] = {
|
||||||
{"ctrlr", offsetof(struct rpc_vhost_blk_ctrlr, ctrlr), spdk_json_decode_string },
|
{"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 },
|
{"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},
|
{"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
|
static void
|
||||||
@ -246,6 +248,7 @@ free_rpc_vhost_blk_ctrlr(struct rpc_vhost_blk_ctrlr *req)
|
|||||||
free(req->ctrlr);
|
free(req->ctrlr);
|
||||||
free(req->dev_name);
|
free(req->dev_name);
|
||||||
free(req->cpumask);
|
free(req->cpumask);
|
||||||
|
free(req->transport);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -263,7 +266,7 @@ rpc_vhost_create_blk_controller(struct spdk_jsonrpc_request *request,
|
|||||||
goto invalid;
|
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) {
|
if (rc < 0) {
|
||||||
goto invalid;
|
goto invalid;
|
||||||
}
|
}
|
||||||
@ -497,4 +500,51 @@ invalid:
|
|||||||
SPDK_RPC_REGISTER("vhost_controller_set_coalescing", rpc_vhost_controller_set_coalescing,
|
SPDK_RPC_REGISTER("vhost_controller_set_coalescing", rpc_vhost_controller_set_coalescing,
|
||||||
SPDK_RPC_RUNTIME)
|
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)
|
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;
|
svdev->vdev.protocol_features = SPDK_VHOST_SCSI_PROTOCOL_FEATURES;
|
||||||
|
|
||||||
spdk_vhost_lock();
|
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_device_backend,
|
||||||
&spdk_vhost_scsi_user_device_backend);
|
&spdk_vhost_scsi_user_device_backend);
|
||||||
if (rc) {
|
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)
|
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):
|
def vhost_create_scsi_controller(client, ctrlr, cpumask=None):
|
||||||
"""Create a vhost scsi controller.
|
"""Create a vhost scsi controller.
|
||||||
Args:
|
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)
|
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.
|
"""Create vhost BLK controller.
|
||||||
Args:
|
Args:
|
||||||
ctrlr: controller name
|
ctrlr: controller name
|
||||||
dev_name: device name to add to controller
|
dev_name: device name to add to controller
|
||||||
cpumask: cpu mask for this controller
|
cpumask: cpu mask for this controller
|
||||||
|
transport: virtio blk transport name (default: vhost_user_blk)
|
||||||
readonly: set controller as read-only
|
readonly: set controller as read-only
|
||||||
packed_ring: support controller packed_ring
|
packed_ring: support controller packed_ring
|
||||||
packed_ring_recovery: enable packed ring live recovery
|
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:
|
if cpumask:
|
||||||
params['cpumask'] = cpumask
|
params['cpumask'] = cpumask
|
||||||
|
if transport:
|
||||||
|
params['transport'] = transport
|
||||||
if readonly:
|
if readonly:
|
||||||
params['readonly'] = readonly
|
params['readonly'] = readonly
|
||||||
if packed_ring:
|
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.add_argument('iops_threshold', help='IOPS threshold when coalescing is enabled', type=int)
|
||||||
p.set_defaults(func=vhost_controller_set_coalescing)
|
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):
|
def vhost_create_scsi_controller(args):
|
||||||
rpc.vhost.vhost_create_scsi_controller(args.client,
|
rpc.vhost.vhost_create_scsi_controller(args.client,
|
||||||
ctrlr=args.ctrlr,
|
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,
|
ctrlr=args.ctrlr,
|
||||||
dev_name=args.dev_name,
|
dev_name=args.dev_name,
|
||||||
cpumask=args.cpumask,
|
cpumask=args.cpumask,
|
||||||
|
transport=args.transport,
|
||||||
readonly=args.readonly,
|
readonly=args.readonly,
|
||||||
packed_ring=args.packed_ring,
|
packed_ring=args.packed_ring,
|
||||||
packed_ring_recovery=args.packed_ring_recovery)
|
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('ctrlr', help='controller name')
|
||||||
p.add_argument('dev_name', help='device name')
|
p.add_argument('dev_name', help='device name')
|
||||||
p.add_argument('--cpumask', help='cpu mask for this controller')
|
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("-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("-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')
|
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);
|
CU_ASSERT(rc == 0);
|
||||||
SPDK_CU_ASSERT_FATAL(vdev != NULL);
|
SPDK_CU_ASSERT_FATAL(vdev != NULL);
|
||||||
memset(vdev, 0, sizeof(*vdev));
|
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) {
|
if (rc == 0) {
|
||||||
*vdev_p = vdev;
|
*vdev_p = vdev;
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user