Commit 1eac3079 authored by Dariusz Stojaczyk's avatar Dariusz Stojaczyk Committed by Jim Harris
Browse files

rte_vhost: fix deadlock on rte_vhost_driver_unregister()



2 locks are executed in 2 places in opposite orders.
Consider the following scenario, threads A and B:
(A)
 * fdset_event_dispatch() start
   * pfdentry->busy = 1; (lock #1)
   * vhost_user_read_cb() start
     * vhost_destroy_device() start
(B)
 * rte_vhost_driver_unregister() start
   * pthread_mutex_lock(&vsocket->conn_mutex); (lock #2)
   * fdset_del()
     * endless loop, waiting for pfdentry->busy == 0 (lock #1)
(A)
     * vhost_destroy_device() end
     * pthread_mutex_lock(&vsocket->conn_mutex); (lock #2)
       (mutex already locked - deadlock at this point)

Thread B has locked vsocket->conn_mutex and is in while(1)
loop waiting for given fd to change it's busy flag to 0.
Thread A would have to finish vhost_user_read_cb() in order
to set busy flag back to 0, but that can't happen due to
the vsocket->conn_mutex lock.

This patch defers the fdset_del(), so that it's called outside of
vsocket->conn_mutex.

Change-Id: Ifb5d4699bdafe96a573444c11ad4eae3adc359f5
Signed-off-by: default avatarDariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-on: https://review.gerrithub.io/375910


Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarPawel Wodkowski <pawelx.wodkowski@intel.com>
Reviewed-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
parent 3d8dbc69
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -696,6 +696,8 @@ rte_vhost_driver_unregister(const char *path)
	int i;
	int count;
	struct vhost_user_connection *conn, *next;
	struct vhost_user_connection_list del_conn_list =
			TAILQ_HEAD_INITIALIZER(del_conn_list);

	pthread_mutex_lock(&vhost_user.mutex);

@@ -717,16 +719,20 @@ rte_vhost_driver_unregister(const char *path)
			     conn = next) {
				next = TAILQ_NEXT(conn, next);

				TAILQ_REMOVE(&vsocket->conn_list, conn, next);
				TAILQ_INSERT_TAIL(&del_conn_list, conn, next);
			}
			pthread_mutex_unlock(&vsocket->conn_mutex);

			TAILQ_FOREACH(conn, &del_conn_list, next) {
				fdset_del(&vhost_user.fdset, conn->connfd);
				RTE_LOG(INFO, VHOST_CONFIG,
					"free connfd = %d for device '%s'\n",
					conn->connfd, path);
				close(conn->connfd);
				vhost_destroy_device(conn->vid);
				TAILQ_REMOVE(&vsocket->conn_list, conn, next);
				free(conn);
			}
			pthread_mutex_unlock(&vsocket->conn_mutex);

			free(vsocket->path);
			free(vsocket);