Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -196,17 +196,22 @@ static int readpage_nounlock(struct file *filp, struct page *page)
	u64 len = PAGE_CACHE_SIZE;

	if (off >= i_size_read(inode)) {
		zero_user_segment(page, err, PAGE_CACHE_SIZE);
		zero_user_segment(page, 0, PAGE_CACHE_SIZE);
		SetPageUptodate(page);
		return 0;
	}

	if (ci->i_inline_version != CEPH_INLINE_NONE) {
		/*
	 * Uptodate inline data should have been added into page cache
	 * while getting Fcr caps.
		 * Uptodate inline data should have been added
		 * into page cache while getting Fcr caps.
		 */
	if (ci->i_inline_version != CEPH_INLINE_NONE)
		if (off == 0)
			return -EINVAL;
		zero_user_segment(page, 0, PAGE_CACHE_SIZE);
		SetPageUptodate(page);
		return 0;
	}

	err = ceph_readpage_from_fscache(inode, page);
	if (err == 0)
+14 −8
Original line number Diff line number Diff line
@@ -879,23 +879,29 @@ static ssize_t ceph_read_iter(struct kiocb *iocb, struct iov_iter *to)

		i_size = i_size_read(inode);
		if (retry_op == READ_INLINE) {
			/* does not support inline data > PAGE_SIZE */
			if (i_size > PAGE_CACHE_SIZE) {
				ret = -EIO;
			} else if (iocb->ki_pos < i_size) {
			BUG_ON(ret > 0 || read > 0);
			if (iocb->ki_pos < i_size &&
			    iocb->ki_pos < PAGE_CACHE_SIZE) {
				loff_t end = min_t(loff_t, i_size,
						   iocb->ki_pos + len);
				end = min_t(loff_t, end, PAGE_CACHE_SIZE);
				if (statret < end)
					zero_user_segment(page, statret, end);
				ret = copy_page_to_iter(page,
						iocb->ki_pos & ~PAGE_MASK,
						end - iocb->ki_pos, to);
				iocb->ki_pos += ret;
			} else {
				ret = 0;
				read += ret;
			}
			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);
			return ret;
			return read;
		}

		/* hit EOF or hole? */