diff options
author | Yan, Zheng <zyan@redhat.com> | 2015-01-09 22:43:12 -0500 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2015-02-19 05:31:39 -0500 |
commit | fcc02d2a03fc629b82d1ca1006fbd06570385264 (patch) | |
tree | d41660d615642608748ebcd51a6140c96102ede0 /fs | |
parent | 86d8f67b26a8b30228b5177b7e594bbc89798a23 (diff) |
ceph: fix reading inline data when i_size > PAGE_SIZE
when inode has inline data but its size > PAGE_SIZE (it was truncated
to larger size), previous direct read code return -EIO. This patch adds
code to return zeros for data whose offset > PAGE_SIZE.
Signed-off-by: Yan, Zheng <zyan@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ceph/addr.c | 19 | ||||
-rw-r--r-- | fs/ceph/file.c | 22 |
2 files changed, 26 insertions, 15 deletions
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index c81c0e004588..7d05e37874d4 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c | |||
@@ -196,17 +196,22 @@ static int readpage_nounlock(struct file *filp, struct page *page) | |||
196 | u64 len = PAGE_CACHE_SIZE; | 196 | u64 len = PAGE_CACHE_SIZE; |
197 | 197 | ||
198 | if (off >= i_size_read(inode)) { | 198 | if (off >= i_size_read(inode)) { |
199 | zero_user_segment(page, err, PAGE_CACHE_SIZE); | 199 | zero_user_segment(page, 0, PAGE_CACHE_SIZE); |
200 | SetPageUptodate(page); | 200 | SetPageUptodate(page); |
201 | return 0; | 201 | return 0; |
202 | } | 202 | } |
203 | 203 | ||
204 | /* | 204 | if (ci->i_inline_version != CEPH_INLINE_NONE) { |
205 | * Uptodate inline data should have been added into page cache | 205 | /* |
206 | * while getting Fcr caps. | 206 | * Uptodate inline data should have been added |
207 | */ | 207 | * into page cache while getting Fcr caps. |
208 | if (ci->i_inline_version != CEPH_INLINE_NONE) | 208 | */ |
209 | return -EINVAL; | 209 | if (off == 0) |
210 | return -EINVAL; | ||
211 | zero_user_segment(page, 0, PAGE_CACHE_SIZE); | ||
212 | SetPageUptodate(page); | ||
213 | return 0; | ||
214 | } | ||
210 | 215 | ||
211 | err = ceph_readpage_from_fscache(inode, page); | 216 | err = ceph_readpage_from_fscache(inode, page); |
212 | if (err == 0) | 217 | if (err == 0) |
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 663da44c06b6..c407abb52b7b 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
@@ -879,28 +879,34 @@ again: | |||
879 | 879 | ||
880 | i_size = i_size_read(inode); | 880 | i_size = i_size_read(inode); |
881 | if (retry_op == READ_INLINE) { | 881 | if (retry_op == READ_INLINE) { |
882 | /* does not support inline data > PAGE_SIZE */ | 882 | BUG_ON(ret > 0 || read > 0); |
883 | if (i_size > PAGE_CACHE_SIZE) { | 883 | if (iocb->ki_pos < i_size && |
884 | ret = -EIO; | 884 | iocb->ki_pos < PAGE_CACHE_SIZE) { |
885 | } else if (iocb->ki_pos < i_size) { | ||
886 | loff_t end = min_t(loff_t, i_size, | 885 | loff_t end = min_t(loff_t, i_size, |
887 | iocb->ki_pos + len); | 886 | iocb->ki_pos + len); |
887 | end = min_t(loff_t, end, PAGE_CACHE_SIZE); | ||
888 | if (statret < end) | 888 | if (statret < end) |
889 | zero_user_segment(page, statret, end); | 889 | zero_user_segment(page, statret, end); |
890 | ret = copy_page_to_iter(page, | 890 | ret = copy_page_to_iter(page, |
891 | iocb->ki_pos & ~PAGE_MASK, | 891 | iocb->ki_pos & ~PAGE_MASK, |
892 | end - iocb->ki_pos, to); | 892 | end - iocb->ki_pos, to); |
893 | iocb->ki_pos += ret; | 893 | iocb->ki_pos += ret; |
894 | } else { | 894 | read += ret; |
895 | ret = 0; | 895 | } |
896 | if (iocb->ki_pos < i_size && read < len) { | ||
897 | size_t zlen = min_t(size_t, len - read, | ||
898 | i_size - iocb->ki_pos); | ||
899 | ret = iov_iter_zero(zlen, to); | ||
900 | iocb->ki_pos += ret; | ||
901 | read += ret; | ||
896 | } | 902 | } |
897 | __free_pages(page, 0); | 903 | __free_pages(page, 0); |
898 | return ret; | 904 | return read; |
899 | } | 905 | } |
900 | 906 | ||
901 | /* hit EOF or hole? */ | 907 | /* hit EOF or hole? */ |
902 | if (retry_op == CHECK_EOF && iocb->ki_pos < i_size && | 908 | if (retry_op == CHECK_EOF && iocb->ki_pos < i_size && |
903 | ret < len) { | 909 | ret < len) { |
904 | dout("sync_read hit hole, ppos %lld < size %lld" | 910 | dout("sync_read hit hole, ppos %lld < size %lld" |
905 | ", reading more\n", iocb->ki_pos, | 911 | ", reading more\n", iocb->ki_pos, |
906 | inode->i_size); | 912 | inode->i_size); |