[dpdk-dev] [PATCH v2] vhost: fix driver unregister for client mode
Ilya Maximets
i.maximets at samsung.com
Thu Jul 21 14:57:00 CEST 2016
I've fixed leak of file descriptors in 'vhost_user_remove_reconnect()'
and sent v3.
On 21.07.2016 11:31, Ilya Maximets wrote:
> Currently while calling of 'rte_vhost_driver_unregister()' connection
> to QEMU will not be closed. This leads to inability to register driver
> again and reconnect to same virtual machine.
>
> This scenario is reproducible with OVS. While executing of the following
> command vhost port will be re-created (will be executed
> 'rte_vhost_driver_register()' followed by 'rte_vhost_driver_unregister()')
> network will be broken and QEMU possibly will crash:
>
> ovs-vsctl set Interface vhost1 ofport_request=15
>
> Fix this by closing all established connections on driver unregister and
> removing of pending connections from reconnection list.
>
> Fixes: 64ab701c3d1e ("vhost: add vhost-user client mode")
>
> Acked-by: Yuanhan Liu <yuanhan.liu at linux.intel.com>
> Signed-off-by: Ilya Maximets <i.maximets at samsung.com>
> ---
> lib/librte_vhost/vhost_user/fd_man.c | 15 ++++++--
> lib/librte_vhost/vhost_user/fd_man.h | 2 +-
> lib/librte_vhost/vhost_user/vhost-net-user.c | 56 ++++++++++++++++++++++++----
> 3 files changed, 62 insertions(+), 11 deletions(-)
>
> diff --git a/lib/librte_vhost/vhost_user/fd_man.c b/lib/librte_vhost/vhost_user/fd_man.c
> index c691339..2d3eeb7 100644
> --- a/lib/librte_vhost/vhost_user/fd_man.c
> +++ b/lib/librte_vhost/vhost_user/fd_man.c
> @@ -132,8 +132,10 @@ fdset_init(struct fdset *pfdset)
> if (pfdset == NULL)
> return;
>
> - for (i = 0; i < MAX_FDS; i++)
> + for (i = 0; i < MAX_FDS; i++) {
> pfdset->fd[i].fd = -1;
> + pfdset->fd[i].dat = NULL;
> + }
> pfdset->num = 0;
> }
>
> @@ -166,14 +168,16 @@ fdset_add(struct fdset *pfdset, int fd, fd_cb rcb, fd_cb wcb, void *dat)
>
> /**
> * Unregister the fd from the fdset.
> + * Returns context of a given fd or NULL.
> */
> -void
> +void *
> fdset_del(struct fdset *pfdset, int fd)
> {
> int i;
> + void *dat = NULL;
>
> if (pfdset == NULL || fd == -1)
> - return;
> + return NULL;
>
> do {
> pthread_mutex_lock(&pfdset->fd_mutex);
> @@ -181,13 +185,17 @@ fdset_del(struct fdset *pfdset, int fd)
> i = fdset_find_fd(pfdset, fd);
> if (i != -1 && pfdset->fd[i].busy == 0) {
> /* busy indicates r/wcb is executing! */
> + dat = pfdset->fd[i].dat;
> pfdset->fd[i].fd = -1;
> pfdset->fd[i].rcb = pfdset->fd[i].wcb = NULL;
> + pfdset->fd[i].dat = NULL;
> pfdset->num--;
> i = -1;
> }
> pthread_mutex_unlock(&pfdset->fd_mutex);
> } while (i != -1);
> +
> + return dat;
> }
>
> /**
> @@ -203,6 +211,7 @@ fdset_del_slot(struct fdset *pfdset, int index)
>
> pfdset->fd[index].fd = -1;
> pfdset->fd[index].rcb = pfdset->fd[index].wcb = NULL;
> + pfdset->fd[index].dat = NULL;
> pfdset->num--;
>
> pthread_mutex_unlock(&pfdset->fd_mutex);
> diff --git a/lib/librte_vhost/vhost_user/fd_man.h b/lib/librte_vhost/vhost_user/fd_man.h
> index 74ecde2..bd66ed1 100644
> --- a/lib/librte_vhost/vhost_user/fd_man.h
> +++ b/lib/librte_vhost/vhost_user/fd_man.h
> @@ -60,7 +60,7 @@ void fdset_init(struct fdset *pfdset);
> int fdset_add(struct fdset *pfdset, int fd,
> fd_cb rcb, fd_cb wcb, void *dat);
>
> -void fdset_del(struct fdset *pfdset, int fd);
> +void *fdset_del(struct fdset *pfdset, int fd);
>
> void fdset_event_dispatch(struct fdset *pfdset);
>
> diff --git a/lib/librte_vhost/vhost_user/vhost-net-user.c b/lib/librte_vhost/vhost_user/vhost-net-user.c
> index f0ea3a2..8c6a096 100644
> --- a/lib/librte_vhost/vhost_user/vhost-net-user.c
> +++ b/lib/librte_vhost/vhost_user/vhost-net-user.c
> @@ -60,6 +60,7 @@
> struct vhost_user_socket {
> char *path;
> int listenfd;
> + int connfd;
> bool is_server;
> bool reconnect;
> };
> @@ -277,11 +278,13 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket)
>
> RTE_LOG(INFO, VHOST_CONFIG, "new device, handle is %d\n", vid);
>
> + vsocket->connfd = fd;
> conn->vsocket = vsocket;
> conn->vid = vid;
> ret = fdset_add(&vhost_user.fdset, fd, vhost_user_msg_handler,
> NULL, conn);
> if (ret < 0) {
> + vsocket->connfd = -1;
> free(conn);
> close(fd);
> RTE_LOG(ERR, VHOST_CONFIG,
> @@ -329,6 +332,7 @@ vhost_user_msg_handler(int connfd, void *dat, int *remove)
> RTE_LOG(ERR, VHOST_CONFIG,
> "vhost read incorrect message\n");
>
> + vsocket->connfd = -1;
> close(connfd);
> *remove = 1;
> free(conn);
> @@ -635,6 +639,7 @@ rte_vhost_driver_register(const char *path, uint64_t flags)
> goto out;
> memset(vsocket, 0, sizeof(struct vhost_user_socket));
> vsocket->path = strdup(path);
> + vsocket->connfd = -1;
>
> if ((flags & RTE_VHOST_USER_CLIENT) != 0) {
> vsocket->reconnect = !(flags & RTE_VHOST_USER_NO_RECONNECT);
> @@ -664,6 +669,29 @@ out:
> return ret;
> }
>
> +static bool
> +vhost_user_remove_reconnect(struct vhost_user_socket *vsocket)
> +{
> + int found = false;
> + struct vhost_user_reconnect *reconn, *next;
> +
> + pthread_mutex_lock(&reconn_list.mutex);
> +
> + for (reconn = TAILQ_FIRST(&reconn_list.head);
> + reconn != NULL; reconn = next) {
> + next = TAILQ_NEXT(reconn, next);
> +
> + if (reconn->vsocket == vsocket) {
> + TAILQ_REMOVE(&reconn_list.head, reconn, next);
> + free(reconn);
> + found = true;
> + break;
> + }
> + }
> + pthread_mutex_unlock(&reconn_list.mutex);
> + return found;
> +}
> +
> /**
> * Unregister the specified vhost socket
> */
> @@ -672,20 +700,34 @@ rte_vhost_driver_unregister(const char *path)
> {
> int i;
> int count;
> + struct vhost_user_connection *conn;
>
> pthread_mutex_lock(&vhost_user.mutex);
>
> for (i = 0; i < vhost_user.vsocket_cnt; i++) {
> - if (!strcmp(vhost_user.vsockets[i]->path, path)) {
> - if (vhost_user.vsockets[i]->is_server) {
> - fdset_del(&vhost_user.fdset,
> - vhost_user.vsockets[i]->listenfd);
> - close(vhost_user.vsockets[i]->listenfd);
> + struct vhost_user_socket *vsocket = vhost_user.vsockets[i];
> +
> + if (!strcmp(vsocket->path, path)) {
> + if (vsocket->is_server) {
> + fdset_del(&vhost_user.fdset, vsocket->listenfd);
> + close(vsocket->listenfd);
> unlink(path);
> + } else if (vsocket->reconnect) {
> + vhost_user_remove_reconnect(vsocket);
> + }
> +
> + conn = fdset_del(&vhost_user.fdset, vsocket->connfd);
> + if (conn) {
> + RTE_LOG(INFO, VHOST_CONFIG,
> + "free connfd = %d for device '%s'\n",
> + vsocket->connfd, path);
> + close(vsocket->connfd);
> + vhost_destroy_device(conn->vid);
> + free(conn);
> }
>
> - free(vhost_user.vsockets[i]->path);
> - free(vhost_user.vsockets[i]);
> + free(vsocket->path);
> + free(vsocket);
>
> count = --vhost_user.vsocket_cnt;
> vhost_user.vsockets[i] = vhost_user.vsockets[count];
>
More information about the dev
mailing list