virtio: allow config read/write to fail

For vhost-user it's a protocol feature that can simply
be not supported. The subsequent patch introduces an extra
check that may cause config read/write to fail.

Change-Id: I5b0e11845fb6021472c608477f1797dada8ab961
Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-on: https://review.gerrithub.io/417458
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
This commit is contained in:
Dariusz Stojaczyk 2018-07-02 13:13:52 +02:00 committed by Jim Harris
parent 48322f0c37
commit 62844ae3ca
6 changed files with 60 additions and 26 deletions

View File

@ -98,10 +98,10 @@ struct virtio_dev {
};
struct virtio_dev_ops {
void (*read_dev_cfg)(struct virtio_dev *hw, size_t offset,
void *dst, int len);
void (*write_dev_cfg)(struct virtio_dev *hw, size_t offset,
const void *src, int len);
int (*read_dev_cfg)(struct virtio_dev *hw, size_t offset,
void *dst, int len);
int (*write_dev_cfg)(struct virtio_dev *hw, size_t offset,
const void *src, int len);
uint8_t (*get_status)(struct virtio_dev *hw);
void (*set_status)(struct virtio_dev *hw, uint8_t status);
@ -392,8 +392,9 @@ void virtio_dev_set_status(struct virtio_dev *vdev, uint8_t flag);
* \param offset offset in bytes
* \param src pointer to data to copy from
* \param len length of data to copy in bytes
* \return 0 on success, negative errno otherwise
*/
void virtio_dev_write_dev_config(struct virtio_dev *vdev, size_t offset, const void *src, int len);
int virtio_dev_write_dev_config(struct virtio_dev *vdev, size_t offset, const void *src, int len);
/**
* Read raw data from the device config at given offset. This call does not
@ -403,8 +404,9 @@ void virtio_dev_write_dev_config(struct virtio_dev *vdev, size_t offset, const v
* \param offset offset in bytes
* \param dst pointer to buffer to copy data into
* \param len length of data to copy in bytes
* \return 0 on success, negative errno otherwise
*/
void virtio_dev_read_dev_config(struct virtio_dev *vdev, size_t offset, void *dst, int len);
int virtio_dev_read_dev_config(struct virtio_dev *vdev, size_t offset, void *dst, int len);
/**
* Get backend-specific ops for given device.

View File

@ -352,8 +352,13 @@ virtio_blk_dev_init(struct virtio_blk_dev *bvdev, uint16_t max_queues)
int rc;
if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_BLK_SIZE)) {
virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, blk_size),
&block_size, sizeof(block_size));
rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, blk_size),
&block_size, sizeof(block_size));
if (rc) {
SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
return rc;
}
if (block_size == 0 || block_size % 512 != 0) {
SPDK_ERRLOG("%s: invalid block size (%"PRIu32"). Must be "
"a multiple of 512.\n", vdev->name, block_size);
@ -363,8 +368,12 @@ virtio_blk_dev_init(struct virtio_blk_dev *bvdev, uint16_t max_queues)
block_size = 512;
}
virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, capacity),
&capacity, sizeof(capacity));
rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, capacity),
&capacity, sizeof(capacity));
if (rc) {
SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
return rc;
}
/* `capacity` is a number of 512-byte sectors. */
num_blocks = capacity * 512 / block_size;
@ -381,8 +390,12 @@ virtio_blk_dev_init(struct virtio_blk_dev *bvdev, uint16_t max_queues)
}
if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_MQ)) {
virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues),
&host_max_queues, sizeof(host_max_queues));
rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues),
&host_max_queues, sizeof(host_max_queues));
if (rc) {
SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
return rc;
}
} else {
host_max_queues = 1;
}
@ -478,8 +491,14 @@ virtio_pci_blk_dev_create(const char *name, struct virtio_pci_ctx *pci_ctx)
/* TODO: add a way to limit usable virtqueues */
if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_MQ)) {
virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues),
&num_queues, sizeof(num_queues));
rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues),
&num_queues, sizeof(num_queues));
if (rc) {
SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
virtio_dev_destruct(vdev);
free(bvdev);
return NULL;
}
} else {
num_queues = 1;
}

View File

@ -337,8 +337,14 @@ virtio_pci_scsi_dev_create(const char *name, struct virtio_pci_ctx *pci_ctx)
return NULL;
}
virtio_dev_read_dev_config(vdev, offsetof(struct virtio_scsi_config, num_queues),
&num_queues, sizeof(num_queues));
rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_scsi_config, num_queues),
&num_queues, sizeof(num_queues));
if (rc) {
SPDK_ERRLOG("%s: config read failed: %s\n", vdev->name, spdk_strerror(-rc));
virtio_dev_destruct(vdev);
free(svdev);
return NULL;
}
rc = virtio_scsi_dev_init(svdev, num_queues);
if (rc != 0) {

View File

@ -683,18 +683,18 @@ virtio_dev_release_queue(struct virtio_dev *vdev, uint16_t index)
pthread_mutex_unlock(&vdev->mutex);
}
void
int
virtio_dev_read_dev_config(struct virtio_dev *dev, size_t offset,
void *dst, int length)
{
virtio_dev_backend_ops(dev)->read_dev_cfg(dev, offset, dst, length);
return virtio_dev_backend_ops(dev)->read_dev_cfg(dev, offset, dst, length);
}
void
int
virtio_dev_write_dev_config(struct virtio_dev *dev, size_t offset,
const void *src, int length)
{
virtio_dev_backend_ops(dev)->write_dev_cfg(dev, offset, src, length);
return virtio_dev_backend_ops(dev)->write_dev_cfg(dev, offset, src, length);
}
void

View File

@ -146,7 +146,7 @@ io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
spdk_mmio_write_4(hi, val >> 32);
}
static void
static int
modern_read_dev_config(struct virtio_dev *dev, size_t offset,
void *dst, int length)
{
@ -165,9 +165,11 @@ modern_read_dev_config(struct virtio_dev *dev, size_t offset,
new_gen = spdk_mmio_read_1(&hw->common_cfg->config_generation);
} while (old_gen != new_gen);
return 0;
}
static void
static int
modern_write_dev_config(struct virtio_dev *dev, size_t offset,
const void *src, int length)
{
@ -178,6 +180,8 @@ modern_write_dev_config(struct virtio_dev *dev, size_t offset,
for (i = 0; i < length; i++) {
spdk_mmio_write_1(((uint8_t *)hw->dev_cfg) + offset + i, *p++);
}
return 0;
}
static uint64_t

View File

@ -215,7 +215,7 @@ virtio_user_dev_setup(struct virtio_dev *vdev)
return 0;
}
static void
static int
virtio_user_read_dev_config(struct virtio_dev *vdev, size_t offset,
void *dst, int length)
{
@ -227,13 +227,14 @@ virtio_user_read_dev_config(struct virtio_dev *vdev, size_t offset,
if (dev->ops->send_request(dev, VHOST_USER_GET_CONFIG, &cfg) < 0) {
SPDK_ERRLOG("get_config failed: %s\n", spdk_strerror(errno));
return;
return -errno;
}
memcpy(dst, cfg.region + offset, length);
return 0;
}
static void
static int
virtio_user_write_dev_config(struct virtio_dev *vdev, size_t offset,
const void *src, int length)
{
@ -246,8 +247,10 @@ virtio_user_write_dev_config(struct virtio_dev *vdev, size_t offset,
if (dev->ops->send_request(dev, VHOST_USER_SET_CONFIG, &cfg) < 0) {
SPDK_ERRLOG("set_config failed: %s\n", spdk_strerror(errno));
return;
return -errno;
}
return 0;
}
static void