diff options
author | Christoph Hellwig <hch@lst.de> | 2015-02-02 08:59:43 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-03-13 12:10:15 -0400 |
commit | 9d5722b7777e64de2d932f46cfee7765fdcc60d6 (patch) | |
tree | b0f1e84779f0b6d6ead9bc2adcb700ddc1ef2efe /fs/fuse/file.c | |
parent | 66ee59af630fd8d5f4f56fb28162857e629aa0ab (diff) |
fuse: handle synchronous iocbs internally
Based on a patch from Maxim Patlasov <MPatlasov@parallels.com>.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r-- | fs/fuse/file.c | 51 |
1 files changed, 31 insertions, 20 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index c01ec3bdcfd8..f81d83eb9758 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -528,6 +528,17 @@ static void fuse_release_user_pages(struct fuse_req *req, int write) | |||
528 | } | 528 | } |
529 | } | 529 | } |
530 | 530 | ||
531 | static ssize_t fuse_get_res_by_io(struct fuse_io_priv *io) | ||
532 | { | ||
533 | if (io->err) | ||
534 | return io->err; | ||
535 | |||
536 | if (io->bytes >= 0 && io->write) | ||
537 | return -EIO; | ||
538 | |||
539 | return io->bytes < 0 ? io->size : io->bytes; | ||
540 | } | ||
541 | |||
531 | /** | 542 | /** |
532 | * In case of short read, the caller sets 'pos' to the position of | 543 | * In case of short read, the caller sets 'pos' to the position of |
533 | * actual end of fuse request in IO request. Otherwise, if bytes_requested | 544 | * actual end of fuse request in IO request. Otherwise, if bytes_requested |
@@ -546,6 +557,7 @@ static void fuse_release_user_pages(struct fuse_req *req, int write) | |||
546 | */ | 557 | */ |
547 | static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos) | 558 | static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos) |
548 | { | 559 | { |
560 | bool is_sync = is_sync_kiocb(io->iocb); | ||
549 | int left; | 561 | int left; |
550 | 562 | ||
551 | spin_lock(&io->lock); | 563 | spin_lock(&io->lock); |
@@ -555,27 +567,21 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos) | |||
555 | io->bytes = pos; | 567 | io->bytes = pos; |
556 | 568 | ||
557 | left = --io->reqs; | 569 | left = --io->reqs; |
570 | if (!left && is_sync) | ||
571 | complete(io->done); | ||
558 | spin_unlock(&io->lock); | 572 | spin_unlock(&io->lock); |
559 | 573 | ||
560 | if (!left) { | 574 | if (!left && !is_sync) { |
561 | long res; | 575 | ssize_t res = fuse_get_res_by_io(io); |
562 | 576 | ||
563 | if (io->err) | 577 | if (res >= 0) { |
564 | res = io->err; | 578 | struct inode *inode = file_inode(io->iocb->ki_filp); |
565 | else if (io->bytes >= 0 && io->write) | 579 | struct fuse_conn *fc = get_fuse_conn(inode); |
566 | res = -EIO; | 580 | struct fuse_inode *fi = get_fuse_inode(inode); |
567 | else { | ||
568 | res = io->bytes < 0 ? io->size : io->bytes; | ||
569 | 581 | ||
570 | if (!is_sync_kiocb(io->iocb)) { | 582 | spin_lock(&fc->lock); |
571 | struct inode *inode = file_inode(io->iocb->ki_filp); | 583 | fi->attr_version = ++fc->attr_version; |
572 | struct fuse_conn *fc = get_fuse_conn(inode); | 584 | spin_unlock(&fc->lock); |
573 | struct fuse_inode *fi = get_fuse_inode(inode); | ||
574 | |||
575 | spin_lock(&fc->lock); | ||
576 | fi->attr_version = ++fc->attr_version; | ||
577 | spin_unlock(&fc->lock); | ||
578 | } | ||
579 | } | 585 | } |
580 | 586 | ||
581 | aio_complete(io->iocb, res, 0); | 587 | aio_complete(io->iocb, res, 0); |
@@ -2801,6 +2807,7 @@ static ssize_t | |||
2801 | fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, | 2807 | fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, |
2802 | loff_t offset) | 2808 | loff_t offset) |
2803 | { | 2809 | { |
2810 | DECLARE_COMPLETION_ONSTACK(wait); | ||
2804 | ssize_t ret = 0; | 2811 | ssize_t ret = 0; |
2805 | struct file *file = iocb->ki_filp; | 2812 | struct file *file = iocb->ki_filp; |
2806 | struct fuse_file *ff = file->private_data; | 2813 | struct fuse_file *ff = file->private_data; |
@@ -2852,6 +2859,9 @@ fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, | |||
2852 | if (!is_sync_kiocb(iocb) && (offset + count > i_size) && rw == WRITE) | 2859 | if (!is_sync_kiocb(iocb) && (offset + count > i_size) && rw == WRITE) |
2853 | io->async = false; | 2860 | io->async = false; |
2854 | 2861 | ||
2862 | if (io->async && is_sync_kiocb(iocb)) | ||
2863 | io->done = &wait; | ||
2864 | |||
2855 | if (rw == WRITE) | 2865 | if (rw == WRITE) |
2856 | ret = __fuse_direct_write(io, iter, &pos); | 2866 | ret = __fuse_direct_write(io, iter, &pos); |
2857 | else | 2867 | else |
@@ -2864,11 +2874,12 @@ fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, | |||
2864 | if (!is_sync_kiocb(iocb)) | 2874 | if (!is_sync_kiocb(iocb)) |
2865 | return -EIOCBQUEUED; | 2875 | return -EIOCBQUEUED; |
2866 | 2876 | ||
2867 | ret = wait_on_sync_kiocb(iocb); | 2877 | wait_for_completion(&wait); |
2868 | } else { | 2878 | ret = fuse_get_res_by_io(io); |
2869 | kfree(io); | ||
2870 | } | 2879 | } |
2871 | 2880 | ||
2881 | kfree(io); | ||
2882 | |||
2872 | if (rw == WRITE) { | 2883 | if (rw == WRITE) { |
2873 | if (ret > 0) | 2884 | if (ret > 0) |
2874 | fuse_write_update_size(inode, pos); | 2885 | fuse_write_update_size(inode, pos); |