virtio/vfio_user: add virtio_blk device support

Add vfio-user transport support based on existing virtio client
library.

Test steps using bdevperf:

Start `spdk_tgt` with created virtio_blk device:
1. build/bin/spdk_tgt
2. scripts/rpc.py bdev_malloc_create -b malloc0 $((512)) 512
3. scripts/rpc.py vfu_virtio_create_blk_endpoint vfu.0 --bdev-name malloc0 \
                                                 --cpumask=0x1 --num-queues=2 \
                                                 --qsize=256 --packed-ring

Start `bdevperf`:
1. test/bdev/bdevperf/bdevperf -r /var/tmp/spdk.sock.1 -g -s 2048 -q 128 -o 4096 \
                               -w randread -t 30 -m 0x2
2. scripts/rpc.py -s /var/tmp/spdk.sock.1 bdev_virtio_attach_controller --dev-type blk \
                  --trtype vfio-user --traddr vfu.0 VirtioBlk0
3. test/bdev/bdevperf/bdevperf.py -s /var/tmp/spdk.sock.1 perform_tests

Change-Id: I368c4becebbca57328a25fc750e41c353420e481
Signed-off-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/13896
Community-CI: Mellanox Build Bot
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Konrad Sztyber <konrad.sztyber@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Changpeng Liu 2022-07-13 16:19:01 +08:00 committed by Tomasz Zawadzki
parent e50ade3153
commit 295e54d144
8 changed files with 572 additions and 11 deletions

View File

@ -443,6 +443,17 @@ int virtio_pci_dev_attach(virtio_pci_create_cb create_cb, void *enum_ctx,
int virtio_user_dev_init(struct virtio_dev *vdev, const char *name, const char *path,
uint32_t queue_size);
/**
* Connect to a vfio-user device and init corresponding virtio_dev struct.
* The virtio_dev will have to be freed with \c virtio_dev_free.
*
* \param vdev preallocated vhost device struct to operate on
* \param name name of this virtio device
* \param path path to the Unix domain socket of the vhost-user device
* \return virtio device
*/
int virtio_vfio_user_dev_init(struct virtio_dev *vdev, const char *name, const char *path);
/**
* Initialize virtio_dev for a given PCI device.
* The virtio_dev has to be freed with \c virtio_dev_destruct.

View File

@ -6,11 +6,11 @@
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
SO_VER := 4
SO_VER := 5
SO_MINOR := 0
CFLAGS += $(ENV_CFLAGS)
C_SRCS = virtio.c virtio_vhost_user.c virtio_pci.c
C_SRCS = virtio.c virtio_vhost_user.c virtio_vfio_user.c virtio_pci.c
LIBNAME = virtio
SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_virtio.map)

View File

@ -27,6 +27,7 @@
virtio_pci_dev_enumerate;
virtio_pci_dev_attach;
virtio_user_dev_init;
virtio_vfio_user_dev_init;
virtio_pci_dev_init;
virtio_pci_dev_event_process;

View File

@ -0,0 +1,482 @@
/* SPDX-License-Identifier: BSD-3-Clause
* Copyright (c) Intel Corporation. All rights reserved.
*/
#include "spdk/stdinc.h"
#include "spdk/memory.h"
#include "spdk/vfio_user_pci.h"
#include "spdk_internal/virtio.h"
#include <linux/vfio.h>
struct virtio_vfio_user_dev {
struct vfio_device *ctx;
char path[PATH_MAX];
uint32_t pci_cap_region;
uint32_t pci_cap_common_cfg_offset;
uint32_t pci_cap_common_cfg_length;
uint32_t pci_cap_device_specific_offset;
uint32_t pci_cap_device_specific_length;
uint32_t pci_cap_notifications_offset;
uint32_t pci_cap_notifications_length;
};
static int
virtio_vfio_user_read_dev_config(struct virtio_dev *vdev, size_t offset,
void *dst, int length)
{
struct virtio_vfio_user_dev *dev = vdev->ctx;
SPDK_DEBUGLOG(virtio_vfio_user, "offset 0x%lx, length 0x%x\n", offset, length);
return spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
dev->pci_cap_device_specific_offset + offset,
length, dst, false);
}
static int
virtio_vfio_user_write_dev_config(struct virtio_dev *vdev, size_t offset,
const void *src, int length)
{
struct virtio_vfio_user_dev *dev = vdev->ctx;
SPDK_DEBUGLOG(virtio_vfio_user, "offset 0x%lx, length 0x%x\n", offset, length);
return spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
dev->pci_cap_device_specific_offset + offset,
length, (void *)src, true);
}
static uint8_t
virtio_vfio_user_get_status(struct virtio_dev *vdev)
{
struct virtio_vfio_user_dev *dev = vdev->ctx;
uint64_t offset;
uint8_t status = 0;
int rc;
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_STATUS;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 1, &status, false);
if (rc) {
SPDK_ERRLOG("Failed to get device status\n");
}
SPDK_DEBUGLOG(virtio_vfio_user, "device status %x\n", status);
return status;
}
static void
virtio_vfio_user_set_status(struct virtio_dev *vdev, uint8_t status)
{
struct virtio_vfio_user_dev *dev = vdev->ctx;
uint64_t offset;
int rc;
SPDK_DEBUGLOG(virtio_vfio_user, "device status %x\n", status);
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_STATUS;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 1, &status, true);
if (rc) {
SPDK_ERRLOG("Failed to set device status\n");
}
}
static uint64_t
virtio_vfio_user_get_features(struct virtio_dev *vdev)
{
struct virtio_vfio_user_dev *dev = vdev->ctx;
uint64_t offset;
uint32_t features_lo, features_hi, feature_select;
int rc;
feature_select = 0;
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_DFSELECT;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 4, &feature_select, true);
if (rc) {
SPDK_ERRLOG("Failed to set device feature select\n");
}
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_DF;
features_lo = 0;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 4, &features_lo, false);
if (rc) {
SPDK_ERRLOG("Failed to get device feature low\n");
}
feature_select = 1;
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_DFSELECT;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 4, &feature_select, true);
if (rc) {
SPDK_ERRLOG("Failed to set device feature select\n");
}
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_DF;
features_hi = 0;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 4, &features_hi, false);
if (rc) {
SPDK_ERRLOG("Failed to get device feature high\n");
}
SPDK_DEBUGLOG(virtio_vfio_user, "feature_hi 0x%x, feature_low 0x%x\n", features_hi, features_lo);
return (((uint64_t)features_hi << 32) | ((uint64_t)features_lo));
}
static int
virtio_vfio_user_set_features(struct virtio_dev *vdev, uint64_t features)
{
struct virtio_vfio_user_dev *dev = vdev->ctx;
uint64_t offset;
uint32_t features_lo, features_hi, feature_select;
int rc;
feature_select = 0;
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_GFSELECT;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 4, &feature_select, true);
if (rc) {
SPDK_ERRLOG("Failed to set Guest feature select\n");
return rc;
}
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_GF;
features_lo = (uint32_t)features;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 4, &features_lo, true);
if (rc) {
SPDK_ERRLOG("Failed to set Guest feature low\n");
return rc;
}
feature_select = 1;
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_GFSELECT;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 4, &feature_select, true);
if (rc) {
SPDK_ERRLOG("Failed to set Guest feature select\n");
return rc;
}
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_GF;
features_hi = (uint32_t)(features >> 32);
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 4, &features_hi, true);
if (rc) {
SPDK_ERRLOG("Failed to set Guest feature high\n");
}
vdev->negotiated_features = features;
SPDK_DEBUGLOG(virtio_vfio_user, "features 0x%"PRIx64"\n", features);
return rc;
}
static void
virtio_vfio_user_destruct_dev(struct virtio_dev *vdev)
{
struct virtio_vfio_user_dev *dev = vdev->ctx;
spdk_vfio_user_release(dev->ctx);
free(dev);
}
static uint16_t
virtio_vfio_user_get_queue_size(struct virtio_dev *vdev, uint16_t queue_id)
{
struct virtio_vfio_user_dev *dev = vdev->ctx;
uint64_t offset;
uint16_t qsize = 0;
int rc;
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_Q_SELECT;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 2, &queue_id, true);
if (rc) {
SPDK_ERRLOG("Failed to set queue select\n");
return 0;
}
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_Q_SIZE;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 2, &qsize, false);
if (rc) {
SPDK_ERRLOG("Failed to get queue size\n");
return 0;
}
SPDK_DEBUGLOG(virtio_vfio_user, "queue %u, size %u\n", queue_id, qsize);
return qsize;
}
static int
virtio_vfio_user_setup_queue(struct virtio_dev *vdev, struct virtqueue *vq)
{
struct virtio_vfio_user_dev *dev = vdev->ctx;
uint64_t desc_addr, avail_addr, used_addr, offset;
uint32_t addr_lo, addr_hi;
uint16_t notify_off, queue_enable;
void *queue_mem;
uint64_t queue_mem_phys_addr;
int rc;
/* To ensure physical address contiguity we make the queue occupy
* only a single hugepage (2MB). As of Virtio 1.0, the queue size
* always falls within this limit.
*/
if (vq->vq_ring_size > VALUE_2MB) {
return -ENOMEM;
}
queue_mem = spdk_zmalloc(vq->vq_ring_size, VALUE_2MB, NULL,
SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
if (queue_mem == NULL) {
return -ENOMEM;
}
queue_mem_phys_addr = spdk_vtophys(queue_mem, NULL);
if (queue_mem_phys_addr == SPDK_VTOPHYS_ERROR) {
spdk_free(queue_mem);
return -EFAULT;
}
vq->vq_ring_mem = queue_mem_phys_addr;
vq->vq_ring_virt_mem = queue_mem;
desc_addr = vq->vq_ring_mem;
avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
used_addr = (avail_addr + offsetof(struct vring_avail, ring[vq->vq_nentries])
+ VIRTIO_PCI_VRING_ALIGN - 1) & ~(VIRTIO_PCI_VRING_ALIGN - 1);
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_Q_SELECT;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 2, &vq->vq_queue_index, true);
if (rc) {
SPDK_ERRLOG("Failed to set queue select\n");
goto err;
}
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_Q_DESCLO;
addr_lo = (uint32_t)desc_addr;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 4, &addr_lo, true);
if (rc) {
SPDK_ERRLOG("Failed to set desc addr low\n");
goto err;
}
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_Q_DESCHI;
addr_hi = (uint32_t)(desc_addr >> 32);
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 4, &addr_hi, true);
if (rc) {
SPDK_ERRLOG("Failed to set desc addr high\n");
goto err;
}
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_Q_AVAILLO;
addr_lo = (uint32_t)avail_addr;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 4, &addr_lo, true);
if (rc) {
SPDK_ERRLOG("Failed to set avail addr low\n");
goto err;
}
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_Q_AVAILHI;
addr_hi = (uint32_t)(avail_addr >> 32);
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 4, &addr_hi, true);
if (rc) {
SPDK_ERRLOG("Failed to set avail addr high\n");
goto err;
}
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_Q_USEDLO;
addr_lo = (uint32_t)used_addr;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 4, &addr_lo, true);
if (rc) {
SPDK_ERRLOG("Failed to set used addr low\n");
goto err;
}
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_Q_USEDHI;
addr_hi = (uint32_t)(used_addr >> 32);
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 4, &addr_hi, true);
if (rc) {
SPDK_ERRLOG("Failed to set used addr high\n");
goto err;
}
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_Q_NOFF;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 2, &notify_off, false);
if (rc) {
SPDK_ERRLOG("Failed to get queue notify off\n");
goto err;
}
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_Q_ENABLE;
queue_enable = 1;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 2, &queue_enable, true);
if (rc) {
SPDK_ERRLOG("Failed to enable queue %u\n", vq->vq_queue_index);
goto err;
}
SPDK_DEBUGLOG(virtio_vfio_user, "queue %"PRIu16" addresses:\n", vq->vq_queue_index);
SPDK_DEBUGLOG(virtio_vfio_user, "\t desc_addr: %" PRIx64 "\n", desc_addr);
SPDK_DEBUGLOG(virtio_vfio_user, "\t aval_addr: %" PRIx64 "\n", avail_addr);
SPDK_DEBUGLOG(virtio_vfio_user, "\t used_addr: %" PRIx64 "\n", used_addr);
return 0;
err:
spdk_free(queue_mem);
return rc;
}
static void
virtio_vfio_user_del_queue(struct virtio_dev *vdev, struct virtqueue *vq)
{
struct virtio_vfio_user_dev *dev = vdev->ctx;
uint64_t offset;
uint16_t queue_enable = 0;
int rc;
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_Q_SELECT;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 2, &vq->vq_queue_index, true);
if (rc) {
SPDK_ERRLOG("Failed to select queue %u\n", vq->vq_queue_index);
spdk_free(vq->vq_ring_virt_mem);
return;
}
offset = dev->pci_cap_common_cfg_offset + VIRTIO_PCI_COMMON_Q_ENABLE;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, dev->pci_cap_region,
offset, 2, &queue_enable, true);
if (rc) {
SPDK_ERRLOG("Failed to enable queue %u\n", vq->vq_queue_index);
}
spdk_free(vq->vq_ring_virt_mem);
/* TODO: clear desc/avail/used address */
}
static void
virtio_vfio_user_notify_queue(struct virtio_dev *vdev, struct virtqueue *vq)
{
/* we're running in polling mode, no need to write doorbells */
}
static const struct virtio_dev_ops virtio_vfio_user_ops = {
.read_dev_cfg = virtio_vfio_user_read_dev_config,
.write_dev_cfg = virtio_vfio_user_write_dev_config,
.get_status = virtio_vfio_user_get_status,
.set_status = virtio_vfio_user_set_status,
.get_features = virtio_vfio_user_get_features,
.set_features = virtio_vfio_user_set_features,
.destruct_dev = virtio_vfio_user_destruct_dev,
.get_queue_size = virtio_vfio_user_get_queue_size,
.setup_queue = virtio_vfio_user_setup_queue,
.del_queue = virtio_vfio_user_del_queue,
.notify_queue = virtio_vfio_user_notify_queue
};
int
virtio_vfio_user_dev_init(struct virtio_dev *vdev, const char *name, const char *path)
{
struct virtio_vfio_user_dev *dev;
uint16_t cmd_reg;
int rc;
if (name == NULL) {
SPDK_ERRLOG("No name gived for controller: %s\n", path);
return -EINVAL;
}
rc = access(path, F_OK);
if (rc != 0) {
SPDK_ERRLOG("Access path %s failed\n", path);
return -EACCES;
}
dev = calloc(1, sizeof(*dev));
if (dev == NULL) {
return -ENOMEM;
}
rc = virtio_dev_construct(vdev, name, &virtio_vfio_user_ops, dev);
if (rc != 0) {
SPDK_ERRLOG("Failed to init device: %s\n", path);
free(dev);
return rc;
}
snprintf(dev->path, PATH_MAX, "%s", path);
dev->ctx = spdk_vfio_user_setup(path);
if (!dev->ctx) {
SPDK_ERRLOG("Error to setup %s as vfio device\n", path);
virtio_dev_destruct(vdev);
free(dev);
return -EINVAL;
}
/* Enable PCI busmaster and disable INTx */
rc = spdk_vfio_user_pci_bar_access(dev->ctx, VFIO_PCI_CONFIG_REGION_INDEX, 4, 2,
&cmd_reg, false);
if (rc != 0) {
SPDK_ERRLOG("Read PCI CMD REG failed\n");
virtio_dev_destruct(vdev);
spdk_vfio_user_release(dev->ctx);
free(dev);
return rc;
}
cmd_reg |= 0x404;
rc = spdk_vfio_user_pci_bar_access(dev->ctx, VFIO_PCI_CONFIG_REGION_INDEX, 4, 2,
&cmd_reg, true);
if (rc != 0) {
SPDK_ERRLOG("Write PCI CMD REG failed\n");
virtio_dev_destruct(vdev);
spdk_vfio_user_release(dev->ctx);
free(dev);
return rc;
}
/* TODO: we cat get virtio device PCI common space layout via
* iterating vendor capabilities in PCI Configuration space,
* while here we use hardcoded layout first, this feature can
* be added in future.
*
* vfio-user emulated virtio device layout in Target:
*
* region 1: MSI-X Table
* region 2: MSI-X PBA
* region 4: virtio modern memory 64bits BAR
* Common configuration 0x0 - 0x1000
* ISR access 0x1000 - 0x2000
* Device specific configuration 0x2000 - 0x3000
* Notifications 0x3000 - 0x4000
*/
dev->pci_cap_region = VFIO_PCI_BAR4_REGION_INDEX;
dev->pci_cap_common_cfg_offset = 0x0;
dev->pci_cap_common_cfg_length = 0x1000;
dev->pci_cap_device_specific_offset = 0x2000;
dev->pci_cap_device_specific_length = 0x1000;
dev->pci_cap_notifications_offset = 0x3000;
dev->pci_cap_notifications_length = 0x1000;
return 0;
}
SPDK_LOG_REGISTER_COMPONENT(virtio_vfio_user)

View File

@ -49,7 +49,7 @@ endif
DEPDIRS-blob := log util thread dma
DEPDIRS-accel := log util thread json rpc jsonrpc
DEPDIRS-jsonrpc := log util json
DEPDIRS-virtio := log util json thread
DEPDIRS-virtio := log util json thread vfio_user
DEPDIRS-lvol := log util blob
DEPDIRS-rpc := log util json jsonrpc

View File

@ -121,6 +121,16 @@ void bdev_virtio_scsi_dev_list(struct spdk_json_write_ctx *write_ctx);
struct spdk_bdev *bdev_virtio_user_blk_dev_create(const char *name, const char *path,
unsigned num_queues, unsigned queue_size);
/**
* Connect to a vfio-user Unix domain socket and create a Virtio BLK bdev.
*
* \param name name for the virtio bdev
* \param path path to the socket
* \return virtio-blk bdev or NULL
*/
struct spdk_bdev *
bdev_virtio_vfio_user_blk_dev_create(const char *name, const char *path);
/**
* Attach virtio-pci device. This creates a Virtio BLK device with the same
* capabilities as the vhost-user equivalent.

View File

@ -730,6 +730,58 @@ bdev_virtio_user_blk_dev_create(const char *name, const char *path,
return &bvdev->bdev;
}
struct spdk_bdev *
bdev_virtio_vfio_user_blk_dev_create(const char *name, const char *path)
{
struct virtio_blk_dev *bvdev;
uint16_t num_queues = 0;
int rc;
bvdev = calloc(1, sizeof(*bvdev));
if (bvdev == NULL) {
SPDK_ERRLOG("calloc failed for virtio device %s: %s\n", name, path);
return NULL;
}
rc = virtio_vfio_user_dev_init(&bvdev->vdev, name, path);
if (rc != 0) {
SPDK_ERRLOG("Failed to create %s as virtio device\n", path);
free(bvdev);
return NULL;
}
rc = virtio_dev_reset(&bvdev->vdev, VIRTIO_BLK_DEV_SUPPORTED_FEATURES);
if (rc != 0) {
SPDK_ERRLOG("Failed to reset %s as virtio device\n", path);
virtio_dev_destruct(&bvdev->vdev);
free(bvdev);
return NULL;
}
if (virtio_dev_has_feature(&bvdev->vdev, VIRTIO_BLK_F_MQ)) {
rc = virtio_dev_read_dev_config(&bvdev->vdev, offsetof(struct virtio_blk_config, num_queues),
&num_queues, sizeof(num_queues));
if (rc) {
SPDK_ERRLOG("%s: config read failed: %s\n", name, spdk_strerror(-rc));
virtio_dev_destruct(&bvdev->vdev);
free(bvdev);
return NULL;
}
} else {
num_queues = 1;
}
rc = virtio_blk_dev_init(bvdev, num_queues);
if (rc != 0) {
SPDK_ERRLOG("Failed to initialize %s as virtio device\n", path);
virtio_dev_destruct(&bvdev->vdev);
free(bvdev);
return NULL;
}
return &bvdev->bdev;
}
static int
bdev_virtio_blk_get_ctx_size(void)
{

View File

@ -184,9 +184,8 @@ rpc_bdev_virtio_attach_controller(struct spdk_jsonrpc_request *request,
const struct spdk_json_val *params)
{
struct rpc_bdev_virtio_attach_controller_ctx *req;
struct spdk_bdev *bdev;
struct spdk_bdev *bdev = NULL;
struct spdk_pci_addr pci_addr;
bool pci;
int rc;
req = calloc(1, sizeof(*req));
@ -217,12 +216,16 @@ rpc_bdev_virtio_attach_controller(struct spdk_jsonrpc_request *request,
spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid PCI address '%s'", req->traddr);
goto cleanup;
}
pci = true;
} else if (strcmp(req->trtype, "user") == 0) {
req->vq_count = req->vq_count == 0 ? SPDK_VIRTIO_USER_DEFAULT_VQ_COUNT : req->vq_count;
req->vq_size = req->vq_size == 0 ? SPDK_VIRTIO_USER_DEFAULT_QUEUE_SIZE : req->vq_size;
pci = false;
} else if (strcmp(req->trtype, "vfio-user") == 0) {
if (req->vq_count != 0 || req->vq_size != 0) {
SPDK_ERRLOG("VQ count or size is not allowed for vfio-user transport type\n");
spdk_jsonrpc_send_error_response(request, EINVAL,
"vq_count or vq_size is not allowed for vfio-user transport type.");
goto cleanup;
}
} else {
SPDK_ERRLOG("Invalid trtype '%s'\n", req->trtype);
spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Invalid trtype '%s'", req->trtype);
@ -231,17 +234,19 @@ rpc_bdev_virtio_attach_controller(struct spdk_jsonrpc_request *request,
req->request = request;
if (strcmp(req->dev_type, "blk") == 0) {
if (pci) {
if (strcmp(req->trtype, "pci") == 0) {
bdev = bdev_virtio_pci_blk_dev_create(req->name, &pci_addr);
} else {
} else if (strcmp(req->trtype, "user") == 0) {
bdev = bdev_virtio_user_blk_dev_create(req->name, req->traddr, req->vq_count, req->vq_size);
} else if (strcmp(req->trtype, "vfio-user") == 0) {
bdev = bdev_virtio_vfio_user_blk_dev_create(req->name, req->traddr);
}
/* Virtio blk doesn't use callback so call it manually to send result. */
rc = bdev ? 0 : -EINVAL;
rpc_create_virtio_dev_cb(req, rc, &bdev, bdev ? 1 : 0);
} else if (strcmp(req->dev_type, "scsi") == 0) {
if (pci) {
if (strcmp(req->trtype, "pci") == 0) {
rc = bdev_virtio_pci_scsi_dev_create(req->name, &pci_addr, rpc_create_virtio_dev_cb, req);
} else {
rc = bdev_virtio_user_scsi_dev_create(req->name, req->traddr, req->vq_count, req->vq_size,