Commit b727e804 authored by Tomasz Zawadzki's avatar Tomasz Zawadzki
Browse files

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: default avatarTomasz Zawadzki <tomasz.zawadzki@intel.com>
Change-Id: Ic9d93a6e0f483796eb56b7174a678e41a6ea4808
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/9540


Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarKonrad Sztyber <konrad.sztyber@intel.com>
Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent 2dd64cf9
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -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

+2 −1
Original line number Diff line number Diff line
@@ -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.
+104 −5
Original line number Diff line number Diff line
@@ -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)
+149 −48
Original line number Diff line number Diff line
@@ -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);
@@ -1592,32 +1589,45 @@ static const struct spdk_vhost_dev_backend vhost_blk_device_backend = {
	.remove_device = vhost_blk_destroy,
};

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)
{
	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 struct spdk_json_val *params)
			 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)
+89 −0
Original line number Diff line number Diff line
@@ -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 */
Loading