diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-10-29 12:43:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-10-29 12:43:33 -0400 |
commit | 23fdb198ae81f47a574296dab5167c5e136a02ba (patch) | |
tree | 138440550fdf4d9ef42e52f321e8eee83dba5f5c | |
parent | 8005803a2ca0af49f36f6e9329b5ecda3df27347 (diff) | |
parent | 091d1a7267726ba162b12ce9332d76cdae602789 (diff) |
Merge tag 'fuse-fixes-5.4-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse
Pull fuse fixes from Miklos Szeredi:
"Mostly virtiofs fixes, but also fixes a regression and couple of
longstanding data/metadata writeback ordering issues"
* tag 'fuse-fixes-5.4-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
fuse: redundant get_fuse_inode() calls in fuse_writepages_fill()
fuse: Add changelog entries for protocols 7.1 - 7.8
fuse: truncate pending writes on O_TRUNC
fuse: flush dirty data/metadata before non-truncate setattr
virtiofs: Remove set but not used variable 'fc'
virtiofs: Retry request submission from worker context
virtiofs: Count pending forgets as in_flight forgets
virtiofs: Set FR_SENT flag only after request has been sent
virtiofs: No need to check fpq->connected state
virtiofs: Do not end request in submission context
fuse: don't advise readdirplus for negative lookup
fuse: don't dereference req->args on finished request
virtio-fs: don't show mount options
virtio-fs: Change module name to virtiofs.ko
-rw-r--r-- | fs/fuse/Makefile | 3 | ||||
-rw-r--r-- | fs/fuse/dev.c | 4 | ||||
-rw-r--r-- | fs/fuse/dir.c | 16 | ||||
-rw-r--r-- | fs/fuse/file.c | 14 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 4 | ||||
-rw-r--r-- | fs/fuse/inode.c | 4 | ||||
-rw-r--r-- | fs/fuse/virtio_fs.c | 169 | ||||
-rw-r--r-- | include/uapi/linux/fuse.h | 37 |
8 files changed, 186 insertions, 65 deletions
diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile index 6419a2b3510d..3e8cebfb59b7 100644 --- a/fs/fuse/Makefile +++ b/fs/fuse/Makefile | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | obj-$(CONFIG_FUSE_FS) += fuse.o | 6 | obj-$(CONFIG_FUSE_FS) += fuse.o |
7 | obj-$(CONFIG_CUSE) += cuse.o | 7 | obj-$(CONFIG_CUSE) += cuse.o |
8 | obj-$(CONFIG_VIRTIO_FS) += virtio_fs.o | 8 | obj-$(CONFIG_VIRTIO_FS) += virtiofs.o |
9 | 9 | ||
10 | fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o | 10 | fuse-objs := dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o |
11 | virtiofs-y += virtio_fs.o | ||
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index dadd617d826c..ed1abc9e33cf 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -276,10 +276,12 @@ static void flush_bg_queue(struct fuse_conn *fc) | |||
276 | void fuse_request_end(struct fuse_conn *fc, struct fuse_req *req) | 276 | void fuse_request_end(struct fuse_conn *fc, struct fuse_req *req) |
277 | { | 277 | { |
278 | struct fuse_iqueue *fiq = &fc->iq; | 278 | struct fuse_iqueue *fiq = &fc->iq; |
279 | bool async = req->args->end; | 279 | bool async; |
280 | 280 | ||
281 | if (test_and_set_bit(FR_FINISHED, &req->flags)) | 281 | if (test_and_set_bit(FR_FINISHED, &req->flags)) |
282 | goto put_request; | 282 | goto put_request; |
283 | |||
284 | async = req->args->end; | ||
283 | /* | 285 | /* |
284 | * test_and_set_bit() implies smp_mb() between bit | 286 | * test_and_set_bit() implies smp_mb() between bit |
285 | * changing and below intr_entry check. Pairs with | 287 | * changing and below intr_entry check. Pairs with |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index d572c900bb0f..54d638f9ba1c 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -405,7 +405,8 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
405 | else | 405 | else |
406 | fuse_invalidate_entry_cache(entry); | 406 | fuse_invalidate_entry_cache(entry); |
407 | 407 | ||
408 | fuse_advise_use_readdirplus(dir); | 408 | if (inode) |
409 | fuse_advise_use_readdirplus(dir); | ||
409 | return newent; | 410 | return newent; |
410 | 411 | ||
411 | out_iput: | 412 | out_iput: |
@@ -1521,6 +1522,19 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, | |||
1521 | is_truncate = true; | 1522 | is_truncate = true; |
1522 | } | 1523 | } |
1523 | 1524 | ||
1525 | /* Flush dirty data/metadata before non-truncate SETATTR */ | ||
1526 | if (is_wb && S_ISREG(inode->i_mode) && | ||
1527 | attr->ia_valid & | ||
1528 | (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_MTIME_SET | | ||
1529 | ATTR_TIMES_SET)) { | ||
1530 | err = write_inode_now(inode, true); | ||
1531 | if (err) | ||
1532 | return err; | ||
1533 | |||
1534 | fuse_set_nowrite(inode); | ||
1535 | fuse_release_nowrite(inode); | ||
1536 | } | ||
1537 | |||
1524 | if (is_truncate) { | 1538 | if (is_truncate) { |
1525 | fuse_set_nowrite(inode); | 1539 | fuse_set_nowrite(inode); |
1526 | set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); | 1540 | set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state); |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 0f0225686aee..db48a5cf8620 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -217,7 +217,7 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir) | |||
217 | { | 217 | { |
218 | struct fuse_conn *fc = get_fuse_conn(inode); | 218 | struct fuse_conn *fc = get_fuse_conn(inode); |
219 | int err; | 219 | int err; |
220 | bool lock_inode = (file->f_flags & O_TRUNC) && | 220 | bool is_wb_truncate = (file->f_flags & O_TRUNC) && |
221 | fc->atomic_o_trunc && | 221 | fc->atomic_o_trunc && |
222 | fc->writeback_cache; | 222 | fc->writeback_cache; |
223 | 223 | ||
@@ -225,16 +225,20 @@ int fuse_open_common(struct inode *inode, struct file *file, bool isdir) | |||
225 | if (err) | 225 | if (err) |
226 | return err; | 226 | return err; |
227 | 227 | ||
228 | if (lock_inode) | 228 | if (is_wb_truncate) { |
229 | inode_lock(inode); | 229 | inode_lock(inode); |
230 | fuse_set_nowrite(inode); | ||
231 | } | ||
230 | 232 | ||
231 | err = fuse_do_open(fc, get_node_id(inode), file, isdir); | 233 | err = fuse_do_open(fc, get_node_id(inode), file, isdir); |
232 | 234 | ||
233 | if (!err) | 235 | if (!err) |
234 | fuse_finish_open(inode, file); | 236 | fuse_finish_open(inode, file); |
235 | 237 | ||
236 | if (lock_inode) | 238 | if (is_wb_truncate) { |
239 | fuse_release_nowrite(inode); | ||
237 | inode_unlock(inode); | 240 | inode_unlock(inode); |
241 | } | ||
238 | 242 | ||
239 | return err; | 243 | return err; |
240 | } | 244 | } |
@@ -1997,7 +2001,7 @@ static int fuse_writepages_fill(struct page *page, | |||
1997 | 2001 | ||
1998 | if (!data->ff) { | 2002 | if (!data->ff) { |
1999 | err = -EIO; | 2003 | err = -EIO; |
2000 | data->ff = fuse_write_file_get(fc, get_fuse_inode(inode)); | 2004 | data->ff = fuse_write_file_get(fc, fi); |
2001 | if (!data->ff) | 2005 | if (!data->ff) |
2002 | goto out_unlock; | 2006 | goto out_unlock; |
2003 | } | 2007 | } |
@@ -2042,8 +2046,6 @@ static int fuse_writepages_fill(struct page *page, | |||
2042 | * under writeback, so we can release the page lock. | 2046 | * under writeback, so we can release the page lock. |
2043 | */ | 2047 | */ |
2044 | if (data->wpa == NULL) { | 2048 | if (data->wpa == NULL) { |
2045 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
2046 | |||
2047 | err = -ENOMEM; | 2049 | err = -ENOMEM; |
2048 | wpa = fuse_writepage_args_alloc(); | 2050 | wpa = fuse_writepage_args_alloc(); |
2049 | if (!wpa) { | 2051 | if (!wpa) { |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 956aeaf961ae..d148188cfca4 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -479,6 +479,7 @@ struct fuse_fs_context { | |||
479 | bool destroy:1; | 479 | bool destroy:1; |
480 | bool no_control:1; | 480 | bool no_control:1; |
481 | bool no_force_umount:1; | 481 | bool no_force_umount:1; |
482 | bool no_mount_options:1; | ||
482 | unsigned int max_read; | 483 | unsigned int max_read; |
483 | unsigned int blksize; | 484 | unsigned int blksize; |
484 | const char *subtype; | 485 | const char *subtype; |
@@ -713,6 +714,9 @@ struct fuse_conn { | |||
713 | /** Do not allow MNT_FORCE umount */ | 714 | /** Do not allow MNT_FORCE umount */ |
714 | unsigned int no_force_umount:1; | 715 | unsigned int no_force_umount:1; |
715 | 716 | ||
717 | /* Do not show mount options */ | ||
718 | unsigned int no_mount_options:1; | ||
719 | |||
716 | /** The number of requests waiting for completion */ | 720 | /** The number of requests waiting for completion */ |
717 | atomic_t num_waiting; | 721 | atomic_t num_waiting; |
718 | 722 | ||
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index e040e2a2b621..16aec32f7f3d 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -558,6 +558,9 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root) | |||
558 | struct super_block *sb = root->d_sb; | 558 | struct super_block *sb = root->d_sb; |
559 | struct fuse_conn *fc = get_fuse_conn_super(sb); | 559 | struct fuse_conn *fc = get_fuse_conn_super(sb); |
560 | 560 | ||
561 | if (fc->no_mount_options) | ||
562 | return 0; | ||
563 | |||
561 | seq_printf(m, ",user_id=%u", from_kuid_munged(fc->user_ns, fc->user_id)); | 564 | seq_printf(m, ",user_id=%u", from_kuid_munged(fc->user_ns, fc->user_id)); |
562 | seq_printf(m, ",group_id=%u", from_kgid_munged(fc->user_ns, fc->group_id)); | 565 | seq_printf(m, ",group_id=%u", from_kgid_munged(fc->user_ns, fc->group_id)); |
563 | if (fc->default_permissions) | 566 | if (fc->default_permissions) |
@@ -1180,6 +1183,7 @@ int fuse_fill_super_common(struct super_block *sb, struct fuse_fs_context *ctx) | |||
1180 | fc->destroy = ctx->destroy; | 1183 | fc->destroy = ctx->destroy; |
1181 | fc->no_control = ctx->no_control; | 1184 | fc->no_control = ctx->no_control; |
1182 | fc->no_force_umount = ctx->no_force_umount; | 1185 | fc->no_force_umount = ctx->no_force_umount; |
1186 | fc->no_mount_options = ctx->no_mount_options; | ||
1183 | 1187 | ||
1184 | err = -ENOMEM; | 1188 | err = -ENOMEM; |
1185 | root = fuse_get_root_inode(sb, ctx->rootmode); | 1189 | root = fuse_get_root_inode(sb, ctx->rootmode); |
diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c index 6af3f131e468..a5c86048b96e 100644 --- a/fs/fuse/virtio_fs.c +++ b/fs/fuse/virtio_fs.c | |||
@@ -30,6 +30,7 @@ struct virtio_fs_vq { | |||
30 | struct virtqueue *vq; /* protected by ->lock */ | 30 | struct virtqueue *vq; /* protected by ->lock */ |
31 | struct work_struct done_work; | 31 | struct work_struct done_work; |
32 | struct list_head queued_reqs; | 32 | struct list_head queued_reqs; |
33 | struct list_head end_reqs; /* End these requests */ | ||
33 | struct delayed_work dispatch_work; | 34 | struct delayed_work dispatch_work; |
34 | struct fuse_dev *fud; | 35 | struct fuse_dev *fud; |
35 | bool connected; | 36 | bool connected; |
@@ -54,6 +55,9 @@ struct virtio_fs_forget { | |||
54 | struct list_head list; | 55 | struct list_head list; |
55 | }; | 56 | }; |
56 | 57 | ||
58 | static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, | ||
59 | struct fuse_req *req, bool in_flight); | ||
60 | |||
57 | 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) |
58 | { | 62 | { |
59 | struct virtio_fs *fs = vq->vdev->priv; | 63 | struct virtio_fs *fs = vq->vdev->priv; |
@@ -66,6 +70,19 @@ static inline struct fuse_pqueue *vq_to_fpq(struct virtqueue *vq) | |||
66 | return &vq_to_fsvq(vq)->fud->pq; | 70 | return &vq_to_fsvq(vq)->fud->pq; |
67 | } | 71 | } |
68 | 72 | ||
73 | /* Should be called with fsvq->lock held. */ | ||
74 | static inline void inc_in_flight_req(struct virtio_fs_vq *fsvq) | ||
75 | { | ||
76 | fsvq->in_flight++; | ||
77 | } | ||
78 | |||
79 | /* Should be called with fsvq->lock held. */ | ||
80 | static inline void dec_in_flight_req(struct virtio_fs_vq *fsvq) | ||
81 | { | ||
82 | WARN_ON(fsvq->in_flight <= 0); | ||
83 | fsvq->in_flight--; | ||
84 | } | ||
85 | |||
69 | static void release_virtio_fs_obj(struct kref *ref) | 86 | static void release_virtio_fs_obj(struct kref *ref) |
70 | { | 87 | { |
71 | struct virtio_fs *vfs = container_of(ref, struct virtio_fs, refcount); | 88 | struct virtio_fs *vfs = container_of(ref, struct virtio_fs, refcount); |
@@ -109,22 +126,6 @@ static void virtio_fs_drain_queue(struct virtio_fs_vq *fsvq) | |||
109 | flush_delayed_work(&fsvq->dispatch_work); | 126 | flush_delayed_work(&fsvq->dispatch_work); |
110 | } | 127 | } |
111 | 128 | ||
112 | static inline void drain_hiprio_queued_reqs(struct virtio_fs_vq *fsvq) | ||
113 | { | ||
114 | struct virtio_fs_forget *forget; | ||
115 | |||
116 | spin_lock(&fsvq->lock); | ||
117 | while (1) { | ||
118 | forget = list_first_entry_or_null(&fsvq->queued_reqs, | ||
119 | struct virtio_fs_forget, list); | ||
120 | if (!forget) | ||
121 | break; | ||
122 | list_del(&forget->list); | ||
123 | kfree(forget); | ||
124 | } | ||
125 | spin_unlock(&fsvq->lock); | ||
126 | } | ||
127 | |||
128 | static void virtio_fs_drain_all_queues(struct virtio_fs *fs) | 129 | static void virtio_fs_drain_all_queues(struct virtio_fs *fs) |
129 | { | 130 | { |
130 | struct virtio_fs_vq *fsvq; | 131 | struct virtio_fs_vq *fsvq; |
@@ -132,9 +133,6 @@ static void virtio_fs_drain_all_queues(struct virtio_fs *fs) | |||
132 | 133 | ||
133 | for (i = 0; i < fs->nvqs; i++) { | 134 | for (i = 0; i < fs->nvqs; i++) { |
134 | fsvq = &fs->vqs[i]; | 135 | fsvq = &fs->vqs[i]; |
135 | if (i == VQ_HIPRIO) | ||
136 | drain_hiprio_queued_reqs(fsvq); | ||
137 | |||
138 | virtio_fs_drain_queue(fsvq); | 136 | virtio_fs_drain_queue(fsvq); |
139 | } | 137 | } |
140 | } | 138 | } |
@@ -253,14 +251,66 @@ static void virtio_fs_hiprio_done_work(struct work_struct *work) | |||
253 | 251 | ||
254 | while ((req = virtqueue_get_buf(vq, &len)) != NULL) { | 252 | while ((req = virtqueue_get_buf(vq, &len)) != NULL) { |
255 | kfree(req); | 253 | kfree(req); |
256 | fsvq->in_flight--; | 254 | dec_in_flight_req(fsvq); |
257 | } | 255 | } |
258 | } while (!virtqueue_enable_cb(vq) && likely(!virtqueue_is_broken(vq))); | 256 | } while (!virtqueue_enable_cb(vq) && likely(!virtqueue_is_broken(vq))); |
259 | spin_unlock(&fsvq->lock); | 257 | spin_unlock(&fsvq->lock); |
260 | } | 258 | } |
261 | 259 | ||
262 | static void virtio_fs_dummy_dispatch_work(struct work_struct *work) | 260 | static void virtio_fs_request_dispatch_work(struct work_struct *work) |
263 | { | 261 | { |
262 | struct fuse_req *req; | ||
263 | struct virtio_fs_vq *fsvq = container_of(work, struct virtio_fs_vq, | ||
264 | dispatch_work.work); | ||
265 | struct fuse_conn *fc = fsvq->fud->fc; | ||
266 | int ret; | ||
267 | |||
268 | pr_debug("virtio-fs: worker %s called.\n", __func__); | ||
269 | while (1) { | ||
270 | spin_lock(&fsvq->lock); | ||
271 | req = list_first_entry_or_null(&fsvq->end_reqs, struct fuse_req, | ||
272 | list); | ||
273 | if (!req) { | ||
274 | spin_unlock(&fsvq->lock); | ||
275 | break; | ||
276 | } | ||
277 | |||
278 | list_del_init(&req->list); | ||
279 | spin_unlock(&fsvq->lock); | ||
280 | fuse_request_end(fc, req); | ||
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 | } | ||
264 | } | 314 | } |
265 | 315 | ||
266 | static void virtio_fs_hiprio_dispatch_work(struct work_struct *work) | 316 | static void virtio_fs_hiprio_dispatch_work(struct work_struct *work) |
@@ -286,6 +336,7 @@ static void virtio_fs_hiprio_dispatch_work(struct work_struct *work) | |||
286 | 336 | ||
287 | list_del(&forget->list); | 337 | list_del(&forget->list); |
288 | if (!fsvq->connected) { | 338 | if (!fsvq->connected) { |
339 | dec_in_flight_req(fsvq); | ||
289 | spin_unlock(&fsvq->lock); | 340 | spin_unlock(&fsvq->lock); |
290 | kfree(forget); | 341 | kfree(forget); |
291 | continue; | 342 | continue; |
@@ -307,13 +358,13 @@ static void virtio_fs_hiprio_dispatch_work(struct work_struct *work) | |||
307 | } else { | 358 | } else { |
308 | pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n", | 359 | pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n", |
309 | ret); | 360 | ret); |
361 | dec_in_flight_req(fsvq); | ||
310 | kfree(forget); | 362 | kfree(forget); |
311 | } | 363 | } |
312 | spin_unlock(&fsvq->lock); | 364 | spin_unlock(&fsvq->lock); |
313 | return; | 365 | return; |
314 | } | 366 | } |
315 | 367 | ||
316 | fsvq->in_flight++; | ||
317 | notify = virtqueue_kick_prepare(vq); | 368 | notify = virtqueue_kick_prepare(vq); |
318 | spin_unlock(&fsvq->lock); | 369 | spin_unlock(&fsvq->lock); |
319 | 370 | ||
@@ -452,7 +503,7 @@ static void virtio_fs_requests_done_work(struct work_struct *work) | |||
452 | 503 | ||
453 | fuse_request_end(fc, req); | 504 | fuse_request_end(fc, req); |
454 | spin_lock(&fsvq->lock); | 505 | spin_lock(&fsvq->lock); |
455 | fsvq->in_flight--; | 506 | dec_in_flight_req(fsvq); |
456 | spin_unlock(&fsvq->lock); | 507 | spin_unlock(&fsvq->lock); |
457 | } | 508 | } |
458 | } | 509 | } |
@@ -502,6 +553,7 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev, | |||
502 | names[VQ_HIPRIO] = fs->vqs[VQ_HIPRIO].name; | 553 | names[VQ_HIPRIO] = fs->vqs[VQ_HIPRIO].name; |
503 | INIT_WORK(&fs->vqs[VQ_HIPRIO].done_work, virtio_fs_hiprio_done_work); | 554 | INIT_WORK(&fs->vqs[VQ_HIPRIO].done_work, virtio_fs_hiprio_done_work); |
504 | INIT_LIST_HEAD(&fs->vqs[VQ_HIPRIO].queued_reqs); | 555 | INIT_LIST_HEAD(&fs->vqs[VQ_HIPRIO].queued_reqs); |
556 | INIT_LIST_HEAD(&fs->vqs[VQ_HIPRIO].end_reqs); | ||
505 | INIT_DELAYED_WORK(&fs->vqs[VQ_HIPRIO].dispatch_work, | 557 | INIT_DELAYED_WORK(&fs->vqs[VQ_HIPRIO].dispatch_work, |
506 | virtio_fs_hiprio_dispatch_work); | 558 | virtio_fs_hiprio_dispatch_work); |
507 | spin_lock_init(&fs->vqs[VQ_HIPRIO].lock); | 559 | spin_lock_init(&fs->vqs[VQ_HIPRIO].lock); |
@@ -511,8 +563,9 @@ static int virtio_fs_setup_vqs(struct virtio_device *vdev, | |||
511 | spin_lock_init(&fs->vqs[i].lock); | 563 | spin_lock_init(&fs->vqs[i].lock); |
512 | INIT_WORK(&fs->vqs[i].done_work, virtio_fs_requests_done_work); | 564 | INIT_WORK(&fs->vqs[i].done_work, virtio_fs_requests_done_work); |
513 | INIT_DELAYED_WORK(&fs->vqs[i].dispatch_work, | 565 | INIT_DELAYED_WORK(&fs->vqs[i].dispatch_work, |
514 | virtio_fs_dummy_dispatch_work); | 566 | virtio_fs_request_dispatch_work); |
515 | INIT_LIST_HEAD(&fs->vqs[i].queued_reqs); | 567 | INIT_LIST_HEAD(&fs->vqs[i].queued_reqs); |
568 | INIT_LIST_HEAD(&fs->vqs[i].end_reqs); | ||
516 | snprintf(fs->vqs[i].name, sizeof(fs->vqs[i].name), | 569 | snprintf(fs->vqs[i].name, sizeof(fs->vqs[i].name), |
517 | "requests.%u", i - VQ_REQUEST); | 570 | "requests.%u", i - VQ_REQUEST); |
518 | callbacks[i] = virtio_fs_vq_done; | 571 | callbacks[i] = virtio_fs_vq_done; |
@@ -708,6 +761,7 @@ __releases(fiq->lock) | |||
708 | list_add_tail(&forget->list, &fsvq->queued_reqs); | 761 | list_add_tail(&forget->list, &fsvq->queued_reqs); |
709 | schedule_delayed_work(&fsvq->dispatch_work, | 762 | schedule_delayed_work(&fsvq->dispatch_work, |
710 | msecs_to_jiffies(1)); | 763 | msecs_to_jiffies(1)); |
764 | inc_in_flight_req(fsvq); | ||
711 | } else { | 765 | } else { |
712 | pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n", | 766 | pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n", |
713 | ret); | 767 | ret); |
@@ -717,7 +771,7 @@ __releases(fiq->lock) | |||
717 | goto out; | 771 | goto out; |
718 | } | 772 | } |
719 | 773 | ||
720 | fsvq->in_flight++; | 774 | inc_in_flight_req(fsvq); |
721 | notify = virtqueue_kick_prepare(vq); | 775 | notify = virtqueue_kick_prepare(vq); |
722 | 776 | ||
723 | spin_unlock(&fsvq->lock); | 777 | spin_unlock(&fsvq->lock); |
@@ -819,7 +873,7 @@ static unsigned int sg_init_fuse_args(struct scatterlist *sg, | |||
819 | 873 | ||
820 | /* Add a request to a virtqueue and kick the device */ | 874 | /* Add a request to a virtqueue and kick the device */ |
821 | static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, | 875 | static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, |
822 | struct fuse_req *req) | 876 | struct fuse_req *req, bool in_flight) |
823 | { | 877 | { |
824 | /* requests need at least 4 elements */ | 878 | /* requests need at least 4 elements */ |
825 | struct scatterlist *stack_sgs[6]; | 879 | struct scatterlist *stack_sgs[6]; |
@@ -835,6 +889,7 @@ static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, | |||
835 | unsigned int i; | 889 | unsigned int i; |
836 | int ret; | 890 | int ret; |
837 | bool notify; | 891 | bool notify; |
892 | struct fuse_pqueue *fpq; | ||
838 | 893 | ||
839 | /* Does the sglist fit on the stack? */ | 894 | /* Does the sglist fit on the stack? */ |
840 | total_sgs = sg_count_fuse_req(req); | 895 | total_sgs = sg_count_fuse_req(req); |
@@ -889,7 +944,17 @@ static int virtio_fs_enqueue_req(struct virtio_fs_vq *fsvq, | |||
889 | goto out; | 944 | goto out; |
890 | } | 945 | } |
891 | 946 | ||
892 | fsvq->in_flight++; | 947 | /* Request successfully sent. */ |
948 | fpq = &fsvq->fud->pq; | ||
949 | spin_lock(&fpq->lock); | ||
950 | list_add_tail(&req->list, fpq->processing); | ||
951 | spin_unlock(&fpq->lock); | ||
952 | set_bit(FR_SENT, &req->flags); | ||
953 | /* matches barrier in request_wait_answer() */ | ||
954 | smp_mb__after_atomic(); | ||
955 | |||
956 | if (!in_flight) | ||
957 | inc_in_flight_req(fsvq); | ||
893 | notify = virtqueue_kick_prepare(vq); | 958 | notify = virtqueue_kick_prepare(vq); |
894 | 959 | ||
895 | spin_unlock(&fsvq->lock); | 960 | spin_unlock(&fsvq->lock); |
@@ -915,9 +980,8 @@ __releases(fiq->lock) | |||
915 | { | 980 | { |
916 | unsigned int queue_id = VQ_REQUEST; /* TODO multiqueue */ | 981 | unsigned int queue_id = VQ_REQUEST; /* TODO multiqueue */ |
917 | struct virtio_fs *fs; | 982 | struct virtio_fs *fs; |
918 | struct fuse_conn *fc; | ||
919 | struct fuse_req *req; | 983 | struct fuse_req *req; |
920 | struct fuse_pqueue *fpq; | 984 | struct virtio_fs_vq *fsvq; |
921 | int ret; | 985 | int ret; |
922 | 986 | ||
923 | WARN_ON(list_empty(&fiq->pending)); | 987 | WARN_ON(list_empty(&fiq->pending)); |
@@ -928,44 +992,36 @@ __releases(fiq->lock) | |||
928 | spin_unlock(&fiq->lock); | 992 | spin_unlock(&fiq->lock); |
929 | 993 | ||
930 | fs = fiq->priv; | 994 | fs = fiq->priv; |
931 | fc = fs->vqs[queue_id].fud->fc; | ||
932 | 995 | ||
933 | pr_debug("%s: opcode %u unique %#llx nodeid %#llx in.len %u out.len %u\n", | 996 | pr_debug("%s: opcode %u unique %#llx nodeid %#llx in.len %u out.len %u\n", |
934 | __func__, req->in.h.opcode, req->in.h.unique, | 997 | __func__, req->in.h.opcode, req->in.h.unique, |
935 | req->in.h.nodeid, req->in.h.len, | 998 | req->in.h.nodeid, req->in.h.len, |
936 | fuse_len_args(req->args->out_numargs, req->args->out_args)); | 999 | fuse_len_args(req->args->out_numargs, req->args->out_args)); |
937 | 1000 | ||
938 | fpq = &fs->vqs[queue_id].fud->pq; | 1001 | fsvq = &fs->vqs[queue_id]; |
939 | spin_lock(&fpq->lock); | 1002 | ret = virtio_fs_enqueue_req(fsvq, req, false); |
940 | if (!fpq->connected) { | ||
941 | spin_unlock(&fpq->lock); | ||
942 | req->out.h.error = -ENODEV; | ||
943 | pr_err("virtio-fs: %s disconnected\n", __func__); | ||
944 | fuse_request_end(fc, req); | ||
945 | return; | ||
946 | } | ||
947 | list_add_tail(&req->list, fpq->processing); | ||
948 | spin_unlock(&fpq->lock); | ||
949 | set_bit(FR_SENT, &req->flags); | ||
950 | /* matches barrier in request_wait_answer() */ | ||
951 | smp_mb__after_atomic(); | ||
952 | |||
953 | retry: | ||
954 | ret = virtio_fs_enqueue_req(&fs->vqs[queue_id], req); | ||
955 | if (ret < 0) { | 1003 | if (ret < 0) { |
956 | if (ret == -ENOMEM || ret == -ENOSPC) { | 1004 | if (ret == -ENOMEM || ret == -ENOSPC) { |
957 | /* Virtqueue full. Retry submission */ | 1005 | /* |
958 | /* TODO use completion instead of timeout */ | 1006 | * Virtqueue full. Retry submission from worker |
959 | usleep_range(20, 30); | 1007 | * context as we might be holding fc->bg_lock. |
960 | goto retry; | 1008 | */ |
1009 | spin_lock(&fsvq->lock); | ||
1010 | list_add_tail(&req->list, &fsvq->queued_reqs); | ||
1011 | inc_in_flight_req(fsvq); | ||
1012 | schedule_delayed_work(&fsvq->dispatch_work, | ||
1013 | msecs_to_jiffies(1)); | ||
1014 | spin_unlock(&fsvq->lock); | ||
1015 | return; | ||
961 | } | 1016 | } |
962 | req->out.h.error = ret; | 1017 | req->out.h.error = ret; |
963 | pr_err("virtio-fs: virtio_fs_enqueue_req() failed %d\n", ret); | 1018 | pr_err("virtio-fs: virtio_fs_enqueue_req() failed %d\n", ret); |
964 | spin_lock(&fpq->lock); | 1019 | |
965 | clear_bit(FR_SENT, &req->flags); | 1020 | /* Can't end request in submission context. Use a worker */ |
966 | list_del_init(&req->list); | 1021 | spin_lock(&fsvq->lock); |
967 | spin_unlock(&fpq->lock); | 1022 | list_add_tail(&req->list, &fsvq->end_reqs); |
968 | fuse_request_end(fc, req); | 1023 | schedule_delayed_work(&fsvq->dispatch_work, 0); |
1024 | spin_unlock(&fsvq->lock); | ||
969 | return; | 1025 | return; |
970 | } | 1026 | } |
971 | } | 1027 | } |
@@ -992,6 +1048,7 @@ static int virtio_fs_fill_super(struct super_block *sb) | |||
992 | .destroy = true, | 1048 | .destroy = true, |
993 | .no_control = true, | 1049 | .no_control = true, |
994 | .no_force_umount = true, | 1050 | .no_force_umount = true, |
1051 | .no_mount_options = true, | ||
995 | }; | 1052 | }; |
996 | 1053 | ||
997 | mutex_lock(&virtio_fs_mutex); | 1054 | mutex_lock(&virtio_fs_mutex); |
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index 802b0377a49e..373cada89815 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h | |||
@@ -38,6 +38,43 @@ | |||
38 | * | 38 | * |
39 | * Protocol changelog: | 39 | * Protocol changelog: |
40 | * | 40 | * |
41 | * 7.1: | ||
42 | * - add the following messages: | ||
43 | * FUSE_SETATTR, FUSE_SYMLINK, FUSE_MKNOD, FUSE_MKDIR, FUSE_UNLINK, | ||
44 | * FUSE_RMDIR, FUSE_RENAME, FUSE_LINK, FUSE_OPEN, FUSE_READ, FUSE_WRITE, | ||
45 | * FUSE_RELEASE, FUSE_FSYNC, FUSE_FLUSH, FUSE_SETXATTR, FUSE_GETXATTR, | ||
46 | * FUSE_LISTXATTR, FUSE_REMOVEXATTR, FUSE_OPENDIR, FUSE_READDIR, | ||
47 | * FUSE_RELEASEDIR | ||
48 | * - add padding to messages to accommodate 32-bit servers on 64-bit kernels | ||
49 | * | ||
50 | * 7.2: | ||
51 | * - add FOPEN_DIRECT_IO and FOPEN_KEEP_CACHE flags | ||
52 | * - add FUSE_FSYNCDIR message | ||
53 | * | ||
54 | * 7.3: | ||
55 | * - add FUSE_ACCESS message | ||
56 | * - add FUSE_CREATE message | ||
57 | * - add filehandle to fuse_setattr_in | ||
58 | * | ||
59 | * 7.4: | ||
60 | * - add frsize to fuse_kstatfs | ||
61 | * - clean up request size limit checking | ||
62 | * | ||
63 | * 7.5: | ||
64 | * - add flags and max_write to fuse_init_out | ||
65 | * | ||
66 | * 7.6: | ||
67 | * - add max_readahead to fuse_init_in and fuse_init_out | ||
68 | * | ||
69 | * 7.7: | ||
70 | * - add FUSE_INTERRUPT message | ||
71 | * - add POSIX file lock support | ||
72 | * | ||
73 | * 7.8: | ||
74 | * - add lock_owner and flags fields to fuse_release_in | ||
75 | * - add FUSE_BMAP message | ||
76 | * - add FUSE_DESTROY message | ||
77 | * | ||
41 | * 7.9: | 78 | * 7.9: |
42 | * - new fuse_getattr_in input argument of GETATTR | 79 | * - new fuse_getattr_in input argument of GETATTR |
43 | * - add lk_flags in fuse_lk_in | 80 | * - add lk_flags in fuse_lk_in |