virtiofs: Count pending forgets as in_flight forgets

If virtqueue is full, we put forget requests on a list and these forgets
are dispatched later using a worker. As of now we don't count these forgets
in fsvq->in_flight variable. This means when queue is being drained, we
have to have special logic to first drain these pending requests and then
wait for fsvq->in_flight to go to zero.

By counting pending forgets in fsvq->in_flight, we can get rid of special
logic and just wait for in_flight to go to zero. Worker thread will kick
and drain all the forgets anyway, leading in_flight to zero.

I also need similar logic for normal request queue in next patch where I am
about to defer request submission in the worker context if queue is full.

This simplifies the code a bit.

Also add two helper functions to inc/dec in_flight. Decrement in_flight
helper will later used to call completion when in_flight reaches zero.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
Vivek Goyal 2019-10-15 13:46:25 -04:00 committed by Miklos Szeredi
parent 5dbe190f34
commit c17ea00961
1 changed files with 20 additions and 24 deletions

View File

@ -67,6 +67,19 @@ static inline struct fuse_pqueue *vq_to_fpq(struct virtqueue *vq)
return &vq_to_fsvq(vq)->fud->pq; return &vq_to_fsvq(vq)->fud->pq;
} }
/* Should be called with fsvq->lock held. */
static inline void inc_in_flight_req(struct virtio_fs_vq *fsvq)
{
fsvq->in_flight++;
}
/* Should be called with fsvq->lock held. */
static inline void dec_in_flight_req(struct virtio_fs_vq *fsvq)
{
WARN_ON(fsvq->in_flight <= 0);
fsvq->in_flight--;
}
static void release_virtio_fs_obj(struct kref *ref) static void release_virtio_fs_obj(struct kref *ref)
{ {
struct virtio_fs *vfs = container_of(ref, struct virtio_fs, refcount); struct virtio_fs *vfs = container_of(ref, struct virtio_fs, refcount);
@ -110,22 +123,6 @@ static void virtio_fs_drain_queue(struct virtio_fs_vq *fsvq)
flush_delayed_work(&fsvq->dispatch_work); flush_delayed_work(&fsvq->dispatch_work);
} }
static inline void drain_hiprio_queued_reqs(struct virtio_fs_vq *fsvq)
{
struct virtio_fs_forget *forget;
spin_lock(&fsvq->lock);
while (1) {
forget = list_first_entry_or_null(&fsvq->queued_reqs,
struct virtio_fs_forget, list);
if (!forget)
break;
list_del(&forget->list);
kfree(forget);
}
spin_unlock(&fsvq->lock);
}
static void virtio_fs_drain_all_queues(struct virtio_fs *fs) static void virtio_fs_drain_all_queues(struct virtio_fs *fs)
{ {
struct virtio_fs_vq *fsvq; struct virtio_fs_vq *fsvq;
@ -133,9 +130,6 @@ static void virtio_fs_drain_all_queues(struct virtio_fs *fs)
for (i = 0; i < fs->nvqs; i++) { for (i = 0; i < fs->nvqs; i++) {
fsvq = &fs->vqs[i]; fsvq = &fs->vqs[i];
if (i == VQ_HIPRIO)
drain_hiprio_queued_reqs(fsvq);
virtio_fs_drain_queue(fsvq); virtio_fs_drain_queue(fsvq);
} }
} }
@ -254,7 +248,7 @@ static void virtio_fs_hiprio_done_work(struct work_struct *work)
while ((req = virtqueue_get_buf(vq, &len)) != NULL) { while ((req = virtqueue_get_buf(vq, &len)) != NULL) {
kfree(req); kfree(req);
fsvq->in_flight--; dec_in_flight_req(fsvq);
} }
} while (!virtqueue_enable_cb(vq) && likely(!virtqueue_is_broken(vq))); } while (!virtqueue_enable_cb(vq) && likely(!virtqueue_is_broken(vq)));
spin_unlock(&fsvq->lock); spin_unlock(&fsvq->lock);
@ -306,6 +300,7 @@ static void virtio_fs_hiprio_dispatch_work(struct work_struct *work)
list_del(&forget->list); list_del(&forget->list);
if (!fsvq->connected) { if (!fsvq->connected) {
dec_in_flight_req(fsvq);
spin_unlock(&fsvq->lock); spin_unlock(&fsvq->lock);
kfree(forget); kfree(forget);
continue; continue;
@ -327,13 +322,13 @@ static void virtio_fs_hiprio_dispatch_work(struct work_struct *work)
} else { } else {
pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n", pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n",
ret); ret);
dec_in_flight_req(fsvq);
kfree(forget); kfree(forget);
} }
spin_unlock(&fsvq->lock); spin_unlock(&fsvq->lock);
return; return;
} }
fsvq->in_flight++;
notify = virtqueue_kick_prepare(vq); notify = virtqueue_kick_prepare(vq);
spin_unlock(&fsvq->lock); spin_unlock(&fsvq->lock);
@ -472,7 +467,7 @@ static void virtio_fs_requests_done_work(struct work_struct *work)
fuse_request_end(fc, req); fuse_request_end(fc, req);
spin_lock(&fsvq->lock); spin_lock(&fsvq->lock);
fsvq->in_flight--; dec_in_flight_req(fsvq);
spin_unlock(&fsvq->lock); spin_unlock(&fsvq->lock);
} }
} }
@ -730,6 +725,7 @@ __releases(fiq->lock)
list_add_tail(&forget->list, &fsvq->queued_reqs); list_add_tail(&forget->list, &fsvq->queued_reqs);
schedule_delayed_work(&fsvq->dispatch_work, schedule_delayed_work(&fsvq->dispatch_work,
msecs_to_jiffies(1)); msecs_to_jiffies(1));
inc_in_flight_req(fsvq);
} else { } else {
pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n", pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n",
ret); ret);
@ -739,7 +735,7 @@ __releases(fiq->lock)
goto out; goto out;
} }
fsvq->in_flight++; inc_in_flight_req(fsvq);
notify = virtqueue_kick_prepare(vq); notify = virtqueue_kick_prepare(vq);
spin_unlock(&fsvq->lock); spin_unlock(&fsvq->lock);
@ -921,7 +917,7 @@ static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq,
/* matches barrier in request_wait_answer() */ /* matches barrier in request_wait_answer() */
smp_mb__after_atomic(); smp_mb__after_atomic();
fsvq->in_flight++; inc_in_flight_req(fsvq);
notify = virtqueue_kick_prepare(vq); notify = virtqueue_kick_prepare(vq);
spin_unlock(&fsvq->lock); spin_unlock(&fsvq->lock);