aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/ceph/addr.c24
-rw-r--r--fs/ceph/cache.c12
2 files changed, 18 insertions, 18 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}
diff --git a/fs/ceph/cache.c b/fs/ceph/cache.c
index fd1172823f86..337f88673ed9 100644
--- a/fs/ceph/cache.c
+++ b/fs/ceph/cache.c
@@ -297,13 +297,7 @@ void ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp)
297 } 297 }
298} 298}
299 299
300static void ceph_vfs_readpage_complete(struct page *page, void *data, int error) 300static void ceph_readpage_from_fscache_complete(struct page *page, void *data, int error)
301{
302 if (!error)
303 SetPageUptodate(page);
304}
305
306static void ceph_vfs_readpage_complete_unlock(struct page *page, void *data, int error)
307{ 301{
308 if (!error) 302 if (!error)
309 SetPageUptodate(page); 303 SetPageUptodate(page);
@@ -331,7 +325,7 @@ int ceph_readpage_from_fscache(struct inode *inode, struct page *page)
331 return -ENOBUFS; 325 return -ENOBUFS;
332 326
333 ret = fscache_read_or_alloc_page(ci->fscache, page, 327 ret = fscache_read_or_alloc_page(ci->fscache, page,
334 ceph_vfs_readpage_complete, NULL, 328 ceph_readpage_from_fscache_complete, NULL,
335 GFP_KERNEL); 329 GFP_KERNEL);
336 330
337 switch (ret) { 331 switch (ret) {
@@ -360,7 +354,7 @@ int ceph_readpages_from_fscache(struct inode *inode,
360 return -ENOBUFS; 354 return -ENOBUFS;
361 355
362 ret = fscache_read_or_alloc_pages(ci->fscache, mapping, pages, nr_pages, 356 ret = fscache_read_or_alloc_pages(ci->fscache, mapping, pages, nr_pages,
363 ceph_vfs_readpage_complete_unlock, 357 ceph_readpage_from_fscache_complete,
364 NULL, mapping_gfp_mask(mapping)); 358 NULL, mapping_gfp_mask(mapping));
365 359
366 switch (ret) { 360 switch (ret) {