virtio: move virtio_dev allocation to upper layers

This allows the to use a virtio_dev allocated as
a part of bigger struct - possibly a SCSI/BLK
specific wrapper.

As a part of this refactor, multiple vdev-related
functions have been renamed to keep the API clean.

Change-Id: If84bf03e4a1642869c2f1ba93939fb32c8fb5d57
Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-on: https://review.gerrithub.io/388298
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
Dariusz Stojaczyk 2017-11-20 19:24:24 +01:00 committed by Jim Harris
parent 04f528938d
commit 48aced6ebc
5 changed files with 103 additions and 74 deletions

View File

@ -574,8 +574,9 @@ scan_target_abort(struct virtio_scsi_scan_base *base, int error)
} }
TAILQ_REMOVE(&g_virtio_driver.init_ctrlrs, base->vdev, tailq); TAILQ_REMOVE(&g_virtio_driver.init_ctrlrs, base->vdev, tailq);
virtio_dev_reset(base->vdev); virtio_dev_stop(base->vdev);
virtio_dev_free(base->vdev); virtio_dev_destruct(base->vdev);
free(base->vdev);
if (base->cb_fn) { if (base->cb_fn) {
@ -1147,19 +1148,26 @@ bdev_virtio_process_config(void)
num_queues = 1; num_queues = 1;
} }
vdev = calloc(1, sizeof(*vdev));
if (vdev == NULL) {
SPDK_ERRLOG("virtio device calloc failed\n");
goto out;
}
name = spdk_conf_section_get_val(sp, "Name"); name = spdk_conf_section_get_val(sp, "Name");
if (name == NULL) { if (name == NULL) {
default_name = spdk_sprintf_alloc("VirtioScsi%u", vdev_num); default_name = spdk_sprintf_alloc("VirtioScsi%u", vdev_num);
name = default_name; name = default_name;
} }
vdev = virtio_user_dev_init(name, path, num_queues, 512, SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED); rc = virtio_user_dev_init(vdev, name, path, num_queues, 512,
SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED);
free(default_name); free(default_name);
default_name = NULL; default_name = NULL;
if (vdev == NULL) { if (rc != 0) {
rc = -1; free(vdev);
goto out; goto out;
} }
} }
@ -1191,8 +1199,9 @@ bdev_virtio_scsi_free(struct virtio_dev *vdev)
virtio_dev_release_queue(vdev, VIRTIO_SCSI_REQUESTQ); virtio_dev_release_queue(vdev, VIRTIO_SCSI_REQUESTQ);
} }
virtio_dev_reset(vdev); virtio_dev_stop(vdev);
virtio_dev_free(vdev); virtio_dev_destruct(vdev);
free(vdev);
} }
static int static int
@ -1211,7 +1220,7 @@ bdev_virtio_scsi_scan(struct virtio_dev *vdev, virtio_create_device_cb cb_fn, vo
base->cb_fn = cb_fn; base->cb_fn = cb_fn;
base->cb_arg = cb_arg; base->cb_arg = cb_arg;
rc = virtio_dev_init(vdev, VIRTIO_SCSI_DEV_SUPPORTED_FEATURES); rc = virtio_dev_restart(vdev, VIRTIO_SCSI_DEV_SUPPORTED_FEATURES);
if (rc != 0) { if (rc != 0) {
spdk_dma_free(base); spdk_dma_free(base);
return rc; return rc;
@ -1312,8 +1321,9 @@ virtio_scsi_dev_unregister_cb(void *io_device)
virtio_dev_release_queue(vdev, VIRTIO_SCSI_CONTROLQ); virtio_dev_release_queue(vdev, VIRTIO_SCSI_CONTROLQ);
} }
virtio_dev_reset(vdev); virtio_dev_stop(vdev);
virtio_dev_free(vdev); virtio_dev_destruct(vdev);
free(vdev);
TAILQ_REMOVE(&g_virtio_driver.attached_ctrlrs, vdev, tailq); TAILQ_REMOVE(&g_virtio_driver.attached_ctrlrs, vdev, tailq);
finish_module = TAILQ_EMPTY(&g_virtio_driver.attached_ctrlrs); finish_module = TAILQ_EMPTY(&g_virtio_driver.attached_ctrlrs);
@ -1345,10 +1355,17 @@ create_virtio_user_scsi_device(const char *base_name, const char *path, unsigned
struct virtio_dev *vdev; struct virtio_dev *vdev;
int rc; int rc;
vdev = virtio_user_dev_init(base_name, path, num_queues, queue_size, vdev = calloc(1, sizeof(*vdev));
if (vdev == NULL) {
SPDK_ERRLOG("calloc failed for virtio device %s: %s\n", base_name, path);
return -ENOMEM;
}
rc = virtio_user_dev_init(vdev, base_name, path, num_queues, queue_size,
SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED); SPDK_VIRTIO_SCSI_QUEUE_NUM_FIXED);
if (!vdev) { if (rc != 0) {
SPDK_ERRLOG("Failed to create virito device %s: %s\n", base_name, path); SPDK_ERRLOG("Failed to create virito device %s: %s\n", base_name, path);
free(vdev);
return -EINVAL; return -EINVAL;
} }

View File

@ -315,31 +315,23 @@ virtio_negotiate_features(struct virtio_dev *dev, uint64_t req_features)
return 0; return 0;
} }
struct virtio_dev * int
virtio_dev_construct(const struct virtio_dev_ops *ops, void *ctx) virtio_dev_construct(struct virtio_dev *vdev, const struct virtio_dev_ops *ops, void *ctx)
{ {
struct virtio_dev *vdev;
vdev = calloc(1, sizeof(*vdev));
if (vdev == NULL) {
SPDK_ERRLOG("virtio device calloc failed\n");
return NULL;
}
pthread_mutex_init(&vdev->mutex, NULL); pthread_mutex_init(&vdev->mutex, NULL);
vdev->backend_ops = ops; vdev->backend_ops = ops;
vdev->ctx = ctx; vdev->ctx = ctx;
return vdev; return 0;
} }
int int
virtio_dev_init(struct virtio_dev *dev, uint64_t req_features) virtio_dev_restart(struct virtio_dev *dev, uint64_t req_features)
{ {
int ret; int ret;
/* Reset the device although not necessary at startup */ /* Reset the device although not necessary at startup */
virtio_dev_reset(dev); virtio_dev_stop(dev);
/* Tell the host we've noticed this device. */ /* Tell the host we've noticed this device. */
virtio_dev_set_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); virtio_dev_set_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
@ -358,12 +350,11 @@ virtio_dev_init(struct virtio_dev *dev, uint64_t req_features)
} }
void void
virtio_dev_free(struct virtio_dev *dev) virtio_dev_destruct(struct virtio_dev *dev)
{ {
virtio_free_queues(dev); virtio_free_queues(dev);
virtio_dev_backend_ops(dev)->free_vdev(dev); virtio_dev_backend_ops(dev)->destruct_dev(dev);
pthread_mutex_destroy(&dev->mutex); pthread_mutex_destroy(&dev->mutex);
free(dev);
} }
static void static void
@ -688,7 +679,7 @@ virtio_dev_write_dev_config(struct virtio_dev *dev, size_t offset,
} }
void void
virtio_dev_reset(struct virtio_dev *dev) virtio_dev_stop(struct virtio_dev *dev)
{ {
virtio_dev_backend_ops(dev)->set_status(dev, VIRTIO_CONFIG_S_RESET); virtio_dev_backend_ops(dev)->set_status(dev, VIRTIO_CONFIG_S_RESET);
/* flush status write */ /* flush status write */

View File

@ -112,8 +112,8 @@ struct virtio_dev_ops {
*/ */
int (*set_features)(struct virtio_dev *vdev, uint64_t features); int (*set_features)(struct virtio_dev *vdev, uint64_t features);
/** Deinit and free virtio device */ /** Destruct virtio device */
void (*free_vdev)(struct virtio_dev *vdev); void (*destruct_dev)(struct virtio_dev *vdev);
uint16_t (*get_queue_num)(struct virtio_dev *hw, uint16_t queue_id); uint16_t (*get_queue_num)(struct virtio_dev *hw, uint16_t queue_id);
int (*setup_queue)(struct virtio_dev *hw, struct virtqueue *vq); int (*setup_queue)(struct virtio_dev *hw, struct virtqueue *vq);
@ -210,22 +210,42 @@ uint16_t virtio_recv_pkts(struct virtqueue *vq, struct virtio_req **reqs,
int virtio_xmit_pkt(struct virtqueue *vq, struct virtio_req *req); int virtio_xmit_pkt(struct virtqueue *vq, struct virtio_req *req);
/** /**
* Construct virtio device. This will set vdev->id field. * Construct a virtio device. The device will be in stopped state by default.
* The device has to be freed with \c virtio_dev_free. * Before doing any I/O, it has to be manually started via \c virtio_dev_restart.
* *
* \param vdev memory for virtio device, must be zeroed
* \param ops backend callbacks * \param ops backend callbacks
* \param ctx argument for the backend callbacks * \param ctx argument for the backend callbacks
*/ */
struct virtio_dev *virtio_dev_construct(const struct virtio_dev_ops *ops, void *ctx); int virtio_dev_construct(struct virtio_dev *vdev, const struct virtio_dev_ops *ops,
void *ctx);
/** /**
* Reset and reinit a virtio device. This will also renegotiate feature flags. * Notify the host to start processing this virtio device. This is
* a blocking call that won't return until the host has started.
* This call will also allocate virtqueues and renegotiate feature flags.
* *
* \param vdev vhost device * \param vdev virtio device
* \param req_features features this driver supports * \param req_features features this driver supports
*/ */
int virtio_dev_init(struct virtio_dev *vdev, uint64_t req_features); int virtio_dev_restart(struct virtio_dev *vdev, uint64_t req_features);
void virtio_dev_free(struct virtio_dev *dev);
/**
* Stop the host from processing the device. This is a blocking call
* that won't return until all outstanding I/O has been processed on
* the host (virtio device) side.
*
* \param vdev virtio device
*/
void virtio_dev_stop(struct virtio_dev *vdev);
/**
* Destruct a virtio device. Note that it must be in the stopped state.
* The virtio_dev should be manually freed afterwards.
*
* \param vdev virtio device
*/
void virtio_dev_destruct(struct virtio_dev *vdev);
/** /**
* Bind a virtqueue with given index to the current thread; * Bind a virtqueue with given index to the current thread;
@ -286,14 +306,6 @@ bool virtio_dev_queue_is_acquired(struct virtio_dev *vdev, uint16_t index);
*/ */
void virtio_dev_release_queue(struct virtio_dev *vdev, uint16_t index); void virtio_dev_release_queue(struct virtio_dev *vdev, uint16_t index);
/**
* Reset given virtio device. This will leave the device in unusable state.
* To reuse the device, call \c virtio_dev_init.
*
* \param vdev virtio device
*/
void virtio_dev_reset(struct virtio_dev *vdev);
/** /**
* Get Virtio status flags. * Get Virtio status flags.
* *
@ -303,9 +315,9 @@ uint8_t virtio_dev_get_status(struct virtio_dev *vdev);
/** /**
* Set Virtio status flag. The flags have to be set in very specific order * Set Virtio status flag. The flags have to be set in very specific order
* defined the VirtIO 1.0 spec section 3.1.1. To unset the flags, call * defined the VIRTIO 1.0 spec section 3.1.1. To unset the flags, stop the
* \c virtio_dev_reset or set \c VIRTIO_CONFIG_S_RESET flag. There is * device or set \c VIRTIO_CONFIG_S_RESET status flag. There is no way to
* no way to unset particular flags. * unset only particular flags.
* *
* \param vdev virtio device * \param vdev virtio device
* \param flag flag to set * \param flag flag to set
@ -367,8 +379,10 @@ void virtio_dev_dump_json_config(struct virtio_dev *vdev, struct spdk_json_write
int virtio_enumerate_pci(void); int virtio_enumerate_pci(void);
/** /**
* Connect to a vhost-user device and create corresponding virtio_dev. * Connect to a vhost-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 name name of this virtio device
* \param path path to the Unix domain socket of the vhost-user device * \param path path to the Unix domain socket of the vhost-user device
* \param requested_queues maximum number of request queues that this * \param requested_queues maximum number of request queues that this
@ -379,8 +393,8 @@ int virtio_enumerate_pci(void);
* additional event and control queues. * additional event and control queues.
* \return virtio device * \return virtio device
*/ */
struct virtio_dev *virtio_user_dev_init(const char *name, const char *path, int virtio_user_dev_init(struct virtio_dev *vdev, const char *name, const char *path,
uint16_t requested_queues, uint16_t requested_queues, uint32_t queue_size,
uint32_t queue_size, uint16_t fixed_queue_num); uint16_t fixed_queue_num);
#endif /* SPDK_VIRTIO_H */ #endif /* SPDK_VIRTIO_H */

View File

@ -198,7 +198,7 @@ modern_set_features(struct virtio_dev *dev, uint64_t features)
} }
static void static void
modern_free_vdev(struct virtio_dev *vdev) modern_destruct_dev(struct virtio_dev *vdev)
{ {
struct virtio_hw *hw = vdev->ctx; struct virtio_hw *hw = vdev->ctx;
@ -301,7 +301,7 @@ static const struct virtio_dev_ops modern_ops = {
.set_status = modern_set_status, .set_status = modern_set_status,
.get_features = modern_get_features, .get_features = modern_get_features,
.set_features = modern_set_features, .set_features = modern_set_features,
.free_vdev = modern_free_vdev, .destruct_dev = modern_destruct_dev,
.get_queue_num = modern_get_queue_num, .get_queue_num = modern_get_queue_num,
.setup_queue = modern_setup_queue, .setup_queue = modern_setup_queue,
.del_queue = modern_del_queue, .del_queue = modern_del_queue,
@ -470,8 +470,16 @@ pci_enum_virtio_probe_cb(void *ctx, struct spdk_pci_device *pci_dev)
return -1; return -1;
} }
vdev = virtio_dev_construct(&modern_ops, hw); vdev = calloc(1, sizeof(*vdev));
if (vdev == NULL) { if (vdev == NULL) {
SPDK_ERRLOG("calloc failed\n");
free_virtio_hw(hw);
return -1;
}
rc = virtio_dev_construct(vdev, &modern_ops, hw);
if (rc != 0) {
free(vdev);
free_virtio_hw(hw); free_virtio_hw(hw);
return -1; return -1;
} }
@ -486,7 +494,7 @@ pci_enum_virtio_probe_cb(void *ctx, struct spdk_pci_device *pci_dev)
return 0; return 0;
err: err:
virtio_dev_free(vdev); virtio_dev_destruct(vdev);
return -1; return -1;
} }

View File

@ -345,7 +345,7 @@ virtio_user_notify_queue(struct virtio_dev *vdev, struct virtqueue *vq)
} }
static void static void
virtio_user_free(struct virtio_dev *vdev) virtio_user_destroy(struct virtio_dev *vdev)
{ {
struct virtio_user_dev *dev = vdev->ctx; struct virtio_user_dev *dev = vdev->ctx;
@ -373,7 +373,7 @@ static const struct virtio_dev_ops virtio_user_ops = {
.set_status = virtio_user_set_status, .set_status = virtio_user_set_status,
.get_features = virtio_user_get_features, .get_features = virtio_user_get_features,
.set_features = virtio_user_set_features, .set_features = virtio_user_set_features,
.free_vdev = virtio_user_free, .destruct_dev = virtio_user_destroy,
.get_queue_num = virtio_user_get_queue_num, .get_queue_num = virtio_user_get_queue_num,
.setup_queue = virtio_user_setup_queue, .setup_queue = virtio_user_setup_queue,
.del_queue = virtio_user_del_queue, .del_queue = virtio_user_del_queue,
@ -381,34 +381,33 @@ static const struct virtio_dev_ops virtio_user_ops = {
.dump_json_config = virtio_user_dump_json_config, .dump_json_config = virtio_user_dump_json_config,
}; };
struct virtio_dev * int
virtio_user_dev_init(const char *name, const char *path, uint16_t requested_queues, virtio_user_dev_init(struct virtio_dev *vdev, const char *name, const char *path,
uint32_t queue_size, uint16_t requested_queues, uint32_t queue_size, uint16_t fixed_queue_num)
uint16_t fixed_queue_num)
{ {
struct virtio_dev *vdev;
struct virtio_user_dev *dev; struct virtio_user_dev *dev;
uint64_t max_queues; uint64_t max_queues;
char err_str[64]; char err_str[64];
int rc;
if (name == NULL) { if (name == NULL) {
SPDK_ERRLOG("No name gived for controller: %s\n", path); SPDK_ERRLOG("No name gived for controller: %s\n", path);
return NULL; return -1;
} else if (requested_queues == 0) { } else if (requested_queues == 0) {
SPDK_ERRLOG("Can't create controller with no queues: %s\n", path); SPDK_ERRLOG("Can't create controller with no queues: %s\n", path);
return NULL; return -1;
} }
dev = calloc(1, sizeof(*dev)); dev = calloc(1, sizeof(*dev));
if (dev == NULL) { if (dev == NULL) {
return NULL; return -1;
} }
vdev = virtio_dev_construct(&virtio_user_ops, dev); rc = virtio_dev_construct(vdev, &virtio_user_ops, dev);
if (vdev == NULL) { if (rc != 0) {
SPDK_ERRLOG("Failed to init device: %s\n", path); SPDK_ERRLOG("Failed to init device: %s\n", path);
free(dev); free(dev);
return NULL; return -1;
} }
vdev->is_hw = 0; vdev->is_hw = 0;
@ -447,9 +446,9 @@ virtio_user_dev_init(const char *name, const char *path, uint16_t requested_queu
} }
TAILQ_INSERT_TAIL(&g_virtio_driver.init_ctrlrs, vdev, tailq); TAILQ_INSERT_TAIL(&g_virtio_driver.init_ctrlrs, vdev, tailq);
return vdev; return 0;
err: err:
virtio_dev_free(vdev); virtio_dev_destruct(vdev);
return NULL; return -1;
} }