Commit a85a4452 authored by Pawel Wodkowski's avatar Pawel Wodkowski Committed by Daniel Verkamp
Browse files

bdev_virtio/rpc: add construct_virtio_user_scsi_bdev



Change-Id: I2a351442ead0874d98bdfb23079a723d7665dbb1
Signed-off-by: default avatarPawel Wodkowski <pawelx.wodkowski@intel.com>
Reviewed-on: https://review.gerrithub.io/381186


Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarDariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
parent d822c205
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
CFLAGS += $(ENV_CFLAGS) -I$(SPDK_ROOT_DIR)/lib/bdev/ -Irte_virtio
CFLAGS += -I$(SPDK_ROOT_DIR)/lib/vhost/linux

C_SRCS = bdev_virtio.c
C_SRCS = bdev_virtio.c bdev_virtio_rpc.c
C_SRCS += rte_virtio/virtio_dev.c rte_virtio/virtio_pci.c
C_SRCS += rte_virtio/virtio_user.c
C_SRCS += rte_virtio/virtio_user/vhost_user.c rte_virtio/virtio_user/virtio_user_dev.c
+139 −65
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@
#include <virtio_dev.h>
#include <virtio_user/virtio_user_dev.h>

#include "bdev_virtio.h"

#define BDEV_VIRTIO_MAX_TARGET 64
#define BDEV_VIRTIO_SCAN_PAYLOAD_SIZE 256
#define CTRLQ_POLL_PERIOD_US (1000 * 5)
@@ -81,6 +83,9 @@ struct virtio_scsi_scan_base {
	/** Virtqueue used for the scan I/O. */
	struct virtqueue		*vq;

	virtio_create_device_cb		cb_fn;
	void				*cb_arg;

	/* Currently queried target */
	unsigned			target;

@@ -539,7 +544,7 @@ bdev_virtio_destroy_cb(void *io_device, void *ctx_buf)
}

static void
scan_target_abort(struct virtio_scsi_scan_base *base)
scan_target_abort(struct virtio_scsi_scan_base *base, int error)
{
	struct virtio_scsi_disk *disk;

@@ -550,16 +555,20 @@ scan_target_abort(struct virtio_scsi_scan_base *base)

	TAILQ_REMOVE(&g_virtio_driver.init_ctrlrs, base->vdev, tailq);
	virtio_dev_free(base->vdev);
	spdk_dma_free(base);

	if (TAILQ_EMPTY(&g_virtio_driver.init_ctrlrs)) {
		spdk_bdev_module_init_done(SPDK_GET_BDEV_MODULE(virtio_scsi));

	if (base->cb_fn) {
		base->cb_fn(base->cb_arg, error, NULL, 0);
	}

	spdk_dma_free(base);
}

static void
scan_target_finish(struct virtio_scsi_scan_base *base)
{
	size_t bdevs_cnt = 0;
	struct spdk_bdev *bdevs[BDEV_VIRTIO_MAX_TARGET];
	struct virtio_scsi_disk *disk;
	struct virtqueue *ctrlq;
	struct spdk_ring *ctrlq_ring;
@@ -582,7 +591,7 @@ scan_target_finish(struct virtio_scsi_scan_base *base)
				      SPDK_ENV_SOCKET_ID_ANY);
	if (ctrlq_ring == NULL) {
		SPDK_ERRLOG("Failed to allocate send ring for the controlq.\n");
		scan_target_abort(base);
		scan_target_abort(base, -ENOMEM);
		return;
	}

@@ -591,7 +600,7 @@ scan_target_finish(struct virtio_scsi_scan_base *base)
		SPDK_ERRLOG("Failed to acquire the controlq.\n");
		assert(false);
		spdk_ring_free(ctrlq_ring);
		scan_target_abort(base);
		scan_target_abort(base, rc);
		return;
	}

@@ -604,16 +613,18 @@ scan_target_finish(struct virtio_scsi_scan_base *base)
		spdk_io_device_register(&disk->vdev, bdev_virtio_create_cb, bdev_virtio_destroy_cb,
					sizeof(struct bdev_virtio_io_channel));
		spdk_bdev_register(&disk->bdev);
		bdevs[bdevs_cnt] = &disk->bdev;
		bdevs_cnt++;
	}

	TAILQ_REMOVE(&g_virtio_driver.init_ctrlrs, base->vdev, tailq);
	TAILQ_INSERT_TAIL(&g_virtio_driver.attached_ctrlrs, base->vdev, tailq);

	spdk_dma_free(base);

	if (TAILQ_EMPTY(&g_virtio_driver.init_ctrlrs)) {
		spdk_bdev_module_init_done(SPDK_GET_BDEV_MODULE(virtio_scsi));
	if (base->cb_fn) {
		base->cb_fn(base->cb_arg, 0, bdevs, bdevs_cnt);
	}

	spdk_dma_free(base);
}

static void
@@ -702,7 +713,7 @@ alloc_virtio_disk(struct virtio_scsi_scan_base *base, uint8_t target_id, uint64_
	disk->target = target_id;

	bdev = &disk->bdev;
	bdev->name = spdk_sprintf_alloc("VirtioScsi%"PRIu32"t%"PRIu8, disk->vdev->id, target_id);
	bdev->name = spdk_sprintf_alloc("%st%"PRIu8, base->vdev->name, target_id);
	if (bdev->name == NULL) {
		SPDK_ERRLOG("Couldn't alloc memory for the bdev name.\n");
		free(disk);
@@ -856,7 +867,8 @@ bdev_virtio_process_config(void)
{
	struct spdk_conf_section *sp;
	struct virtio_dev *vdev = NULL;
	char *path;
	char *default_name = NULL;
	char *path, *name;
	unsigned vdev_num;
	int num_queues;
	bool enable_pci;
@@ -886,8 +898,17 @@ bdev_virtio_process_config(void)
			num_queues = 1;
		}

		vdev = virtio_user_dev_init(path, num_queues, 512,
					    SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED);
		name = spdk_conf_section_get_val(sp, "Name");
		if (name == NULL) {
			default_name = spdk_sprintf_alloc("VirtioScsi%u", vdev_num);
			name = default_name;
		}

		vdev = virtio_user_dev_init(name, path, num_queues, 512, SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED);

		free(default_name);
		default_name = NULL;

		if (vdev == NULL) {
			rc = -1;
			goto out;
@@ -908,44 +929,48 @@ out:
	return rc;
}


static int
bdev_virtio_initialize(void)
static void
bdev_virtio_scsi_free(struct virtio_dev *vdev)
{
	struct virtio_scsi_scan_base *base;
	struct virtio_dev *vdev, *next_vdev;
	struct virtqueue *vq;
	int rc = 0;

	rc = bdev_virtio_process_config();
	if (rc != 0) {
		goto out;
	if (virtio_dev_queue_is_acquired(vdev, VIRTIO_SCSI_REQUESTQ)) {
		vq = vdev->vqs[VIRTIO_SCSI_REQUESTQ];
		spdk_bdev_poller_stop(&vq->poller);
		spdk_dma_free(vq->poller_ctx);
		vq->poller_ctx = NULL;
		virtio_dev_release_queue(vdev, VIRTIO_SCSI_REQUESTQ);
	}

	if (TAILQ_EMPTY(&g_virtio_driver.init_ctrlrs)) {
		spdk_bdev_module_init_done(SPDK_GET_BDEV_MODULE(virtio_scsi));
		return 0;
	virtio_dev_free(vdev);
}

	/* Initialize all created devices and scan available targets */
	TAILQ_FOREACH(vdev, &g_virtio_driver.init_ctrlrs, tailq) {
		base = spdk_dma_zmalloc(sizeof(*base), 64, NULL);
static int
bdev_virtio_scsi_scan(struct virtio_dev *vdev, virtio_create_device_cb cb_fn, void *cb_arg)
{
	struct virtio_scsi_scan_base *base = spdk_dma_zmalloc(sizeof(struct virtio_scsi_scan_base), 64,
					     NULL);
	struct virtqueue *vq;
	int rc;

	if (base == NULL) {
		SPDK_ERRLOG("couldn't allocate memory for scsi target scan.\n");
			rc = -1;
			goto out;
		return -ENOMEM;
	}

	base->cb_fn = cb_fn;
	base->cb_arg = cb_arg;

	rc = virtio_dev_init(vdev, VIRTIO_SCSI_DEV_SUPPORTED_FEATURES);
	if (rc != 0) {
		spdk_dma_free(base);
			goto out;
		return rc;
	}

	rc = virtio_dev_start(vdev);
	if (rc != 0) {
		spdk_dma_free(base);
			goto out;
		return rc;
	}

	base->vdev = vdev;
@@ -955,17 +980,51 @@ bdev_virtio_initialize(void)
	if (rc != 0) {
		SPDK_ERRLOG("Couldn't acquire requestq for the target scan.\n");
		spdk_dma_free(base);
			goto out;
		return rc;
	}

	vq = vdev->vqs[VIRTIO_SCSI_REQUESTQ];
	base->vq = vq;
	vq->poller_ctx = base;
	spdk_bdev_poller_start(&vq->poller, bdev_scan_poll, base, 0);

	rc = scan_target(base);
		if (rc != 0) {
	if (rc) {
		SPDK_ERRLOG("Failed to start target scan.\n");
	}

	return rc;
}

static void
bdev_virtio_initial_scan_complete(void *ctx __attribute__((unused)),
				  int result  __attribute__((unused)),
				  struct spdk_bdev **bdevs __attribute__((unused)), size_t bdevs_cnt __attribute__((unused)))
{
	if (TAILQ_EMPTY(&g_virtio_driver.init_ctrlrs)) {
		spdk_bdev_module_init_done(SPDK_GET_BDEV_MODULE(virtio_scsi));
	}
}

static int
bdev_virtio_initialize(void)
{
	struct virtio_dev *vdev, *next_vdev;
	int rc;

	rc = bdev_virtio_process_config();
	if (rc != 0) {
		goto out;
	}

	if (TAILQ_EMPTY(&g_virtio_driver.init_ctrlrs)) {
		spdk_bdev_module_init_done(SPDK_GET_BDEV_MODULE(virtio_scsi));
		return 0;
	}

	/* Initialize all created devices and scan available targets */
	TAILQ_FOREACH(vdev, &g_virtio_driver.init_ctrlrs, tailq) {
		rc = bdev_virtio_scsi_scan(vdev, bdev_virtio_initial_scan_complete, NULL);
		if (rc != 0) {
			goto out;
		}
	}
@@ -976,24 +1035,15 @@ out:
	/* Remove any created devices */
	TAILQ_FOREACH_SAFE(vdev, &g_virtio_driver.init_ctrlrs, tailq, next_vdev) {
		TAILQ_REMOVE(&g_virtio_driver.init_ctrlrs, vdev, tailq);
		if (virtio_dev_queue_is_acquired(vdev, VIRTIO_SCSI_REQUESTQ)) {
			vq = vdev->vqs[VIRTIO_SCSI_REQUESTQ];
			spdk_bdev_poller_stop(&vq->poller);
			spdk_dma_free(vq->poller_ctx);
			vq->poller_ctx = NULL;
			virtio_dev_release_queue(vdev, VIRTIO_SCSI_REQUESTQ);
		}
		/* since scan pollers couldn't do a single tick yet.
		 * it's safe just to free the vdev now.
		 */
		virtio_dev_free(vdev);
		bdev_virtio_scsi_free(vdev);
	}

	spdk_bdev_module_init_done(SPDK_GET_BDEV_MODULE(virtio_scsi));
	return rc;
}

static void bdev_virtio_finish(void)
static void
bdev_virtio_finish(void)
{
	struct virtio_dev *vdev, *next;
	struct virtqueue *vq;
@@ -1015,4 +1065,28 @@ static void bdev_virtio_finish(void)
	}
}

int
create_virtio_user_scsi_device(const char *base_name, const char *path, unsigned num_queues,
			       unsigned queue_size, virtio_create_device_cb cb_fn, void *cb_arg)
{
	struct virtio_dev *vdev;
	int rc;

	vdev = virtio_user_dev_init(base_name, path, num_queues, queue_size,
				    SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED);
	if (!vdev) {
		SPDK_ERRLOG("Failed to create virito device %s: %s\n", base_name, path);
		return -EINVAL;
	}

	rc = bdev_virtio_scsi_scan(vdev, cb_fn, cb_arg);
	if (rc) {
		TAILQ_REMOVE(&g_virtio_driver.init_ctrlrs, vdev, tailq);
		bdev_virtio_scsi_free(vdev);
	}

	return rc;
}


SPDK_LOG_REGISTER_TRACE_FLAG("virtio", SPDK_TRACE_VIRTIO)
+66 −0
Original line number Diff line number Diff line
/*-
 *   BSD LICENSE
 *
 *   Copyright (c) Intel Corporation.
 *   All rights reserved.
 *
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the
 *       distribution.
 *     * Neither the name of Intel Corporation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef SPDK_BDEV_VIRTIO_H
#define SPDK_BDEV_VIRTIO_H

#include "spdk/bdev.h"

typedef void (*virtio_create_device_cb)(void *, int, struct spdk_bdev **, size_t size);

/**
 * Add new Virtio SCSI device and scan it. When LUN is found bdev is automaticly
 * added to point this LUN.
 *
 * \param path
 *   Path to socket.
 * \param base_name
 *   Name to used for all bdevs created from this device.
 * \param vq_size
 *   Max queue size.
 * \param cb_fn
 *   An optional callback to be called after scanning all targets on the controller.
 *   First parameter is \c cb_arg
 *   Second parameter is error code. Zero on succes or negative error code.
 *   Third parameter is bdevs array found on created device. NULL in case of error.
 *   Fourth is number of bdevs in array. Zero in case of error.
 * \param cb_arg1
 *   First argument of \c cb_fn
 * \return
 *   Zero on success (device scan is started) or negative error code.
 *   In case of error \c done_cb is not called.
 */
int create_virtio_user_scsi_device(const char *base_name, const char *path, unsigned num_queues,
				   unsigned queue_size, virtio_create_device_cb cb_fn, void *cb_arg);

#endif /* SPDK_BDEV_VIRTIO_H */
+140 −0
Original line number Diff line number Diff line
/*-
 *   BSD LICENSE
 *
 *   Copyright (c) Intel Corporation.
 *   All rights reserved.
 *
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in
 *       the documentation and/or other materials provided with the
 *       distribution.
 *     * Neither the name of Intel Corporation nor the names of its
 *       contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "spdk/stdinc.h"

#include "spdk/string.h"
#include "spdk/rpc.h"
#include "spdk/util.h"
#include "spdk_internal/log.h"

#include "bdev_virtio.h"

struct rpc_virtio_user_scsi_dev {
	char *path;
	char *name;
	uint32_t vq_count;
	uint32_t vq_size;
	struct spdk_jsonrpc_request *request;

};

static const struct spdk_json_object_decoder rpc_construct_virtio_user_scsi_dev[] = {
	{"path", offsetof(struct rpc_virtio_user_scsi_dev, path), spdk_json_decode_string },
	{"name", offsetof(struct rpc_virtio_user_scsi_dev, name), spdk_json_decode_string },
	{"vq_count", offsetof(struct rpc_virtio_user_scsi_dev, vq_size), spdk_json_decode_uint32, true },
	{"vq_size", offsetof(struct rpc_virtio_user_scsi_dev, vq_size), spdk_json_decode_uint32, true },
};

static void
free_rpc_connect_virtio_user_scsi_dev(struct rpc_virtio_user_scsi_dev *req)
{
	if (!req) {
		return;
	}

	free(req->path);
	free(req->name);
	free(req);
}

static void
rpc_create_virtio_user_scsi_bdev_cb(void *ctx, int result, struct spdk_bdev **bdevs, size_t cnt)
{
	struct rpc_virtio_user_scsi_dev *req = ctx;
	struct spdk_json_write_ctx *w;
	char buf[64];
	size_t i;

	if (result) {
		spdk_strerror_r(-result, buf, sizeof(buf));
		spdk_jsonrpc_send_error_response(req->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
		free_rpc_connect_virtio_user_scsi_dev(req);
		return;
	}

	w = spdk_jsonrpc_begin_result(req->request);
	if (w) {
		spdk_json_write_array_begin(w);

		for (i = 0; i < cnt; i++) {
			spdk_json_write_string(w, spdk_bdev_get_name(bdevs[i]));
			bdevs++;
		}

		spdk_json_write_array_end(w);
		spdk_jsonrpc_end_result(req->request, w);
	}

	free_rpc_connect_virtio_user_scsi_dev(ctx);
}

static void
spdk_rpc_create_virtio_user_scsi_bdev(struct spdk_jsonrpc_request *request,
				      const struct spdk_json_val *params)
{
	struct rpc_virtio_user_scsi_dev *req;
	char buf[64];
	int rc;

	req = calloc(1, sizeof(*req));
	if (!req) {
		rc = -ENOMEM;
		goto invalid;
	}

	req->vq_count = 1;
	req->vq_size = 512;

	if (spdk_json_decode_object(params, rpc_construct_virtio_user_scsi_dev,
				    SPDK_COUNTOF(rpc_construct_virtio_user_scsi_dev),
				    req)) {
		rc = -EINVAL;
		goto invalid;
	}

	req->request = request;
	rc = create_virtio_user_scsi_device(req->name, req->path, req->vq_count, req->vq_size,
					    rpc_create_virtio_user_scsi_bdev_cb, req);
	if (rc < 0) {
		goto invalid;
	}

	return;

invalid:
	spdk_strerror_r(-rc, buf, sizeof(buf));
	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, buf);
	free_rpc_connect_virtio_user_scsi_dev(req);
}
SPDK_RPC_REGISTER("construct_virtio_user_scsi_bdev", spdk_rpc_create_virtio_user_scsi_bdev);
+3 −0
Original line number Diff line number Diff line
@@ -73,6 +73,9 @@

struct virtio_dev {
	struct virtqueue **vqs;

	/** Name of this virtio dev set by backend */
	char		*name;
	uint16_t	started;

	/** Max number of queues the host supports. */
Loading