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 | |
| 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>
| -rw-r--r-- | fs/fuse/file.c | 51 | ||||
| -rw-r--r-- | fs/fuse/fuse_i.h | 1 |
2 files changed, 32 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); |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 1cdfb07c1376..7354dc142a50 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
| @@ -263,6 +263,7 @@ struct fuse_io_priv { | |||
| 263 | int err; | 263 | int err; |
| 264 | struct kiocb *iocb; | 264 | struct kiocb *iocb; |
| 265 | struct file *file; | 265 | struct file *file; |
| 266 | struct completion *done; | ||
| 266 | }; | 267 | }; |
| 267 | 268 | ||
| 268 | /** | 269 | /** |
