summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2016-02-26 03:27:13 -0500
committerIlya Dryomov <idryomov@gmail.com>2016-03-25 13:51:53 -0400
commitaf5e5eb574776cdf1b756a27cc437bff257e22fe (patch)
treec96a1b12b10744491f89d19ac1bfe21f6a519747
parent89f081730c49a1d3b46359aa0054e6b3b80f47e4 (diff)
ceph: fix race during filling readdir cache
Readdir cache uses page cache to save dentry pointers. When adding dentry pointers to middle of a page, we need to make sure the page already exists. Otherwise the beginning part of the page will be invalid pointers. Signed-off-by: Yan, Zheng <zyan@redhat.com>
-rw-r--r--fs/ceph/inode.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index cec68a6e20df..495decfc4b34 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -1349,15 +1349,20 @@ static int fill_readdir_cache(struct inode *dir, struct dentry *dn,
1349 1349
1350 if (!ctl->page || pgoff != page_index(ctl->page)) { 1350 if (!ctl->page || pgoff != page_index(ctl->page)) {
1351 ceph_readdir_cache_release(ctl); 1351 ceph_readdir_cache_release(ctl);
1352 ctl->page = grab_cache_page(&dir->i_data, pgoff); 1352 if (idx == 0)
1353 ctl->page = grab_cache_page(&dir->i_data, pgoff);
1354 else
1355 ctl->page = find_lock_page(&dir->i_data, pgoff);
1353 if (!ctl->page) { 1356 if (!ctl->page) {
1354 ctl->index = -1; 1357 ctl->index = -1;
1355 return -ENOMEM; 1358 return idx == 0 ? -ENOMEM : 0;
1356 } 1359 }
1357 /* reading/filling the cache are serialized by 1360 /* reading/filling the cache are serialized by
1358 * i_mutex, no need to use page lock */ 1361 * i_mutex, no need to use page lock */
1359 unlock_page(ctl->page); 1362 unlock_page(ctl->page);
1360 ctl->dentries = kmap(ctl->page); 1363 ctl->dentries = kmap(ctl->page);
1364 if (idx == 0)
1365 memset(ctl->dentries, 0, PAGE_CACHE_SIZE);
1361 } 1366 }
1362 1367
1363 if (req->r_dir_release_cnt == atomic64_read(&ci->i_release_count) && 1368 if (req->r_dir_release_cnt == atomic64_read(&ci->i_release_count) &&