vhost: added new/destroy_device callback layer
new/destroy_device implementations in particular backends now take spdk_vhost_dev pointer. This patch is a first step towards fixing synchronization issues between RPC and vhost reactor. See the next patch which introduces generic vhost mutex in vhost.c. Change-Id: I448492330734726c21189f71ec7a9a8ed81c8195 Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com> Reviewed-on: https://review.gerrithub.io/372073 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Pawel Wodkowski <pawelx.wodkowski@intel.com> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
parent
551b0e9128
commit
10b1a4a9a3
@ -50,6 +50,14 @@ static char dev_dirname[PATH_MAX] = "";
|
||||
|
||||
#define MAX_VHOST_DEVICES 64
|
||||
|
||||
static int new_device(int vid);
|
||||
static void destroy_device(int vid);
|
||||
|
||||
const struct vhost_device_ops g_spdk_vhost_ops = {
|
||||
.new_device = new_device,
|
||||
.destroy_device = destroy_device,
|
||||
};
|
||||
|
||||
static struct spdk_vhost_dev *g_spdk_vhost_devices[MAX_VHOST_DEVICES];
|
||||
|
||||
void *spdk_vhost_gpa_to_vva(struct spdk_vhost_dev *vdev, uint64_t addr)
|
||||
@ -184,7 +192,7 @@ spdk_vhost_dev_has_feature(struct spdk_vhost_dev *vdev, unsigned feature_id)
|
||||
return vdev->negotiated_features & (1ULL << feature_id);
|
||||
}
|
||||
|
||||
struct spdk_vhost_dev *
|
||||
static struct spdk_vhost_dev *
|
||||
spdk_vhost_dev_find_by_vid(int vid)
|
||||
{
|
||||
unsigned i;
|
||||
@ -356,7 +364,7 @@ spdk_vhost_dev_construct(struct spdk_vhost_dev *vdev, const char *name, uint64_t
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (rte_vhost_driver_callback_register(path, &backend->ops) != 0) {
|
||||
if (rte_vhost_driver_callback_register(path, &g_spdk_vhost_ops) != 0) {
|
||||
rte_vhost_driver_unregister(path);
|
||||
SPDK_ERRLOG("Couldn't register callbacks for controller %s\n", name);
|
||||
return -EIO;
|
||||
@ -368,7 +376,7 @@ spdk_vhost_dev_construct(struct spdk_vhost_dev *vdev, const char *name, uint64_t
|
||||
vdev->lcore = -1;
|
||||
vdev->cpumask = cpumask;
|
||||
vdev->type = type;
|
||||
vdev->vhost_backend = backend;
|
||||
vdev->backend = backend;
|
||||
|
||||
g_spdk_vhost_devices[ctrlr_num] = vdev;
|
||||
|
||||
@ -519,64 +527,77 @@ spdk_vhost_allocate_reactor(uint64_t cpumask)
|
||||
return selected_core;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_vhost_dev_unload(struct spdk_vhost_dev *vdev)
|
||||
static void
|
||||
destroy_device(int vid)
|
||||
{
|
||||
struct spdk_vhost_dev *vdev;
|
||||
struct rte_vhost_vring *q;
|
||||
uint16_t i;
|
||||
|
||||
vdev = spdk_vhost_dev_find_by_vid(vid);
|
||||
if (vdev == NULL) {
|
||||
SPDK_ERRLOG("Couldn't find device with vid %d to stop.\n", vid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vdev->backend->destroy_device(vdev) != 0) {
|
||||
SPDK_ERRLOG("Couldn't stop device with vid %d.\n", vid);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < vdev->num_queues; i++) {
|
||||
q = &vdev->virtqueue[i];
|
||||
rte_vhost_set_vhost_vring_last_idx(vdev->vid, i, q->last_avail_idx, q->last_used_idx);
|
||||
}
|
||||
|
||||
free(vdev->mem);
|
||||
|
||||
spdk_vhost_free_reactor(vdev->lcore);
|
||||
vdev->lcore = -1;
|
||||
vdev->vid = -1;
|
||||
}
|
||||
|
||||
struct spdk_vhost_dev *
|
||||
spdk_vhost_dev_load(int vid)
|
||||
static int
|
||||
new_device(int vid)
|
||||
{
|
||||
struct spdk_vhost_dev *vdev;
|
||||
char ifname[PATH_MAX];
|
||||
int rc;
|
||||
|
||||
uint16_t num_queues = rte_vhost_get_vring_num(vid);
|
||||
uint16_t i;
|
||||
|
||||
if (rte_vhost_get_ifname(vid, ifname, PATH_MAX) < 0) {
|
||||
SPDK_ERRLOG("Couldn't get a valid ifname for device %d\n", vid);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
vdev = spdk_vhost_dev_find(ifname);
|
||||
if (vdev == NULL) {
|
||||
SPDK_ERRLOG("Controller %s not found.\n", ifname);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vdev->lcore != -1) {
|
||||
SPDK_ERRLOG("Controller %s already connected.\n", ifname);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (num_queues > SPDK_VHOST_MAX_VQUEUES) {
|
||||
SPDK_ERRLOG("vhost device %d: Too many queues (%"PRIu16"). Max %"PRIu16"\n", vid, num_queues,
|
||||
SPDK_VHOST_MAX_VQUEUES);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_queues; i++) {
|
||||
if (rte_vhost_get_vhost_vring(vid, i, &vdev->virtqueue[i])) {
|
||||
SPDK_ERRLOG("vhost device %d: Failed to get information of queue %"PRIu16"\n", vid, i);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Disable notifications. */
|
||||
if (rte_vhost_enable_guest_notification(vid, i, 0) != 0) {
|
||||
SPDK_ERRLOG("vhost device %d: Failed to disable guest notification on queue %"PRIu16"\n", vid, i);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
@ -586,17 +607,25 @@ spdk_vhost_dev_load(int vid)
|
||||
|
||||
if (rte_vhost_get_negotiated_features(vid, &vdev->negotiated_features) != 0) {
|
||||
SPDK_ERRLOG("vhost device %d: Failed to get negotiated driver features\n", vid);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rte_vhost_get_mem_table(vid, &vdev->mem) != 0) {
|
||||
SPDK_ERRLOG("vhost device %d: Failed to get guest memory table\n", vid);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
vdev->lcore = spdk_vhost_allocate_reactor(vdev->cpumask);
|
||||
rc = vdev->backend->new_device(vdev);
|
||||
if (rc != 0) {
|
||||
free(vdev->mem);
|
||||
spdk_vhost_free_reactor(vdev->lcore);
|
||||
vdev->lcore = -1;
|
||||
vdev->vid = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return vdev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
@ -733,8 +762,8 @@ spdk_vhost_timed_event_wait(struct spdk_vhost_timed_event *ev, const char *errms
|
||||
void
|
||||
spdk_vhost_dump_config_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w)
|
||||
{
|
||||
assert(vdev->vhost_backend->dump_config_json != NULL);
|
||||
vdev->vhost_backend->dump_config_json(vdev, w);
|
||||
assert(vdev->backend->dump_config_json != NULL);
|
||||
vdev->backend->dump_config_json(vdev, w);
|
||||
}
|
||||
|
||||
SPDK_LOG_REGISTER_TRACE_FLAG("vhost_ring", SPDK_TRACE_VHOST_RING)
|
||||
|
@ -518,48 +518,42 @@ alloc_task_pool(struct spdk_vhost_blk_dev *bvdev)
|
||||
*
|
||||
*/
|
||||
static int
|
||||
new_device(int vid)
|
||||
new_device(struct spdk_vhost_dev *vdev)
|
||||
{
|
||||
struct spdk_vhost_dev *vdev = spdk_vhost_dev_load(vid);
|
||||
struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vdev);
|
||||
struct spdk_vhost_blk_dev *bvdev;
|
||||
int rc = -1;
|
||||
|
||||
if (vdev == NULL) {
|
||||
bvdev = to_blk_dev(vdev);
|
||||
if (bvdev == NULL) {
|
||||
SPDK_ERRLOG("Trying to start non-blk controller as a blk one.\n");
|
||||
return -1;
|
||||
} else if (bvdev == NULL) {
|
||||
SPDK_ERRLOG("Trying to start non-blk controller as blk one.\n");
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = alloc_task_pool(bvdev);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("%s: failed to alloc task pool.", bvdev->vdev.name);
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
spdk_vhost_timed_event_send(bvdev->vdev.lcore, add_vdev_cb, bvdev, 1, "add blk vdev");
|
||||
|
||||
out:
|
||||
if (rc != 0) {
|
||||
spdk_vhost_dev_unload(&bvdev->vdev);
|
||||
}
|
||||
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_device(int vid)
|
||||
static int
|
||||
destroy_device(struct spdk_vhost_dev *vdev)
|
||||
{
|
||||
struct spdk_vhost_blk_dev *bvdev;
|
||||
struct spdk_vhost_dev *vdev;
|
||||
struct spdk_vhost_timed_event event = {0};
|
||||
uint32_t i;
|
||||
|
||||
vdev = spdk_vhost_dev_find_by_vid(vid);
|
||||
bvdev = to_blk_dev(vdev);
|
||||
if (bvdev == NULL) {
|
||||
SPDK_ERRLOG("Couldn't find device with vid %d to stop.\n", vid);
|
||||
abort();
|
||||
SPDK_ERRLOG("Trying to stop non-blk controller as a blk one.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
spdk_vhost_timed_event_init(&event, vdev->lcore, NULL, NULL, 1);
|
||||
@ -579,7 +573,7 @@ destroy_device(int vid)
|
||||
spdk_vhost_timed_event_send(vdev->lcore, remove_vdev_cb, bvdev, 1, "remove vdev");
|
||||
|
||||
free_task_pool(bvdev);
|
||||
spdk_vhost_dev_unload(vdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -616,11 +610,9 @@ static const struct spdk_vhost_dev_backend vhost_blk_device_backend = {
|
||||
.disabled_features = SPDK_VHOST_DISABLED_FEATURES | (1ULL << VIRTIO_BLK_F_GEOMETRY) |
|
||||
(1ULL << VIRTIO_BLK_F_RO) | (1ULL << VIRTIO_BLK_F_FLUSH) | (1ULL << VIRTIO_BLK_F_CONFIG_WCE) |
|
||||
(1ULL << VIRTIO_BLK_F_BARRIER) | (1ULL << VIRTIO_BLK_F_SCSI),
|
||||
.new_device = new_device,
|
||||
.destroy_device = destroy_device,
|
||||
.dump_config_json = spdk_vhost_blk_dump_config_json,
|
||||
.ops = {
|
||||
.new_device = new_device,
|
||||
.destroy_device = destroy_device,
|
||||
}
|
||||
};
|
||||
|
||||
int
|
||||
|
@ -85,8 +85,9 @@ enum spdk_vhost_dev_type {
|
||||
struct spdk_vhost_dev_backend {
|
||||
uint64_t virtio_features;
|
||||
uint64_t disabled_features;
|
||||
int (*new_device)(struct spdk_vhost_dev *);
|
||||
int (*destroy_device)(struct spdk_vhost_dev *);
|
||||
void (*dump_config_json)(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w);
|
||||
const struct vhost_device_ops ops;
|
||||
};
|
||||
|
||||
struct spdk_vhost_dev {
|
||||
@ -100,12 +101,12 @@ struct spdk_vhost_dev {
|
||||
uint64_t cpumask;
|
||||
|
||||
enum spdk_vhost_dev_type type;
|
||||
const struct spdk_vhost_dev_backend *backend;
|
||||
|
||||
uint16_t num_queues;
|
||||
uint64_t negotiated_features;
|
||||
struct rte_vhost_vring virtqueue[SPDK_VHOST_MAX_VQUEUES] __attribute((aligned(
|
||||
SPDK_CACHE_LINE_SIZE)));
|
||||
const struct spdk_vhost_dev_backend *vhost_backend;
|
||||
};
|
||||
|
||||
void spdk_vhost_dev_mem_register(struct spdk_vhost_dev *vdev);
|
||||
@ -129,15 +130,11 @@ bool spdk_vhost_vring_desc_is_wr(struct vring_desc *cur_desc);
|
||||
int spdk_vhost_vring_desc_to_iov(struct spdk_vhost_dev *vdev, struct iovec *iov,
|
||||
uint16_t *iov_index, const struct vring_desc *desc);
|
||||
bool spdk_vhost_dev_has_feature(struct spdk_vhost_dev *vdev, unsigned feature_id);
|
||||
struct spdk_vhost_dev *spdk_vhost_dev_find_by_vid(int vid);
|
||||
|
||||
int spdk_vhost_dev_construct(struct spdk_vhost_dev *vdev, const char *name, uint64_t cpumask,
|
||||
enum spdk_vhost_dev_type type, const struct spdk_vhost_dev_backend *backend);
|
||||
int spdk_vhost_dev_remove(struct spdk_vhost_dev *vdev);
|
||||
|
||||
struct spdk_vhost_dev *spdk_vhost_dev_load(int vid);
|
||||
void spdk_vhost_dev_unload(struct spdk_vhost_dev *dev);
|
||||
|
||||
typedef void (*spdk_vhost_timed_event_fn)(void *);
|
||||
|
||||
struct spdk_vhost_timed_event {
|
||||
|
@ -109,18 +109,16 @@ struct spdk_vhost_scsi_event {
|
||||
struct spdk_scsi_lun *lun;
|
||||
};
|
||||
|
||||
static int new_device(int vid);
|
||||
static void destroy_device(int vid);
|
||||
static int new_device(struct spdk_vhost_dev *);
|
||||
static int destroy_device(struct spdk_vhost_dev *);
|
||||
static void spdk_vhost_scsi_config_json(struct spdk_vhost_dev *vdev, struct spdk_json_write_ctx *w);
|
||||
|
||||
const struct spdk_vhost_dev_backend spdk_vhost_scsi_device_backend = {
|
||||
.virtio_features = SPDK_VHOST_SCSI_FEATURES,
|
||||
.disabled_features = SPDK_VHOST_SCSI_DISABLED_FEATURES,
|
||||
.new_device = new_device,
|
||||
.destroy_device = destroy_device,
|
||||
.dump_config_json = spdk_vhost_scsi_config_json,
|
||||
.ops = {
|
||||
.new_device = new_device,
|
||||
.destroy_device = destroy_device,
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
@ -1099,64 +1097,48 @@ alloc_task_pool(struct spdk_vhost_scsi_dev *svdev)
|
||||
* and then allocated to a specific data core.
|
||||
*/
|
||||
static int
|
||||
new_device(int vid)
|
||||
new_device(struct spdk_vhost_dev *vdev)
|
||||
{
|
||||
struct spdk_vhost_dev *vdev;
|
||||
struct spdk_vhost_scsi_dev *svdev = NULL;
|
||||
int rc = -1;
|
||||
|
||||
vdev = spdk_vhost_dev_load(vid);
|
||||
if (vdev == NULL) {
|
||||
SPDK_ERRLOG("Trying start a controller with unknown vid: %d.\n", vid);
|
||||
return -1;
|
||||
}
|
||||
struct spdk_vhost_scsi_dev *svdev;
|
||||
int rc;
|
||||
|
||||
svdev = to_scsi_dev(vdev);
|
||||
if (svdev == NULL) {
|
||||
SPDK_ERRLOG("Trying to start non-scsi controller as scsi one.\n");
|
||||
goto out;
|
||||
SPDK_ERRLOG("Trying to start non-scsi controller as a scsi one.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = alloc_task_pool(svdev);
|
||||
if (rc != 0) {
|
||||
SPDK_ERRLOG("%s: failed to alloc task pool.", vdev->name);
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
svdev->vhost_events = spdk_ring_create(SPDK_RING_TYPE_MP_SC, 16,
|
||||
spdk_env_get_socket_id(vdev->lcore));
|
||||
if (svdev->vhost_events == NULL) {
|
||||
SPDK_ERRLOG("%s: failed to alloc event pool.", vdev->name);
|
||||
goto out;
|
||||
return -1;
|
||||
}
|
||||
|
||||
spdk_vhost_timed_event_send(vdev->lcore, add_vdev_cb, svdev, 1, "add scsi vdev");
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
if (rc != 0) {
|
||||
spdk_vhost_dev_unload(&svdev->vdev);
|
||||
}
|
||||
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_device(int vid)
|
||||
static int
|
||||
destroy_device(struct spdk_vhost_dev *vdev)
|
||||
{
|
||||
struct spdk_vhost_scsi_dev *svdev;
|
||||
struct spdk_vhost_dev *vdev;
|
||||
void *ev;
|
||||
struct spdk_vhost_timed_event event = {0};
|
||||
uint32_t i;
|
||||
|
||||
vdev = spdk_vhost_dev_find_by_vid(vid);
|
||||
if (vdev == NULL) {
|
||||
rte_panic("Couldn't find device with vid %d to stop.\n", vid);
|
||||
}
|
||||
svdev = to_scsi_dev(vdev);
|
||||
assert(svdev);
|
||||
if (svdev == NULL) {
|
||||
SPDK_ERRLOG("Trying to stop non-scsi controller as a scsi one.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
spdk_vhost_timed_event_init(&event, vdev->lcore, NULL, NULL, 1);
|
||||
spdk_poller_unregister(&svdev->requestq_poller, event.spdk_event);
|
||||
@ -1187,7 +1169,7 @@ destroy_device(int vid)
|
||||
spdk_ring_free(svdev->vhost_events);
|
||||
|
||||
free_task_pool(svdev);
|
||||
spdk_vhost_dev_unload(vdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
|
Loading…
x
Reference in New Issue
Block a user