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,9 +98,9 @@ struct virtio_dev {
}; };
struct virtio_dev_ops { struct virtio_dev_ops {
void (*read_dev_cfg)(struct virtio_dev *hw, size_t offset, int (*read_dev_cfg)(struct virtio_dev *hw, size_t offset,
void *dst, int len); void *dst, int len);
void (*write_dev_cfg)(struct virtio_dev *hw, size_t offset, int (*write_dev_cfg)(struct virtio_dev *hw, size_t offset,
const void *src, int len); const void *src, int len);
uint8_t (*get_status)(struct virtio_dev *hw); uint8_t (*get_status)(struct virtio_dev *hw);
void (*set_status)(struct virtio_dev *hw, uint8_t status); 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 offset offset in bytes
* \param src pointer to data to copy from * \param src pointer to data to copy from
* \param len length of data to copy in bytes * \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 * 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 offset offset in bytes
* \param dst pointer to buffer to copy data into * \param dst pointer to buffer to copy data into
* \param len length of data to copy in bytes * \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. * 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; int rc;
if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_BLK_SIZE)) { if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_BLK_SIZE)) {
virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, blk_size), rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, blk_size),
&block_size, sizeof(block_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) { if (block_size == 0 || block_size % 512 != 0) {
SPDK_ERRLOG("%s: invalid block size (%"PRIu32"). Must be " SPDK_ERRLOG("%s: invalid block size (%"PRIu32"). Must be "
"a multiple of 512.\n", vdev->name, block_size); "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; block_size = 512;
} }
virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, capacity), rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, capacity),
&capacity, sizeof(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. */ /* `capacity` is a number of 512-byte sectors. */
num_blocks = capacity * 512 / block_size; 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)) { if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_MQ)) {
virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues), rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues),
&host_max_queues, sizeof(host_max_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 { } else {
host_max_queues = 1; 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 */ /* TODO: add a way to limit usable virtqueues */
if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_MQ)) { if (virtio_dev_has_feature(vdev, VIRTIO_BLK_F_MQ)) {
virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues), rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_blk_config, num_queues),
&num_queues, sizeof(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 { } else {
num_queues = 1; 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; return NULL;
} }
virtio_dev_read_dev_config(vdev, offsetof(struct virtio_scsi_config, num_queues), rc = virtio_dev_read_dev_config(vdev, offsetof(struct virtio_scsi_config, num_queues),
&num_queues, sizeof(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); rc = virtio_scsi_dev_init(svdev, num_queues);
if (rc != 0) { 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); pthread_mutex_unlock(&vdev->mutex);
} }
void int
virtio_dev_read_dev_config(struct virtio_dev *dev, size_t offset, virtio_dev_read_dev_config(struct virtio_dev *dev, size_t offset,
void *dst, int length) 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, virtio_dev_write_dev_config(struct virtio_dev *dev, size_t offset,
const void *src, int length) 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 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); spdk_mmio_write_4(hi, val >> 32);
} }
static void static int
modern_read_dev_config(struct virtio_dev *dev, size_t offset, modern_read_dev_config(struct virtio_dev *dev, size_t offset,
void *dst, int length) 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); new_gen = spdk_mmio_read_1(&hw->common_cfg->config_generation);
} while (old_gen != new_gen); } while (old_gen != new_gen);
return 0;
} }
static void static int
modern_write_dev_config(struct virtio_dev *dev, size_t offset, modern_write_dev_config(struct virtio_dev *dev, size_t offset,
const void *src, int length) 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++) { for (i = 0; i < length; i++) {
spdk_mmio_write_1(((uint8_t *)hw->dev_cfg) + offset + i, *p++); spdk_mmio_write_1(((uint8_t *)hw->dev_cfg) + offset + i, *p++);
} }
return 0;
} }
static uint64_t static uint64_t

View File

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