Commit fcc02d2a authored by Yan, Zheng's avatar Yan, Zheng Committed by Ilya Dryomov

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: default avatarYan, Zheng <zyan@redhat.com>
parent 86d8f67b
...@@ -196,17 +196,22 @@ static int readpage_nounlock(struct file *filp, struct page *page) ...@@ -196,17 +196,22 @@ static int readpage_nounlock(struct file *filp, struct page *page)
u64 len = PAGE_CACHE_SIZE; u64 len = PAGE_CACHE_SIZE;
if (off >= i_size_read(inode)) { if (off >= i_size_read(inode)) {
zero_user_segment(page, err, PAGE_CACHE_SIZE); zero_user_segment(page, 0, PAGE_CACHE_SIZE);
SetPageUptodate(page); SetPageUptodate(page);
return 0; return 0;
} }
if (ci->i_inline_version != CEPH_INLINE_NONE) {
/* /*
* Uptodate inline data should have been added into page cache * Uptodate inline data should have been added
* while getting Fcr caps. * into page cache while getting Fcr caps.
*/ */
if (ci->i_inline_version != CEPH_INLINE_NONE) if (off == 0)
return -EINVAL; return -EINVAL;
zero_user_segment(page, 0, PAGE_CACHE_SIZE);
SetPageUptodate(page);
return 0;
}
err = ceph_readpage_from_fscache(inode, page); err = ceph_readpage_from_fscache(inode, page);
if (err == 0) if (err == 0)
......
...@@ -879,23 +879,29 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to) ...@@ -879,23 +879,29 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to)
i_size = i_size_read(inode); i_size = i_size_read(inode);
if (retry_op == READ_INLINE) { if (retry_op == READ_INLINE) {
/* does not support inline data > PAGE_SIZE */ BUG_ON(ret > 0 || read > 0);
if (i_size > PAGE_CACHE_SIZE) { if (iocb->ki_pos < i_size &&
ret = -EIO; iocb->ki_pos < PAGE_CACHE_SIZE) {
} else if (iocb->ki_pos < i_size) {
loff_t end = min_t(loff_t, i_size, loff_t end = min_t(loff_t, i_size,
iocb->ki_pos + len); iocb->ki_pos + len);
end = min_t(loff_t, end, PAGE_CACHE_SIZE);
if (statret < end) if (statret < end)
zero_user_segment(page, statret, end); zero_user_segment(page, statret, end);
ret = copy_page_to_iter(page, ret = copy_page_to_iter(page,
iocb->ki_pos & ~PAGE_MASK, iocb->ki_pos & ~PAGE_MASK,
end - iocb->ki_pos, to); end - iocb->ki_pos, to);
iocb->ki_pos += ret; iocb->ki_pos += ret;
} else { read += ret;
ret = 0; }
if (iocb->ki_pos < i_size && read < len) {
size_t zlen = min_t(size_t, len - read,
i_size - iocb->ki_pos);
ret = iov_iter_zero(zlen, to);
iocb->ki_pos += ret;
read += ret;
} }
__free_pages(page, 0); __free_pages(page, 0);
return ret; return read;
} }
/* hit EOF or hole? */ /* hit EOF or hole? */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment