aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2016-05-18 08:31:55 -0400
committerIlya Dryomov <idryomov@gmail.com>2016-06-01 04:31:50 -0400
commitf7f7e7a0635dedd5064fba255cb3facfa87b06d6 (patch)
tree3e18ffcddf422deba5b7a10948b15b827defd441
parent46b59b2be05a71d80d76883d2f495f182d768f47 (diff)
ceph: improve fscache revalidation
There are several issues in fscache revalidation code. - In ceph_revalidate_work(), fscache_invalidate() is called when fscache_check_consistency() return 0. This is complete wrong because 0 means cache is valid. - Handle_cap_grant() calls ceph_queue_revalidate() if client already has CAP_FILE_CACHE. This code is confusing. Client should revalidate the cache each time it got CAP_FILE_CACHE anew. - In Handle_cap_grant(), fscache_invalidate() is called if MDS revokes CAP_FILE_CACHE. This is inconsistency with the case that inode get evicted. In the later case, the cache is not discarded. Client may use the cache when inode is reloaded. This patch moves the fscache revalidation into ceph_get_caps(). Client revalidates the cache after it gets CAP_FILE_CACHE. i_rdcache_gen should keep constance while CAP_FILE_CACHE is used. If i_fscache_gen is not equal to i_rdcache_gen, client needs to check cache's consistency. Signed-off-by: Yan, Zheng <zyan@redhat.com>
-rw-r--r--fs/ceph/cache.c84
-rw-r--r--fs/ceph/cache.h20
-rw-r--r--fs/ceph/caps.c16
-rw-r--r--fs/ceph/super.h4
4 files changed, 41 insertions, 83 deletions
diff --git a/fs/ceph/cache.c b/fs/ceph/cache.c
index c19db6afd0cc..5b3f4828f214 100644
--- a/fs/ceph/cache.c
+++ b/fs/ceph/cache.c
@@ -69,15 +69,8 @@ int ceph_fscache_register_fs(struct ceph_fs_client* fsc)
69 fsc->fscache = fscache_acquire_cookie(ceph_cache_netfs.primary_index, 69 fsc->fscache = fscache_acquire_cookie(ceph_cache_netfs.primary_index,
70 &ceph_fscache_fsid_object_def, 70 &ceph_fscache_fsid_object_def,
71 fsc, true); 71 fsc, true);
72 72 if (!fsc->fscache)
73 if (fsc->fscache == NULL) {
74 pr_err("Unable to resgister fsid: %p fscache cookie", fsc); 73 pr_err("Unable to resgister fsid: %p fscache cookie", fsc);
75 return 0;
76 }
77
78 fsc->revalidate_wq = alloc_workqueue("ceph-revalidate", 0, 1);
79 if (fsc->revalidate_wq == NULL)
80 return -ENOMEM;
81 74
82 return 0; 75 return 0;
83} 76}
@@ -260,8 +253,7 @@ static void ceph_vfs_readpage_complete_unlock(struct page *page, void *data, int
260 253
261static inline bool cache_valid(struct ceph_inode_info *ci) 254static inline bool cache_valid(struct ceph_inode_info *ci)
262{ 255{
263 return ((ceph_caps_issued(ci) & CEPH_CAP_FILE_CACHE) && 256 return ci->i_fscache_gen == ci->i_rdcache_gen;
264 (ci->i_fscache_gen == ci->i_rdcache_gen));
265} 257}
266 258
267 259
@@ -354,69 +346,27 @@ void ceph_invalidate_fscache_page(struct inode* inode, struct page *page)
354 346
355void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc) 347void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc)
356{ 348{
357 if (fsc->revalidate_wq)
358 destroy_workqueue(fsc->revalidate_wq);
359
360 fscache_relinquish_cookie(fsc->fscache, 0); 349 fscache_relinquish_cookie(fsc->fscache, 0);
361 fsc->fscache = NULL; 350 fsc->fscache = NULL;
362} 351}
363 352
364static void ceph_revalidate_work(struct work_struct *work) 353/*
365{ 354 * caller should hold CEPH_CAP_FILE_{RD,CACHE}
366 int issued; 355 */
367 u32 orig_gen; 356void ceph_fscache_revalidate_cookie(struct ceph_inode_info *ci)
368 struct ceph_inode_info *ci = container_of(work, struct ceph_inode_info,
369 i_revalidate_work);
370 struct inode *inode = &ci->vfs_inode;
371
372 spin_lock(&ci->i_ceph_lock);
373 issued = __ceph_caps_issued(ci, NULL);
374 orig_gen = ci->i_rdcache_gen;
375 spin_unlock(&ci->i_ceph_lock);
376
377 if (!(issued & CEPH_CAP_FILE_CACHE)) {
378 dout("revalidate_work lost cache before validation %p\n",
379 inode);
380 goto out;
381 }
382
383 if (!fscache_check_consistency(ci->fscache))
384 fscache_invalidate(ci->fscache);
385
386 spin_lock(&ci->i_ceph_lock);
387 /* Update the new valid generation (backwards sanity check too) */
388 if (orig_gen > ci->i_fscache_gen) {
389 ci->i_fscache_gen = orig_gen;
390 }
391 spin_unlock(&ci->i_ceph_lock);
392
393out:
394 iput(&ci->vfs_inode);
395}
396
397void ceph_queue_revalidate(struct inode *inode)
398{ 357{
399 struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb); 358 if (cache_valid(ci))
400 struct ceph_inode_info *ci = ceph_inode(inode);
401
402 if (fsc->revalidate_wq == NULL || ci->fscache == NULL)
403 return; 359 return;
404 360
405 ihold(inode); 361 /* resue i_truncate_mutex. There should be no pending
406 362 * truncate while the caller holds CEPH_CAP_FILE_RD */
407 if (queue_work(ceph_sb_to_client(inode->i_sb)->revalidate_wq, 363 mutex_lock(&ci->i_truncate_mutex);
408 &ci->i_revalidate_work)) { 364 if (!cache_valid(ci)) {
409 dout("ceph_queue_revalidate %p\n", inode); 365 if (fscache_check_consistency(ci->fscache))
410 } else { 366 fscache_invalidate(ci->fscache);
411 dout("ceph_queue_revalidate %p failed\n)", inode); 367 spin_lock(&ci->i_ceph_lock);
412 iput(inode); 368 ci->i_fscache_gen = ci->i_rdcache_gen;
369 spin_unlock(&ci->i_ceph_lock);
413 } 370 }
414} 371 mutex_unlock(&ci->i_truncate_mutex);
415
416void ceph_fscache_inode_init(struct ceph_inode_info *ci)
417{
418 ci->fscache = NULL;
419 /* The first load is verifed cookie open time */
420 ci->i_fscache_gen = 1;
421 INIT_WORK(&ci->i_revalidate_work, ceph_revalidate_work);
422} 372}
diff --git a/fs/ceph/cache.h b/fs/ceph/cache.h
index dfe9b5823bd3..7e72c7594f0c 100644
--- a/fs/ceph/cache.h
+++ b/fs/ceph/cache.h
@@ -34,10 +34,10 @@ void ceph_fscache_unregister(void);
34int ceph_fscache_register_fs(struct ceph_fs_client* fsc); 34int ceph_fscache_register_fs(struct ceph_fs_client* fsc);
35void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc); 35void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc);
36 36
37void ceph_fscache_inode_init(struct ceph_inode_info *ci);
38void ceph_fscache_register_inode_cookie(struct inode *inode); 37void ceph_fscache_register_inode_cookie(struct inode *inode);
39void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci); 38void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci);
40void ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp); 39void ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp);
40void ceph_fscache_revalidate_cookie(struct ceph_inode_info *ci);
41 41
42int ceph_readpage_from_fscache(struct inode *inode, struct page *page); 42int ceph_readpage_from_fscache(struct inode *inode, struct page *page);
43int ceph_readpages_from_fscache(struct inode *inode, 43int ceph_readpages_from_fscache(struct inode *inode,
@@ -46,7 +46,12 @@ int ceph_readpages_from_fscache(struct inode *inode,
46 unsigned *nr_pages); 46 unsigned *nr_pages);
47void ceph_readpage_to_fscache(struct inode *inode, struct page *page); 47void ceph_readpage_to_fscache(struct inode *inode, struct page *page);
48void ceph_invalidate_fscache_page(struct inode* inode, struct page *page); 48void ceph_invalidate_fscache_page(struct inode* inode, struct page *page);
49void ceph_queue_revalidate(struct inode *inode); 49
50static inline void ceph_fscache_inode_init(struct ceph_inode_info *ci)
51{
52 ci->fscache = NULL;
53 ci->i_fscache_gen = 0;
54}
50 55
51static inline void ceph_fscache_invalidate(struct inode *inode) 56static inline void ceph_fscache_invalidate(struct inode *inode)
52{ 57{
@@ -82,6 +87,11 @@ static inline void ceph_fscache_readpages_cancel(struct inode *inode,
82 return fscache_readpages_cancel(ci->fscache, pages); 87 return fscache_readpages_cancel(ci->fscache, pages);
83} 88}
84 89
90static inline void ceph_disable_fscache_readpage(struct ceph_inode_info *ci)
91{
92 ci->i_fscache_gen = ci->i_rdcache_gen - 1;
93}
94
85#else 95#else
86 96
87static inline int ceph_fscache_register(void) 97static inline int ceph_fscache_register(void)
@@ -119,6 +129,10 @@ static inline void ceph_fscache_file_set_cookie(struct inode *inode,
119{ 129{
120} 130}
121 131
132static inline void ceph_fscache_revalidate_cookie(struct ceph_inode_info *ci)
133{
134}
135
122static inline void ceph_fscache_uncache_page(struct inode *inode, 136static inline void ceph_fscache_uncache_page(struct inode *inode,
123 struct page *pages) 137 struct page *pages)
124{ 138{
@@ -167,7 +181,7 @@ static inline void ceph_fscache_readpages_cancel(struct inode *inode,
167{ 181{
168} 182}
169 183
170static inline void ceph_queue_revalidate(struct inode *inode) 184static inline void ceph_disable_fscache_readpage(struct ceph_inode_info *ci)
171{ 185{
172} 186}
173 187
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index 7bdf7d59a36d..6f60d0a3d0f9 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -2393,6 +2393,9 @@ again:
2393 snap_rwsem_locked = true; 2393 snap_rwsem_locked = true;
2394 } 2394 }
2395 *got = need | (have & want); 2395 *got = need | (have & want);
2396 if ((need & CEPH_CAP_FILE_RD) &&
2397 !(*got & CEPH_CAP_FILE_CACHE))
2398 ceph_disable_fscache_readpage(ci);
2396 __take_cap_refs(ci, *got, true); 2399 __take_cap_refs(ci, *got, true);
2397 ret = 1; 2400 ret = 1;
2398 } 2401 }
@@ -2554,6 +2557,9 @@ int ceph_get_caps(struct ceph_inode_info *ci, int need, int want,
2554 break; 2557 break;
2555 } 2558 }
2556 2559
2560 if ((_got & CEPH_CAP_FILE_RD) && (_got & CEPH_CAP_FILE_CACHE))
2561 ceph_fscache_revalidate_cookie(ci);
2562
2557 *got = _got; 2563 *got = _got;
2558 return 0; 2564 return 0;
2559} 2565}
@@ -2795,7 +2801,6 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
2795 bool writeback = false; 2801 bool writeback = false;
2796 bool queue_trunc = false; 2802 bool queue_trunc = false;
2797 bool queue_invalidate = false; 2803 bool queue_invalidate = false;
2798 bool queue_revalidate = false;
2799 bool deleted_inode = false; 2804 bool deleted_inode = false;
2800 bool fill_inline = false; 2805 bool fill_inline = false;
2801 2806
@@ -2837,8 +2842,6 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
2837 ci->i_rdcache_revoking = ci->i_rdcache_gen; 2842 ci->i_rdcache_revoking = ci->i_rdcache_gen;
2838 } 2843 }
2839 } 2844 }
2840
2841 ceph_fscache_invalidate(inode);
2842 } 2845 }
2843 2846
2844 /* side effects now are allowed */ 2847 /* side effects now are allowed */
@@ -2880,11 +2883,6 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
2880 } 2883 }
2881 } 2884 }
2882 2885
2883 /* Do we need to revalidate our fscache cookie. Don't bother on the
2884 * first cache cap as we already validate at cookie creation time. */
2885 if ((issued & CEPH_CAP_FILE_CACHE) && ci->i_rdcache_gen > 1)
2886 queue_revalidate = true;
2887
2888 if (newcaps & CEPH_CAP_ANY_RD) { 2886 if (newcaps & CEPH_CAP_ANY_RD) {
2889 /* ctime/mtime/atime? */ 2887 /* ctime/mtime/atime? */
2890 ceph_decode_timespec(&mtime, &grant->mtime); 2888 ceph_decode_timespec(&mtime, &grant->mtime);
@@ -2995,8 +2993,6 @@ static void handle_cap_grant(struct ceph_mds_client *mdsc,
2995 2993
2996 if (queue_trunc) 2994 if (queue_trunc)
2997 ceph_queue_vmtruncate(inode); 2995 ceph_queue_vmtruncate(inode);
2998 else if (queue_revalidate)
2999 ceph_queue_revalidate(inode);
3000 2996
3001 if (writeback) 2997 if (writeback)
3002 /* 2998 /*
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 0130a8592191..0168b49fb6ad 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -103,7 +103,6 @@ struct ceph_fs_client {
103 103
104#ifdef CONFIG_CEPH_FSCACHE 104#ifdef CONFIG_CEPH_FSCACHE
105 struct fscache_cookie *fscache; 105 struct fscache_cookie *fscache;
106 struct workqueue_struct *revalidate_wq;
107#endif 106#endif
108}; 107};
109 108
@@ -360,8 +359,7 @@ struct ceph_inode_info {
360 359
361#ifdef CONFIG_CEPH_FSCACHE 360#ifdef CONFIG_CEPH_FSCACHE
362 struct fscache_cookie *fscache; 361 struct fscache_cookie *fscache;
363 u32 i_fscache_gen; /* sequence, for delayed fscache validate */ 362 u32 i_fscache_gen;
364 struct work_struct i_revalidate_work;
365#endif 363#endif
366 struct inode vfs_inode; /* at end */ 364 struct inode vfs_inode; /* at end */
367}; 365};