Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Christoph Hellwig and committed by
Al Viro
9d5722b7 66ee59af

+32 -20
+31 -20
fs/fuse/file.c
··· 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 543 * In case of short read, the caller sets 'pos' to the position of 533 544 * actual end of fuse request in IO request. Otherwise, if bytes_requested ··· 557 546 */ 558 547 static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos) 559 548 { 549 + bool is_sync = is_sync_kiocb(io->iocb); 560 550 int left; 561 551 562 552 spin_lock(&io->lock); ··· 567 555 io->bytes = pos; 568 556 569 557 left = --io->reqs; 558 + if (!left && is_sync) 559 + complete(io->done); 570 560 spin_unlock(&io->lock); 571 561 572 - if (!left) { 573 - long res; 562 + if (!left && !is_sync) { 563 + ssize_t res = fuse_get_res_by_io(io); 574 564 575 - if (io->err) 576 - res = io->err; 577 - else if (io->bytes >= 0 && io->write) 578 - res = -EIO; 579 - else { 580 - res = io->bytes < 0 ? io->size : io->bytes; 565 + if (res >= 0) { 566 + struct inode *inode = file_inode(io->iocb->ki_filp); 567 + struct fuse_conn *fc = get_fuse_conn(inode); 568 + struct fuse_inode *fi = get_fuse_inode(inode); 581 569 582 - if (!is_sync_kiocb(io->iocb)) { 583 - struct inode *inode = file_inode(io->iocb->ki_filp); 584 - struct fuse_conn *fc = get_fuse_conn(inode); 585 - struct fuse_inode *fi = get_fuse_inode(inode); 586 - 587 - spin_lock(&fc->lock); 588 - fi->attr_version = ++fc->attr_version; 589 - spin_unlock(&fc->lock); 590 - } 570 + spin_lock(&fc->lock); 571 + fi->attr_version = ++fc->attr_version; 572 + spin_unlock(&fc->lock); 591 573 } 592 574 593 575 aio_complete(io->iocb, res, 0); ··· 2807 2801 fuse_direct_IO(int rw, struct kiocb *iocb, struct iov_iter *iter, 2808 2802 loff_t offset) 2809 2803 { 2804 + DECLARE_COMPLETION_ONSTACK(wait); 2810 2805 ssize_t ret = 0; 2811 2806 struct file *file = iocb->ki_filp; 2812 2807 struct fuse_file *ff = file->private_data; ··· 2859 2852 if (!is_sync_kiocb(iocb) && (offset + count > i_size) && rw == WRITE) 2860 2853 io->async = false; 2861 2854 2855 + if (io->async && is_sync_kiocb(iocb)) 2856 + io->done = &wait; 2857 + 2862 2858 if (rw == WRITE) 2863 2859 ret = __fuse_direct_write(io, iter, &pos); 2864 2860 else ··· 2874 2864 if (!is_sync_kiocb(iocb)) 2875 2865 return -EIOCBQUEUED; 2876 2866 2877 - ret = wait_on_sync_kiocb(iocb); 2878 - } else { 2879 - kfree(io); 2867 + wait_for_completion(&wait); 2868 + ret = fuse_get_res_by_io(io); 2880 2869 } 2870 + 2871 + kfree(io); 2881 2872 2882 2873 if (rw == WRITE) { 2883 2874 if (ret > 0)
+1
fs/fuse/fuse_i.h
··· 263 263 int err; 264 264 struct kiocb *iocb; 265 265 struct file *file; 266 + struct completion *done; 266 267 }; 267 268 268 269 /**