aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph/addr.c
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2017-08-03 23:22:31 -0400
committerIlya Dryomov <idryomov@gmail.com>2017-08-31 18:04:26 -0400
commitdd2bc473482eedc60c29cf00ad12568ce40ce511 (patch)
treee06527af35691390fce75993b0986cad10be1225 /fs/ceph/addr.c
parentcc4a41fe5541a73019a864883297bd5043aa6d98 (diff)
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: "Yan, Zheng" <zyan@redhat.com> Reviewed-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs/ceph/addr.c')
-rw-r--r--fs/ceph/addr.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index 50836280a6f8..1bc709fe330a 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -189,7 +189,7 @@ static int ceph_releasepage(struct page *page, gfp_t g)
189/* 189/*
190 * read a single page, without unlocking it. 190 * read a single page, without unlocking it.
191 */ 191 */
192static int readpage_nounlock(struct file *filp, struct page *page) 192static int ceph_do_readpage(struct file *filp, struct page *page)
193{ 193{
194 struct inode *inode = file_inode(filp); 194 struct inode *inode = file_inode(filp);
195 struct ceph_inode_info *ci = ceph_inode(inode); 195 struct ceph_inode_info *ci = ceph_inode(inode);
@@ -219,7 +219,7 @@ static int readpage_nounlock(struct file *filp, struct page *page)
219 219
220 err = ceph_readpage_from_fscache(inode, page); 220 err = ceph_readpage_from_fscache(inode, page);
221 if (err == 0) 221 if (err == 0)
222 goto out; 222 return -EINPROGRESS;
223 223
224 dout("readpage inode %p file %p page %p index %lu\n", 224 dout("readpage inode %p file %p page %p index %lu\n",
225 inode, filp, page, page->index); 225 inode, filp, page, page->index);
@@ -249,8 +249,11 @@ out:
249 249
250static int ceph_readpage(struct file *filp, struct page *page) 250static int ceph_readpage(struct file *filp, struct page *page)
251{ 251{
252 int r = readpage_nounlock(filp, page); 252 int r = ceph_do_readpage(filp, page);
253 unlock_page(page); 253 if (r != -EINPROGRESS)
254 unlock_page(page);
255 else
256 r = 0;
254 return r; 257 return r;
255} 258}
256 259
@@ -1237,7 +1240,7 @@ retry_locked:
1237 goto retry_locked; 1240 goto retry_locked;
1238 r = writepage_nounlock(page, NULL); 1241 r = writepage_nounlock(page, NULL);
1239 if (r < 0) 1242 if (r < 0)
1240 goto fail_nosnap; 1243 goto fail_unlock;
1241 goto retry_locked; 1244 goto retry_locked;
1242 } 1245 }
1243 1246
@@ -1265,11 +1268,14 @@ retry_locked:
1265 } 1268 }
1266 1269
1267 /* we need to read it. */ 1270 /* we need to read it. */
1268 r = readpage_nounlock(file, page); 1271 r = ceph_do_readpage(file, page);
1269 if (r < 0) 1272 if (r < 0) {
1270 goto fail_nosnap; 1273 if (r == -EINPROGRESS)
1274 return -EAGAIN;
1275 goto fail_unlock;
1276 }
1271 goto retry_locked; 1277 goto retry_locked;
1272fail_nosnap: 1278fail_unlock:
1273 unlock_page(page); 1279 unlock_page(page);
1274 return r; 1280 return r;
1275} 1281}