Skip to content

Commit 857d0b3

Browse files
ukernelgregkh
authored andcommitted
ceph: fix readpage from fscache
commit dd2bc473482eedc60c29cf00ad12568ce40ce511 upstream. 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() Signed-off-by: "Yan, Zheng" <zyan@redhat.com> Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 043ccc9 commit 857d0b3

2 files changed

Lines changed: 18 additions & 18 deletions

File tree

fs/ceph/addr.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ static int ceph_releasepage(struct page *page, gfp_t g)
189189
/*
190190
* read a single page, without unlocking it.
191191
*/
192-
static int readpage_nounlock(struct file *filp, struct page *page)
192+
static int ceph_do_readpage(struct file *filp, struct page *page)
193193
{
194194
struct inode *inode = file_inode(filp);
195195
struct ceph_inode_info *ci = ceph_inode(inode);
@@ -219,7 +219,7 @@ static int readpage_nounlock(struct file *filp, struct page *page)
219219

220220
err = ceph_readpage_from_fscache(inode, page);
221221
if (err == 0)
222-
goto out;
222+
return -EINPROGRESS;
223223

224224
dout("readpage inode %p file %p page %p index %lu\n",
225225
inode, filp, page, page->index);
@@ -249,8 +249,11 @@ static int readpage_nounlock(struct file *filp, struct page *page)
249249

250250
static int ceph_readpage(struct file *filp, struct page *page)
251251
{
252-
int r = readpage_nounlock(filp, page);
253-
unlock_page(page);
252+
int r = ceph_do_readpage(filp, page);
253+
if (r != -EINPROGRESS)
254+
unlock_page(page);
255+
else
256+
r = 0;
254257
return r;
255258
}
256259

@@ -1094,7 +1097,7 @@ static int ceph_update_writeable_page(struct file *file,
10941097
goto retry_locked;
10951098
r = writepage_nounlock(page, NULL);
10961099
if (r < 0)
1097-
goto fail_nosnap;
1100+
goto fail_unlock;
10981101
goto retry_locked;
10991102
}
11001103

@@ -1122,11 +1125,14 @@ static int ceph_update_writeable_page(struct file *file,
11221125
}
11231126

11241127
/* we need to read it. */
1125-
r = readpage_nounlock(file, page);
1126-
if (r < 0)
1127-
goto fail_nosnap;
1128+
r = ceph_do_readpage(file, page);
1129+
if (r < 0) {
1130+
if (r == -EINPROGRESS)
1131+
return -EAGAIN;
1132+
goto fail_unlock;
1133+
}
11281134
goto retry_locked;
1129-
fail_nosnap:
1135+
fail_unlock:
11301136
unlock_page(page);
11311137
return r;
11321138
}

fs/ceph/cache.c

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -224,13 +224,7 @@ void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci)
224224
fscache_relinquish_cookie(cookie, 0);
225225
}
226226

227-
static void ceph_vfs_readpage_complete(struct page *page, void *data, int error)
228-
{
229-
if (!error)
230-
SetPageUptodate(page);
231-
}
232-
233-
static void ceph_vfs_readpage_complete_unlock(struct page *page, void *data, int error)
227+
static void ceph_readpage_from_fscache_complete(struct page *page, void *data, int error)
234228
{
235229
if (!error)
236230
SetPageUptodate(page);
@@ -259,7 +253,7 @@ int ceph_readpage_from_fscache(struct inode *inode, struct page *page)
259253
return -ENOBUFS;
260254

261255
ret = fscache_read_or_alloc_page(ci->fscache, page,
262-
ceph_vfs_readpage_complete, NULL,
256+
ceph_readpage_from_fscache_complete, NULL,
263257
GFP_KERNEL);
264258

265259
switch (ret) {
@@ -288,7 +282,7 @@ int ceph_readpages_from_fscache(struct inode *inode,
288282
return -ENOBUFS;
289283

290284
ret = fscache_read_or_alloc_pages(ci->fscache, mapping, pages, nr_pages,
291-
ceph_vfs_readpage_complete_unlock,
285+
ceph_readpage_from_fscache_complete,
292286
NULL, mapping_gfp_mask(mapping));
293287

294288
switch (ret) {

0 commit comments

Comments
 (0)