virtiofs: Use completions while waiting for queue to be drained

While we wait for queue to finish draining, use completions instead of
usleep_range(). This is better way of waiting for event.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
Vivek Goyal 2019-10-30 11:07:19 -04:00 committed by Miklos Szeredi
parent 1efcf39eb6
commit 724c15a43e

View File

@ -35,6 +35,7 @@ struct virtio_fs_vq {
struct fuse_dev *fud;
bool connected;
long in_flight;
struct completion in_flight_zero; /* No inflight requests */
char name[24];
} ____cacheline_aligned_in_smp;
@ -85,6 +86,8 @@ static inline void dec_in_flight_req(struct virtio_fs_vq *fsvq)
{
WARN_ON(fsvq->in_flight <= 0);
fsvq->in_flight--;
if (!fsvq->in_flight)
complete(&fsvq->in_flight_zero);
}
static void release_virtio_fs_obj(struct kref *ref)
@ -115,22 +118,23 @@ static void virtio_fs_drain_queue(struct virtio_fs_vq *fsvq)
WARN_ON(fsvq->in_flight < 0);
/* Wait for in flight requests to finish.*/
while (1) {
spin_lock(&fsvq->lock);
if (!fsvq->in_flight) {
spin_unlock(&fsvq->lock);
break;
}
spin_lock(&fsvq->lock);
if (fsvq->in_flight) {
/* We are holding virtio_fs_mutex. There should not be any
* waiters waiting for completion.
*/
reinit_completion(&fsvq->in_flight_zero);
spin_unlock(&fsvq->lock);
wait_for_completion(&fsvq->in_flight_zero);
} else {
spin_unlock(&fsvq->lock);
/* TODO use completion instead of timeout */
usleep_range(1000, 2000);
}
flush_work(&fsvq->done_work);
flush_delayed_work(&fsvq->dispatch_work);
}
static void virtio_fs_drain_all_queues(struct virtio_fs *fs)
static void virtio_fs_drain_all_queues_locked(struct virtio_fs *fs)
{
struct virtio_fs_vq *fsvq;
int i;
@ -141,6 +145,19 @@ static void virtio_fs_drain_all_queues(struct virtio_fs *fs)
}
}
static void virtio_fs_drain_all_queues(struct virtio_fs *fs)
{
/* Provides mutual exclusion between ->remove and ->kill_sb
* paths. We don't want both of these draining queue at the
* same time. Current completion logic reinits completion
* and that means there should not be any other thread
* doing reinit or waiting for completion already.
*/
mutex_lock(&virtio_fs_mutex);
virtio_fs_drain_all_queues_locked(fs);
mutex_unlock(&virtio_fs_mutex);
}
static void virtio_fs_start_all_queues(struct virtio_fs *fs)
{
struct virtio_fs_vq *fsvq;
@ -581,6 +598,7 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev,
INIT_LIST_HEAD(&fs->vqs[VQ_HIPRIO].end_reqs);
INIT_DELAYED_WORK(&fs->vqs[VQ_HIPRIO].dispatch_work,
virtio_fs_hiprio_dispatch_work);
init_completion(&fs->vqs[VQ_HIPRIO].in_flight_zero);
spin_lock_init(&fs->vqs[VQ_HIPRIO].lock);
/* Initialize the requests virtqueues */
@ -591,6 +609,7 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev,
virtio_fs_request_dispatch_work);
INIT_LIST_HEAD(&fs->vqs[i].queued_reqs);
INIT_LIST_HEAD(&fs->vqs[i].end_reqs);
init_completion(&fs->vqs[i].in_flight_zero);
snprintf(fs->vqs[i].name, sizeof(fs->vqs[i].name),
"requests.%u", i - VQ_REQUEST);
callbacks[i] = virtio_fs_vq_done;
@ -684,7 +703,7 @@ static void virtio_fs_remove(struct virtio_device *vdev)
/* This device is going away. No one should get new reference */
list_del_init(&fs->list);
virtio_fs_stop_all_queues(fs);
virtio_fs_drain_all_queues(fs);
virtio_fs_drain_all_queues_locked(fs);
vdev->config->reset(vdev);
virtio_fs_cleanup_vqs(vdev, fs);