Right now within virtio_fs_requests_done_work(), virtqueue is protected by both fsvq->lock and fpq->lock for processing both virtqueue and fpq->processing_list, however, it is fine for them to be protected separately.
Also since %req has been removed from fpq->processing_list, no one except request_wait_answer() is looking at this %req and request_wait_answer() waits only on FINISH flag, it's OK to remove fpq->lock after %req is dropped from the list. Signed-off-by: Liu Bo <[email protected]> --- fs/fuse/virtio_fs.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index 9b3f2e9..d88bb6c 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c @@ -347,21 +347,22 @@ static void virtio_fs_requests_done_work(struct work_struct *work) /* Collect completed requests off the virtqueue */ spin_lock(&fsvq->lock); - /* grab fpq->lock as req is on fpq->processing list */ - spin_lock(&fpq->lock); do { unsigned len; virtqueue_disable_cb(vq); while ((req = virtqueue_get_buf(vq, &len)) != NULL) { + /* grab fpq->lock as req is on fpq->processing list */ + spin_lock(&fpq->lock); + /* If !connected, req is freed by fuse_abort_conn. */ - if (fpq->connected) { + if (fpq->connected) list_move_tail(&req->list, &reqs); - } + + spin_unlock(&fpq->lock); } } while (!virtqueue_enable_cb(vq) && likely(!virtqueue_is_broken(vq))); - spin_unlock(&fpq->lock); spin_unlock(&fsvq->lock); /* End requests */ @@ -373,10 +374,8 @@ static void virtio_fs_requests_done_work(struct work_struct *work) /* TODO zeroing? */ - spin_lock(&fpq->lock); clear_bit(FR_SENT, &req->flags); list_del_init(&req->list); - spin_unlock(&fpq->lock); fuse_request_end(fc, req); } -- 1.8.3.1
