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

ceph: fix readpage from fscache

ceph_readpage() unlocks page prematurely prematurely in the case
that page is reading from fscache. Caller of readpage expects that
page is uptodate when it get unlocked. So page shoule get locked
by completion callback of fscache_read_or_alloc_pages()

Cc: stable@vger.kernel.org # 4.1+, needs backporting for < 4.7
Signed-off-by: default avatar"Yan, Zheng" <zyan@redhat.com>
Reviewed-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent cc4a41fe
...@@ -189,7 +189,7 @@ static int ceph_releasepage(struct page *page, gfp_t g) ...@@ -189,7 +189,7 @@ static int ceph_releasepage(struct page *page, gfp_t g)
/* /*
* read a single page, without unlocking it. * read a single page, without unlocking it.
*/ */
static int readpage_nounlock(struct file *filp, struct page *page) static int ceph_do_readpage(struct file *filp, struct page *page)
{ {
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
...@@ -219,7 +219,7 @@ static int readpage_nounlock(struct file *filp, struct page *page) ...@@ -219,7 +219,7 @@ static int readpage_nounlock(struct file *filp, struct page *page)
err = ceph_readpage_from_fscache(inode, page); err = ceph_readpage_from_fscache(inode, page);
if (err == 0) if (err == 0)
goto out; return -EINPROGRESS;
dout("readpage inode %p file %p page %p index %lu\n", dout("readpage inode %p file %p page %p index %lu\n",
inode, filp, page, page->index); inode, filp, page, page->index);
...@@ -249,8 +249,11 @@ static int readpage_nounlock(struct file *filp, struct page *page) ...@@ -249,8 +249,11 @@ static int readpage_nounlock(struct file *filp, struct page *page)
static int ceph_readpage(struct file *filp, struct page *page) static int ceph_readpage(struct file *filp, struct page *page)
{ {
int r = readpage_nounlock(filp, page); int r = ceph_do_readpage(filp, page);
if (r != -EINPROGRESS)
unlock_page(page); unlock_page(page);
else
r = 0;
return r; return r;
} }
...@@ -1237,7 +1240,7 @@ static int ceph_update_writeable_page(struct file *file, ...@@ -1237,7 +1240,7 @@ static int ceph_update_writeable_page(struct file *file,
goto retry_locked; goto retry_locked;
r = writepage_nounlock(page, NULL); r = writepage_nounlock(page, NULL);
if (r < 0) if (r < 0)
goto fail_nosnap; goto fail_unlock;
goto retry_locked; goto retry_locked;
} }
...@@ -1265,11 +1268,14 @@ static int ceph_update_writeable_page(struct file *file, ...@@ -1265,11 +1268,14 @@ static int ceph_update_writeable_page(struct file *file,
} }
/* we need to read it. */ /* we need to read it. */
r = readpage_nounlock(file, page); r = ceph_do_readpage(file, page);
if (r < 0) if (r < 0) {
goto fail_nosnap; if (r == -EINPROGRESS)
return -EAGAIN;
goto fail_unlock;
}
goto retry_locked; goto retry_locked;
fail_nosnap: fail_unlock:
unlock_page(page); unlock_page(page);
return r; return r;
} }
......
...@@ -297,13 +297,7 @@ void ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp) ...@@ -297,13 +297,7 @@ void ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp)
} }
} }
static void ceph_vfs_readpage_complete(struct page *page, void *data, int error) static void ceph_readpage_from_fscache_complete(struct page *page, void *data, int error)
{
if (!error)
SetPageUptodate(page);
}
static void ceph_vfs_readpage_complete_unlock(struct page *page, void *data, int error)
{ {
if (!error) if (!error)
SetPageUptodate(page); SetPageUptodate(page);
...@@ -331,7 +325,7 @@ int ceph_readpage_from_fscache(struct inode *inode, struct page *page) ...@@ -331,7 +325,7 @@ int ceph_readpage_from_fscache(struct inode *inode, struct page *page)
return -ENOBUFS; return -ENOBUFS;
ret = fscache_read_or_alloc_page(ci->fscache, page, ret = fscache_read_or_alloc_page(ci->fscache, page,
ceph_vfs_readpage_complete, NULL, ceph_readpage_from_fscache_complete, NULL,
GFP_KERNEL); GFP_KERNEL);
switch (ret) { switch (ret) {
...@@ -360,7 +354,7 @@ int ceph_readpages_from_fscache(struct inode *inode, ...@@ -360,7 +354,7 @@ int ceph_readpages_from_fscache(struct inode *inode,
return -ENOBUFS; return -ENOBUFS;
ret = fscache_read_or_alloc_pages(ci->fscache, mapping, pages, nr_pages, ret = fscache_read_or_alloc_pages(ci->fscache, mapping, pages, nr_pages,
ceph_vfs_readpage_complete_unlock, ceph_readpage_from_fscache_complete,
NULL, mapping_gfp_mask(mapping)); NULL, mapping_gfp_mask(mapping));
switch (ret) { switch (ret) {
......
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