diff options
-rw-r--r-- | fs/fuse/virtio_fs.c | 61 |
1 files changed, 52 insertions, 9 deletions
diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index 3ea613d5e34f..2de8fc0d6a24 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c | |||
@@ -55,6 +55,9 @@ struct virtio_fs_forget { | |||
55 | struct list_head list; | 55 | struct list_head list; |
56 | }; | 56 | }; |
57 | 57 | ||
58 | static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, | ||
59 | struct fuse_req *req, bool in_flight); | ||
60 | |||
58 | static inline struct virtio_fs_vq *vq_to_fsvq(struct virtqueue *vq) | 61 | static inline struct virtio_fs_vq *vq_to_fsvq(struct virtqueue *vq) |
59 | { | 62 | { |
60 | struct virtio_fs *fs = vq->vdev->priv; | 63 | struct virtio_fs *fs = vq->vdev->priv; |
@@ -260,6 +263,7 @@ static void virtio_fs_request_dispatch_work(struct work_struct *work) | |||
260 | struct virtio_fs_vq *fsvq = container_of(work, struct virtio_fs_vq, | 263 | struct virtio_fs_vq *fsvq = container_of(work, struct virtio_fs_vq, |
261 | dispatch_work.work); | 264 | dispatch_work.work); |
262 | struct fuse_conn *fc = fsvq->fud->fc; | 265 | struct fuse_conn *fc = fsvq->fud->fc; |
266 | int ret; | ||
263 | 267 | ||
264 | pr_debug("virtio-fs: worker %s called.\n", __func__); | 268 | pr_debug("virtio-fs: worker %s called.\n", __func__); |
265 | while (1) { | 269 | while (1) { |
@@ -268,13 +272,45 @@ static void virtio_fs_request_dispatch_work(struct work_struct *work) | |||
268 | list); | 272 | list); |
269 | if (!req) { | 273 | if (!req) { |
270 | spin_unlock(&fsvq->lock); | 274 | spin_unlock(&fsvq->lock); |
271 | return; | 275 | break; |
272 | } | 276 | } |
273 | 277 | ||
274 | list_del_init(&req->list); | 278 | list_del_init(&req->list); |
275 | spin_unlock(&fsvq->lock); | 279 | spin_unlock(&fsvq->lock); |
276 | fuse_request_end(fc, req); | 280 | fuse_request_end(fc, req); |
277 | } | 281 | } |
282 | |||
283 | /* Dispatch pending requests */ | ||
284 | while (1) { | ||
285 | spin_lock(&fsvq->lock); | ||
286 | req = list_first_entry_or_null(&fsvq->queued_reqs, | ||
287 | struct fuse_req, list); | ||
288 | if (!req) { | ||
289 | spin_unlock(&fsvq->lock); | ||
290 | return; | ||
291 | } | ||
292 | list_del_init(&req->list); | ||
293 | spin_unlock(&fsvq->lock); | ||
294 | |||
295 | ret = virtio_fs_enqueue_req(fsvq, req, true); | ||
296 | if (ret < 0) { | ||
297 | if (ret == -ENOMEM || ret == -ENOSPC) { | ||
298 | spin_lock(&fsvq->lock); | ||
299 | list_add_tail(&req->list, &fsvq->queued_reqs); | ||
300 | schedule_delayed_work(&fsvq->dispatch_work, | ||
301 | msecs_to_jiffies(1)); | ||
302 | spin_unlock(&fsvq->lock); | ||
303 | return; | ||
304 | } | ||
305 | req->out.h.error = ret; | ||
306 | spin_lock(&fsvq->lock); | ||
307 | dec_in_flight_req(fsvq); | ||
308 | spin_unlock(&fsvq->lock); | ||
309 | pr_err("virtio-fs: virtio_fs_enqueue_req() failed %d\n", | ||
310 | ret); | ||
311 | fuse_request_end(fc, req); | ||
312 | } | ||
313 | } | ||
278 | } | 314 | } |
279 | 315 | ||
280 | static void virtio_fs_hiprio_dispatch_work(struct work_struct *work) | 316 | static void virtio_fs_hiprio_dispatch_work(struct work_struct *work) |
@@ -837,7 +873,7 @@ static unsigned int sg_init_fuse_args(struct scatterlist *sg, | |||
837 | 873 | ||
838 | /* Add a request to a virtqueue and kick the device */ | 874 | /* Add a request to a virtqueue and kick the device */ |
839 | static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, | 875 | static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, |
840 | struct fuse_req *req) | 876 | struct fuse_req *req, bool in_flight) |
841 | { | 877 | { |
842 | /* requests need at least 4 elements */ | 878 | /* requests need at least 4 elements */ |
843 | struct scatterlist *stack_sgs[6]; | 879 | struct scatterlist *stack_sgs[6]; |
@@ -917,7 +953,8 @@ static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, | |||
917 | /* matches barrier in request_wait_answer() */ | 953 | /* matches barrier in request_wait_answer() */ |
918 | smp_mb__after_atomic(); | 954 | smp_mb__after_atomic(); |
919 | 955 | ||
920 | inc_in_flight_req(fsvq); | 956 | if (!in_flight) |
957 | inc_in_flight_req(fsvq); | ||
921 | notify = virtqueue_kick_prepare(vq); | 958 | notify = virtqueue_kick_prepare(vq); |
922 | 959 | ||
923 | spin_unlock(&fsvq->lock); | 960 | spin_unlock(&fsvq->lock); |
@@ -963,15 +1000,21 @@ __releases(fiq->lock) | |||
963 | req->in.h.nodeid, req->in.h.len, | 1000 | req->in.h.nodeid, req->in.h.len, |
964 | fuse_len_args(req->args->out_numargs, req->args->out_args)); | 1001 | fuse_len_args(req->args->out_numargs, req->args->out_args)); |
965 | 1002 | ||
966 | retry: | ||
967 | fsvq = &fs->vqs[queue_id]; | 1003 | fsvq = &fs->vqs[queue_id]; |
968 | ret = virtio_fs_enqueue_req(fsvq, req); | 1004 | ret = virtio_fs_enqueue_req(fsvq, req, false); |
969 | if (ret < 0) { | 1005 | if (ret < 0) { |
970 | if (ret == -ENOMEM || ret == -ENOSPC) { | 1006 | if (ret == -ENOMEM || ret == -ENOSPC) { |
971 | /* Virtqueue full. Retry submission */ | 1007 | /* |
972 | /* TODO use completion instead of timeout */ | 1008 | * Virtqueue full. Retry submission from worker |
973 | usleep_range(20, 30); | 1009 | * context as we might be holding fc->bg_lock. |
974 | goto retry; | 1010 | */ |
1011 | spin_lock(&fsvq->lock); | ||
1012 | list_add_tail(&req->list, &fsvq->queued_reqs); | ||
1013 | inc_in_flight_req(fsvq); | ||
1014 | schedule_delayed_work(&fsvq->dispatch_work, | ||
1015 | msecs_to_jiffies(1)); | ||
1016 | spin_unlock(&fsvq->lock); | ||
1017 | return; | ||
975 | } | 1018 | } |
976 | req->out.h.error = ret; | 1019 | req->out.h.error = ret; |
977 | pr_err("virtio-fs: virtio_fs_enqueue_req() failed %d\n", ret); | 1020 | pr_err("virtio-fs: virtio_fs_enqueue_req() failed %d\n", ret); |