ceph: fix rdcache_gen usage and invalidate

We used to use rdcache_gen to indicate whether we "might" have cached
pages. Now we just look at the mapping to determine that. However, some
old behavior remains from that transition.

First, rdcache_gen == 0 no longer means we have no pages. That can happen
at any time (presumably when we carry FILE_CACHE). We should not reset it
to zero, and we should not check that it is zero.

That means that the only purpose for rdcache_revoking is to resolve races
between new issues of FILE_CACHE and an async invalidate. If they are
equal, we should invalidate. On success, we decrement rdcache_revoking,
so that it is no longer equal to rdcache_gen. Similarly, if we success
in doing a sync invalidate, set revoking = gen - 1. (This is a small
optimization to avoid doing unnecessary invalidate work and does not
affect correctness.)

Signed-off-by: Sage Weil <sage@newdream.net>

Sage Weil cd045cb4 feb4cc9b

+10 -14
+2 -2
fs/ceph/caps.c
··· 1430 invalidating_gen == ci->i_rdcache_gen) { 1431 /* success. */ 1432 dout("try_nonblocking_invalidate %p success\n", inode); 1433 - ci->i_rdcache_gen = 0; 1434 - ci->i_rdcache_revoking = 0; 1435 return 0; 1436 } 1437 dout("try_nonblocking_invalidate %p failed\n", inode);
··· 1430 invalidating_gen == ci->i_rdcache_gen) { 1431 /* success. */ 1432 dout("try_nonblocking_invalidate %p success\n", inode); 1433 + /* save any racing async invalidate some trouble */ 1434 + ci->i_rdcache_revoking = ci->i_rdcache_gen - 1; 1435 return 0; 1436 } 1437 dout("try_nonblocking_invalidate %p failed\n", inode);
+7 -9
fs/ceph/inode.c
··· 1394 spin_lock(&inode->i_lock); 1395 dout("invalidate_pages %p gen %d revoking %d\n", inode, 1396 ci->i_rdcache_gen, ci->i_rdcache_revoking); 1397 - if (ci->i_rdcache_gen == 0 || 1398 - ci->i_rdcache_revoking != ci->i_rdcache_gen) { 1399 - BUG_ON(ci->i_rdcache_revoking > ci->i_rdcache_gen); 1400 /* nevermind! */ 1401 - ci->i_rdcache_revoking = 0; 1402 spin_unlock(&inode->i_lock); 1403 goto out; 1404 } ··· 1405 ceph_invalidate_nondirty_pages(inode->i_mapping); 1406 1407 spin_lock(&inode->i_lock); 1408 - if (orig_gen == ci->i_rdcache_gen) { 1409 dout("invalidate_pages %p gen %d successful\n", inode, 1410 ci->i_rdcache_gen); 1411 - ci->i_rdcache_gen = 0; 1412 - ci->i_rdcache_revoking = 0; 1413 check = 1; 1414 } else { 1415 - dout("invalidate_pages %p gen %d raced, gen now %d\n", 1416 - inode, orig_gen, ci->i_rdcache_gen); 1417 } 1418 spin_unlock(&inode->i_lock); 1419
··· 1394 spin_lock(&inode->i_lock); 1395 dout("invalidate_pages %p gen %d revoking %d\n", inode, 1396 ci->i_rdcache_gen, ci->i_rdcache_revoking); 1397 + if (ci->i_rdcache_revoking != ci->i_rdcache_gen) { 1398 /* nevermind! */ 1399 spin_unlock(&inode->i_lock); 1400 goto out; 1401 } ··· 1408 ceph_invalidate_nondirty_pages(inode->i_mapping); 1409 1410 spin_lock(&inode->i_lock); 1411 + if (orig_gen == ci->i_rdcache_gen && 1412 + orig_gen == ci->i_rdcache_revoking) { 1413 dout("invalidate_pages %p gen %d successful\n", inode, 1414 ci->i_rdcache_gen); 1415 + ci->i_rdcache_revoking--; 1416 check = 1; 1417 } else { 1418 + dout("invalidate_pages %p gen %d raced, now %d revoking %d\n", 1419 + inode, orig_gen, ci->i_rdcache_gen, 1420 + ci->i_rdcache_revoking); 1421 } 1422 spin_unlock(&inode->i_lock); 1423
+1 -3
fs/ceph/super.h
··· 293 int i_rd_ref, i_rdcache_ref, i_wr_ref; 294 int i_wrbuffer_ref, i_wrbuffer_ref_head; 295 u32 i_shared_gen; /* increment each time we get FILE_SHARED */ 296 - u32 i_rdcache_gen; /* we increment this each time we get 297 - FILE_CACHE. If it's non-zero, we 298 - _may_ have cached pages. */ 299 u32 i_rdcache_revoking; /* RDCACHE gen to async invalidate, if any */ 300 301 struct list_head i_unsafe_writes; /* uncommitted sync writes */
··· 293 int i_rd_ref, i_rdcache_ref, i_wr_ref; 294 int i_wrbuffer_ref, i_wrbuffer_ref_head; 295 u32 i_shared_gen; /* increment each time we get FILE_SHARED */ 296 + u32 i_rdcache_gen; /* incremented each time we get FILE_CACHE. */ 297 u32 i_rdcache_revoking; /* RDCACHE gen to async invalidate, if any */ 298 299 struct list_head i_unsafe_writes; /* uncommitted sync writes */