There is a 1:1 relationship between struct virtio_net and struct vhost_user_connection. They share the same lifetime. struct virtio_net is the per-device state that is part of the vhost.h API. struct vhost_user_connection is the AF_UNIX-specific per-device state and is private to trans_af_unix.c. It will be necessary to go between these two structs.
This patch embeds struct virtio_net within struct vhost_user_connection so that AF_UNIX transport code can convert a struct virtio_net pointer into a struct vhost_user_connection pointer. There is now just a single malloc/free for both of these structs together. Signed-off-by: Nikos Dragazis <ndraga...@arrikto.com> Signed-off-by: Stefan Hajnoczi <stefa...@redhat.com> --- lib/librte_vhost/trans_af_unix.c | 60 +++++++++++++++------------------------- lib/librte_vhost/vhost.c | 12 ++++---- lib/librte_vhost/vhost.h | 11 +++++++- 3 files changed, 40 insertions(+), 43 deletions(-) diff --git a/lib/librte_vhost/trans_af_unix.c b/lib/librte_vhost/trans_af_unix.c index 865d862..7e119b4 100644 --- a/lib/librte_vhost/trans_af_unix.c +++ b/lib/librte_vhost/trans_af_unix.c @@ -26,9 +26,9 @@ static struct fdset af_unix_fdset = { TAILQ_HEAD(vhost_user_connection_list, vhost_user_connection); struct vhost_user_connection { + struct virtio_net device; /* must be the first field! */ struct vhost_user_socket *vsocket; int connfd; - int vid; TAILQ_ENTRY(vhost_user_connection) next; }; @@ -153,7 +153,7 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket) { struct af_unix_socket *af_vsocket = container_of(vsocket, struct af_unix_socket, socket); - int vid; + struct virtio_net *dev; size_t size; struct vhost_user_connection *conn; int ret; @@ -161,42 +161,37 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket) if (vsocket == NULL) return; - conn = malloc(sizeof(*conn)); - if (conn == NULL) { - close(fd); + dev = vhost_new_device(vsocket->trans_ops); + if (!dev) { return; } - vid = vhost_new_device(vsocket->trans_ops); - if (vid == -1) { - goto err; - } + conn = container_of(dev, struct vhost_user_connection, device); + conn->connfd = fd; + conn->vsocket = vsocket; size = strnlen(vsocket->path, PATH_MAX); - vhost_set_ifname(vid, vsocket->path, size); + vhost_set_ifname(dev->vid, vsocket->path, size); - vhost_set_builtin_virtio_net(vid, vsocket->use_builtin_virtio_net); + vhost_set_builtin_virtio_net(dev->vid, vsocket->use_builtin_virtio_net); - vhost_attach_vdpa_device(vid, vsocket->vdpa_dev_id); + vhost_attach_vdpa_device(dev->vid, vsocket->vdpa_dev_id); if (vsocket->dequeue_zero_copy) - vhost_enable_dequeue_zero_copy(vid); + vhost_enable_dequeue_zero_copy(dev->vid); - RTE_LOG(INFO, VHOST_CONFIG, "new device, handle is %d\n", vid); + RTE_LOG(INFO, VHOST_CONFIG, "new device, handle is %d\n", dev->vid); if (vsocket->notify_ops->new_connection) { - ret = vsocket->notify_ops->new_connection(vid); + ret = vsocket->notify_ops->new_connection(dev->vid); if (ret < 0) { RTE_LOG(ERR, VHOST_CONFIG, "failed to add vhost user connection with fd %d\n", fd); - goto err_cleanup; + goto err; } } - conn->connfd = fd; - conn->vsocket = vsocket; - conn->vid = vid; ret = fdset_add(&af_unix_fdset, fd, vhost_user_read_cb, NULL, conn); if (ret < 0) { @@ -205,9 +200,9 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket) fd); if (vsocket->notify_ops->destroy_connection) - vsocket->notify_ops->destroy_connection(conn->vid); + vsocket->notify_ops->destroy_connection(dev->vid); - goto err_cleanup; + goto err; } pthread_mutex_lock(&af_vsocket->conn_mutex); @@ -217,11 +212,9 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket) fdset_pipe_notify(&af_unix_fdset); return; -err_cleanup: - vhost_destroy_device(vid); err: - free(conn); - close(fd); + close(conn->connfd); + vhost_destroy_device(dev->vid); } /* call back when there is new vhost-user connection from client */ @@ -247,26 +240,19 @@ vhost_user_read_cb(int connfd, void *dat, int *remove) container_of(vsocket, struct af_unix_socket, socket); int ret; - ret = vhost_user_msg_handler(conn->vid, connfd); + ret = vhost_user_msg_handler(conn->device.vid, connfd); if (ret < 0) { - struct virtio_net *dev = get_device(conn->vid); - close(connfd); *remove = 1; - if (dev) - vhost_destroy_device_notify(dev); - if (vsocket->notify_ops->destroy_connection) - vsocket->notify_ops->destroy_connection(conn->vid); - - vhost_destroy_device(conn->vid); + vsocket->notify_ops->destroy_connection(conn->device.vid); pthread_mutex_lock(&af_vsocket->conn_mutex); TAILQ_REMOVE(&af_vsocket->conn_list, conn, next); pthread_mutex_unlock(&af_vsocket->conn_mutex); - free(conn); + vhost_destroy_device(conn->device.vid); if (vsocket->reconnect) { create_unix_socket(vsocket); @@ -594,9 +580,8 @@ af_unix_socket_cleanup(struct vhost_user_socket *vsocket) "free connfd = %d for device '%s'\n", conn->connfd, vsocket->path); close(conn->connfd); - vhost_destroy_device(conn->vid); TAILQ_REMOVE(&af_vsocket->conn_list, conn, next); - free(conn); + vhost_destroy_device(conn->device.vid); } pthread_mutex_unlock(&af_vsocket->conn_mutex); @@ -648,6 +633,7 @@ af_unix_vring_call(struct virtio_net *dev __rte_unused, const struct vhost_transport_ops af_unix_trans_ops = { .socket_size = sizeof(struct af_unix_socket), + .device_size = sizeof(struct vhost_user_connection), .socket_init = af_unix_socket_init, .socket_cleanup = af_unix_socket_cleanup, .socket_start = af_unix_socket_start, diff --git a/lib/librte_vhost/vhost.c b/lib/librte_vhost/vhost.c index a72edf3..0fdc54f 100644 --- a/lib/librte_vhost/vhost.c +++ b/lib/librte_vhost/vhost.c @@ -7,6 +7,7 @@ #include <stddef.h> #include <stdint.h> #include <stdlib.h> +#include <assert.h> #ifdef RTE_LIBRTE_VHOST_NUMA #include <numa.h> #include <numaif.h> @@ -479,7 +480,7 @@ reset_device(struct virtio_net *dev) * Invoked when there is a new vhost-user connection established (when * there is a new virtio device being attached). */ -int +struct virtio_net * vhost_new_device(const struct vhost_transport_ops *trans_ops) { struct virtio_net *dev; @@ -493,14 +494,15 @@ vhost_new_device(const struct vhost_transport_ops *trans_ops) if (i == MAX_VHOST_DEVICE) { RTE_LOG(ERR, VHOST_CONFIG, "Failed to find a free slot for new device.\n"); - return -1; + return NULL; } - dev = rte_zmalloc(NULL, sizeof(struct virtio_net), 0); + assert(trans_ops->device_size >= sizeof(struct virtio_net)); + dev = rte_zmalloc(NULL, trans_ops->device_size, 0); if (dev == NULL) { RTE_LOG(ERR, VHOST_CONFIG, "Failed to allocate memory for new dev.\n"); - return -1; + return NULL; } vhost_devices[i] = dev; @@ -512,7 +514,7 @@ vhost_new_device(const struct vhost_transport_ops *trans_ops) dev->postcopy_ufd = -1; rte_spinlock_init(&dev->slave_req_lock); - return i; + return dev; } void diff --git a/lib/librte_vhost/vhost.h b/lib/librte_vhost/vhost.h index 0831b27..b9e4df1 100644 --- a/lib/librte_vhost/vhost.h +++ b/lib/librte_vhost/vhost.h @@ -298,6 +298,9 @@ struct vhost_transport_ops { /** Size of struct vhost_user_socket-derived per-socket state */ size_t socket_size; + /** Size of struct virtio_net-derived per-device state */ + size_t device_size; + /** * Initialize a vhost-user socket that is being created by * rte_vhost_driver_register(). This function checks that the flags @@ -356,6 +359,11 @@ extern const struct vhost_transport_ops af_unix_trans_ops; /** * Device structure contains all configuration information relating * to the device. + * + * Transport-specific per-device state can be kept by embedding this struct at + * the beginning of a transport-specific struct. Set + * vhost_transport_ops->device_size to the size of the transport-specific + * struct. */ struct virtio_net { /* Frontend (QEMU) memory and memory region information */ @@ -568,7 +576,8 @@ get_device(int vid) return dev; } -int vhost_new_device(const struct vhost_transport_ops *trans_ops); +struct virtio_net * +vhost_new_device(const struct vhost_transport_ops *trans_ops); void cleanup_device(struct virtio_net *dev, int destroy); void reset_device(struct virtio_net *dev); void vhost_destroy_device(int); -- 2.7.4