aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2015-01-09 22:43:12 -0500
committerIlya Dryomov <idryomov@gmail.com>2015-02-19 05:31:39 -0500
commitfcc02d2a03fc629b82d1ca1006fbd06570385264 (patch)
treed41660d615642608748ebcd51a6140c96102ede0 /fs
parent86d8f67b26a8b30228b5177b7e594bbc89798a23 (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.c19
-rw-r--r--fs/ceph/file.c22
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);