vhost: fix unregistering in client mode
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: 64ab701c3d
("vhost: add vhost-user client mode")
Signed-off-by: Ilya Maximets <i.maximets@samsung.com>
Acked-by: Yuanhan Liu <yuanhan.liu@linux.intel.com>
This commit is contained in:
parent
81b5d22f1d
commit
164fd39678
@ -132,8 +132,10 @@ fdset_init(struct fdset *pfdset)
|
|||||||
if (pfdset == NULL)
|
if (pfdset == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < MAX_FDS; i++)
|
for (i = 0; i < MAX_FDS; i++) {
|
||||||
pfdset->fd[i].fd = -1;
|
pfdset->fd[i].fd = -1;
|
||||||
|
pfdset->fd[i].dat = NULL;
|
||||||
|
}
|
||||||
pfdset->num = 0;
|
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.
|
* Unregister the fd from the fdset.
|
||||||
|
* Returns context of a given fd or NULL.
|
||||||
*/
|
*/
|
||||||
void
|
void *
|
||||||
fdset_del(struct fdset *pfdset, int fd)
|
fdset_del(struct fdset *pfdset, int fd)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
void *dat = NULL;
|
||||||
|
|
||||||
if (pfdset == NULL || fd == -1)
|
if (pfdset == NULL || fd == -1)
|
||||||
return;
|
return NULL;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
pthread_mutex_lock(&pfdset->fd_mutex);
|
pthread_mutex_lock(&pfdset->fd_mutex);
|
||||||
@ -181,13 +185,17 @@ fdset_del(struct fdset *pfdset, int fd)
|
|||||||
i = fdset_find_fd(pfdset, fd);
|
i = fdset_find_fd(pfdset, fd);
|
||||||
if (i != -1 && pfdset->fd[i].busy == 0) {
|
if (i != -1 && pfdset->fd[i].busy == 0) {
|
||||||
/* busy indicates r/wcb is executing! */
|
/* busy indicates r/wcb is executing! */
|
||||||
|
dat = pfdset->fd[i].dat;
|
||||||
pfdset->fd[i].fd = -1;
|
pfdset->fd[i].fd = -1;
|
||||||
pfdset->fd[i].rcb = pfdset->fd[i].wcb = NULL;
|
pfdset->fd[i].rcb = pfdset->fd[i].wcb = NULL;
|
||||||
|
pfdset->fd[i].dat = NULL;
|
||||||
pfdset->num--;
|
pfdset->num--;
|
||||||
i = -1;
|
i = -1;
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&pfdset->fd_mutex);
|
pthread_mutex_unlock(&pfdset->fd_mutex);
|
||||||
} while (i != -1);
|
} 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].fd = -1;
|
||||||
pfdset->fd[index].rcb = pfdset->fd[index].wcb = NULL;
|
pfdset->fd[index].rcb = pfdset->fd[index].wcb = NULL;
|
||||||
|
pfdset->fd[index].dat = NULL;
|
||||||
pfdset->num--;
|
pfdset->num--;
|
||||||
|
|
||||||
pthread_mutex_unlock(&pfdset->fd_mutex);
|
pthread_mutex_unlock(&pfdset->fd_mutex);
|
||||||
|
@ -60,7 +60,7 @@ void fdset_init(struct fdset *pfdset);
|
|||||||
int fdset_add(struct fdset *pfdset, int fd,
|
int fdset_add(struct fdset *pfdset, int fd,
|
||||||
fd_cb rcb, fd_cb wcb, void *dat);
|
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);
|
void fdset_event_dispatch(struct fdset *pfdset);
|
||||||
|
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
struct vhost_user_socket {
|
struct vhost_user_socket {
|
||||||
char *path;
|
char *path;
|
||||||
int listenfd;
|
int listenfd;
|
||||||
|
int connfd;
|
||||||
bool is_server;
|
bool is_server;
|
||||||
bool reconnect;
|
bool reconnect;
|
||||||
};
|
};
|
||||||
@ -278,11 +279,13 @@ vhost_user_add_connection(int fd, struct vhost_user_socket *vsocket)
|
|||||||
|
|
||||||
RTE_LOG(INFO, VHOST_CONFIG, "new device, handle is %d\n", vid);
|
RTE_LOG(INFO, VHOST_CONFIG, "new device, handle is %d\n", vid);
|
||||||
|
|
||||||
|
vsocket->connfd = fd;
|
||||||
conn->vsocket = vsocket;
|
conn->vsocket = vsocket;
|
||||||
conn->vid = vid;
|
conn->vid = vid;
|
||||||
ret = fdset_add(&vhost_user.fdset, fd, vhost_user_msg_handler,
|
ret = fdset_add(&vhost_user.fdset, fd, vhost_user_msg_handler,
|
||||||
NULL, conn);
|
NULL, conn);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
vsocket->connfd = -1;
|
||||||
free(conn);
|
free(conn);
|
||||||
close(fd);
|
close(fd);
|
||||||
RTE_LOG(ERR, VHOST_CONFIG,
|
RTE_LOG(ERR, VHOST_CONFIG,
|
||||||
@ -330,6 +333,7 @@ vhost_user_msg_handler(int connfd, void *dat, int *remove)
|
|||||||
RTE_LOG(ERR, VHOST_CONFIG,
|
RTE_LOG(ERR, VHOST_CONFIG,
|
||||||
"vhost read incorrect message\n");
|
"vhost read incorrect message\n");
|
||||||
|
|
||||||
|
vsocket->connfd = -1;
|
||||||
close(connfd);
|
close(connfd);
|
||||||
*remove = 1;
|
*remove = 1;
|
||||||
free(conn);
|
free(conn);
|
||||||
@ -679,6 +683,7 @@ rte_vhost_driver_register(const char *path, uint64_t flags)
|
|||||||
goto out;
|
goto out;
|
||||||
memset(vsocket, 0, sizeof(struct vhost_user_socket));
|
memset(vsocket, 0, sizeof(struct vhost_user_socket));
|
||||||
vsocket->path = strdup(path);
|
vsocket->path = strdup(path);
|
||||||
|
vsocket->connfd = -1;
|
||||||
|
|
||||||
if ((flags & RTE_VHOST_USER_CLIENT) != 0) {
|
if ((flags & RTE_VHOST_USER_CLIENT) != 0) {
|
||||||
vsocket->reconnect = !(flags & RTE_VHOST_USER_NO_RECONNECT);
|
vsocket->reconnect = !(flags & RTE_VHOST_USER_NO_RECONNECT);
|
||||||
@ -708,6 +713,30 @@ rte_vhost_driver_register(const char *path, uint64_t flags)
|
|||||||
return ret;
|
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);
|
||||||
|
close(reconn->fd);
|
||||||
|
free(reconn);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&reconn_list.mutex);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregister the specified vhost socket
|
* Unregister the specified vhost socket
|
||||||
*/
|
*/
|
||||||
@ -716,20 +745,34 @@ rte_vhost_driver_unregister(const char *path)
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int count;
|
int count;
|
||||||
|
struct vhost_user_connection *conn;
|
||||||
|
|
||||||
pthread_mutex_lock(&vhost_user.mutex);
|
pthread_mutex_lock(&vhost_user.mutex);
|
||||||
|
|
||||||
for (i = 0; i < vhost_user.vsocket_cnt; i++) {
|
for (i = 0; i < vhost_user.vsocket_cnt; i++) {
|
||||||
if (!strcmp(vhost_user.vsockets[i]->path, path)) {
|
struct vhost_user_socket *vsocket = vhost_user.vsockets[i];
|
||||||
if (vhost_user.vsockets[i]->is_server) {
|
|
||||||
fdset_del(&vhost_user.fdset,
|
if (!strcmp(vsocket->path, path)) {
|
||||||
vhost_user.vsockets[i]->listenfd);
|
if (vsocket->is_server) {
|
||||||
close(vhost_user.vsockets[i]->listenfd);
|
fdset_del(&vhost_user.fdset, vsocket->listenfd);
|
||||||
|
close(vsocket->listenfd);
|
||||||
unlink(path);
|
unlink(path);
|
||||||
|
} else if (vsocket->reconnect) {
|
||||||
|
vhost_user_remove_reconnect(vsocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(vhost_user.vsockets[i]->path);
|
conn = fdset_del(&vhost_user.fdset, vsocket->connfd);
|
||||||
free(vhost_user.vsockets[i]);
|
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(vsocket->path);
|
||||||
|
free(vsocket);
|
||||||
|
|
||||||
count = --vhost_user.vsocket_cnt;
|
count = --vhost_user.vsocket_cnt;
|
||||||
vhost_user.vsockets[i] = vhost_user.vsockets[count];
|
vhost_user.vsockets[i] = vhost_user.vsockets[count];
|
||||||
|
Loading…
Reference in New Issue
Block a user