diff options
author | Pavel Emelyanov <xemul@openvz.org> | 2013-10-10 09:10:16 -0400 |
---|---|---|
committer | Miklos Szeredi <mszeredi@suse.cz> | 2014-04-02 09:38:47 -0400 |
commit | a92adc824ed5feaa2d4f7029f21170f574987aee (patch) | |
tree | c9eff424e5bcdf453915d7c6aed709d0d0fb24eb /fs/fuse | |
parent | 650b22b941fa03590c4a3671e79ec2c96ea59e9a (diff) |
fuse: Prepare to handle short reads
A helper which gets called when read reports less bytes than was requested.
See patch "trust kernel i_size only" for details.
Signed-off-by: Maxim Patlasov <MPatlasov@parallels.com>
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/file.c | 21 |
1 files changed, 13 insertions, 8 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 2489aca4d1a6..592d7b48e421 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -671,6 +671,15 @@ static void fuse_read_update_size(struct inode *inode, loff_t size, | |||
671 | spin_unlock(&fc->lock); | 671 | spin_unlock(&fc->lock); |
672 | } | 672 | } |
673 | 673 | ||
674 | static void fuse_short_read(struct fuse_req *req, struct inode *inode, | ||
675 | u64 attr_ver) | ||
676 | { | ||
677 | size_t num_read = req->out.args[0].size; | ||
678 | |||
679 | loff_t pos = page_offset(req->pages[0]) + num_read; | ||
680 | fuse_read_update_size(inode, pos, attr_ver); | ||
681 | } | ||
682 | |||
674 | static int fuse_readpage(struct file *file, struct page *page) | 683 | static int fuse_readpage(struct file *file, struct page *page) |
675 | { | 684 | { |
676 | struct fuse_io_priv io = { .async = 0, .file = file }; | 685 | struct fuse_io_priv io = { .async = 0, .file = file }; |
@@ -708,18 +717,18 @@ static int fuse_readpage(struct file *file, struct page *page) | |||
708 | req->page_descs[0].length = count; | 717 | req->page_descs[0].length = count; |
709 | num_read = fuse_send_read(req, &io, pos, count, NULL); | 718 | num_read = fuse_send_read(req, &io, pos, count, NULL); |
710 | err = req->out.h.error; | 719 | err = req->out.h.error; |
711 | fuse_put_request(fc, req); | ||
712 | 720 | ||
713 | if (!err) { | 721 | if (!err) { |
714 | /* | 722 | /* |
715 | * Short read means EOF. If file size is larger, truncate it | 723 | * Short read means EOF. If file size is larger, truncate it |
716 | */ | 724 | */ |
717 | if (num_read < count) | 725 | if (num_read < count) |
718 | fuse_read_update_size(inode, pos + num_read, attr_ver); | 726 | fuse_short_read(req, inode, attr_ver); |
719 | 727 | ||
720 | SetPageUptodate(page); | 728 | SetPageUptodate(page); |
721 | } | 729 | } |
722 | 730 | ||
731 | fuse_put_request(fc, req); | ||
723 | fuse_invalidate_atime(inode); | 732 | fuse_invalidate_atime(inode); |
724 | out: | 733 | out: |
725 | unlock_page(page); | 734 | unlock_page(page); |
@@ -742,13 +751,9 @@ static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req) | |||
742 | /* | 751 | /* |
743 | * Short read means EOF. If file size is larger, truncate it | 752 | * Short read means EOF. If file size is larger, truncate it |
744 | */ | 753 | */ |
745 | if (!req->out.h.error && num_read < count) { | 754 | if (!req->out.h.error && num_read < count) |
746 | loff_t pos; | 755 | fuse_short_read(req, inode, req->misc.read.attr_ver); |
747 | 756 | ||
748 | pos = page_offset(req->pages[0]) + num_read; | ||
749 | fuse_read_update_size(inode, pos, | ||
750 | req->misc.read.attr_ver); | ||
751 | } | ||
752 | fuse_invalidate_atime(inode); | 757 | fuse_invalidate_atime(inode); |
753 | } | 758 | } |
754 | 759 | ||