virtiofsd: Kill threads when queues are stopped

Kill the threads we've started when the queues get stopped.

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
With improvements by:
Signed-off-by: Eryu Guan <eguan@linux.alibaba.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
This commit is contained in:
Dr. David Alan Gilbert 2018-11-23 18:19:31 +00:00
parent e8556f4909
commit 10477ac47f
1 changed files with 44 additions and 7 deletions

View File

@ -41,6 +41,7 @@ struct fv_QueueInfo {
/* Our queue index, corresponds to array position */ /* Our queue index, corresponds to array position */
int qidx; int qidx;
int kick_fd; int kick_fd;
int kill_fd; /* For killing the thread */
/* The element for the command currently being processed */ /* The element for the command currently being processed */
VuVirtqElement *qe; VuVirtqElement *qe;
@ -412,14 +413,17 @@ static void *fv_queue_thread(void *opaque)
fuse_log(FUSE_LOG_INFO, "%s: Start for queue %d kick_fd %d\n", __func__, fuse_log(FUSE_LOG_INFO, "%s: Start for queue %d kick_fd %d\n", __func__,
qi->qidx, qi->kick_fd); qi->qidx, qi->kick_fd);
while (1) { while (1) {
struct pollfd pf[1]; struct pollfd pf[2];
pf[0].fd = qi->kick_fd; pf[0].fd = qi->kick_fd;
pf[0].events = POLLIN; pf[0].events = POLLIN;
pf[0].revents = 0; pf[0].revents = 0;
pf[1].fd = qi->kill_fd;
pf[1].events = POLLIN;
pf[1].revents = 0;
fuse_log(FUSE_LOG_DEBUG, "%s: Waiting for Queue %d event\n", __func__, fuse_log(FUSE_LOG_DEBUG, "%s: Waiting for Queue %d event\n", __func__,
qi->qidx); qi->qidx);
int poll_res = ppoll(pf, 1, NULL, NULL); int poll_res = ppoll(pf, 2, NULL, NULL);
if (poll_res == -1) { if (poll_res == -1) {
if (errno == EINTR) { if (errno == EINTR) {
@ -430,12 +434,23 @@ static void *fv_queue_thread(void *opaque)
fuse_log(FUSE_LOG_ERR, "fv_queue_thread ppoll: %m\n"); fuse_log(FUSE_LOG_ERR, "fv_queue_thread ppoll: %m\n");
break; break;
} }
assert(poll_res == 1); assert(poll_res >= 1);
if (pf[0].revents & (POLLERR | POLLHUP | POLLNVAL)) { if (pf[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
fuse_log(FUSE_LOG_ERR, "%s: Unexpected poll revents %x Queue %d\n", fuse_log(FUSE_LOG_ERR, "%s: Unexpected poll revents %x Queue %d\n",
__func__, pf[0].revents, qi->qidx); __func__, pf[0].revents, qi->qidx);
break; break;
} }
if (pf[1].revents & (POLLERR | POLLHUP | POLLNVAL)) {
fuse_log(FUSE_LOG_ERR,
"%s: Unexpected poll revents %x Queue %d killfd\n",
__func__, pf[1].revents, qi->qidx);
break;
}
if (pf[1].revents) {
fuse_log(FUSE_LOG_INFO, "%s: kill event on queue %d - quitting\n",
__func__, qi->qidx);
break;
}
assert(pf[0].revents & POLLIN); assert(pf[0].revents & POLLIN);
fuse_log(FUSE_LOG_DEBUG, "%s: Got queue event on Queue %d\n", __func__, fuse_log(FUSE_LOG_DEBUG, "%s: Got queue event on Queue %d\n", __func__,
qi->qidx); qi->qidx);
@ -589,6 +604,28 @@ out:
return NULL; return NULL;
} }
static void fv_queue_cleanup_thread(struct fv_VuDev *vud, int qidx)
{
int ret;
struct fv_QueueInfo *ourqi;
assert(qidx < vud->nqueues);
ourqi = vud->qi[qidx];
/* Kill the thread */
if (eventfd_write(ourqi->kill_fd, 1)) {
fuse_log(FUSE_LOG_ERR, "Eventfd_write for queue %d: %s\n",
qidx, strerror(errno));
}
ret = pthread_join(ourqi->thread, NULL);
if (ret) {
fuse_log(FUSE_LOG_ERR, "%s: Failed to join thread idx %d err %d\n",
__func__, qidx, ret);
}
close(ourqi->kill_fd);
ourqi->kick_fd = -1;
}
/* Callback from libvhost-user on start or stop of a queue */ /* Callback from libvhost-user on start or stop of a queue */
static void fv_queue_set_started(VuDev *dev, int qidx, bool started) static void fv_queue_set_started(VuDev *dev, int qidx, bool started)
{ {
@ -633,16 +670,16 @@ static void fv_queue_set_started(VuDev *dev, int qidx, bool started)
} }
ourqi = vud->qi[qidx]; ourqi = vud->qi[qidx];
ourqi->kick_fd = dev->vq[qidx].kick_fd; ourqi->kick_fd = dev->vq[qidx].kick_fd;
ourqi->kill_fd = eventfd(0, EFD_CLOEXEC | EFD_SEMAPHORE);
assert(ourqi->kill_fd != -1);
if (pthread_create(&ourqi->thread, NULL, fv_queue_thread, ourqi)) { if (pthread_create(&ourqi->thread, NULL, fv_queue_thread, ourqi)) {
fuse_log(FUSE_LOG_ERR, "%s: Failed to create thread for queue %d\n", fuse_log(FUSE_LOG_ERR, "%s: Failed to create thread for queue %d\n",
__func__, qidx); __func__, qidx);
assert(0); assert(0);
} }
} else { } else {
/* TODO: Kill the thread */ fv_queue_cleanup_thread(vud, qidx);
assert(qidx < vud->nqueues);
ourqi = vud->qi[qidx];
ourqi->kick_fd = -1;
} }
} }