aboutsummaryrefslogtreecommitdiffstats
path: root/fs/dcache.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-08 16:26:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-08 16:26:18 -0400
commit8aab6a27332bbf2abfcb35224738394e784d940b (patch)
tree2ab91f09238c948a18314487ec6a3574cd78ea32 /fs/dcache.c
parentb409624ad5a99c2e84df6657bd0f7931ac470d2d (diff)
vfs: reorganize dput() memory accesses
This is me being a bit OCD after all the dentry optimization work this merge window: profiles end up showing 'dput()' as a rather expensive operation, and there were two unrelated bad reasons for that. The first reason was reading d_lockref.count for debugging purposes, which touches the lockref cacheline (for reads) before really need to. More importantly, the debugging test in question is _wrong_, and has hidden bugs. It's true that we can only sleep when the count goes down to zero, but the test as-is hides the much more subtle bug that happens if we race with somebody else deleting the file. Anyway we _will_ touch that cacheline, but let's do it for a write and in the right routine (ie in "lockref_put_or_lock()") which annotates the costs better. So remove the misleading debug code. The other was an unnecessary access to the cacheline that contains the d_lru list, just to check whether we already were on the LRU list or not. This is exactly what we have d_flags for, so that we can avoid touching extra cache lines for the common case. So just add another bit for "is this dentry on the LRU". Finally, mark the tests properly likely/unlikely, so that the common fast-paths are dense in the instruction stream. This makes the profiles look much saner. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/dcache.c')
-rw-r--r--fs/dcache.c20
1 files changed, 10 insertions, 10 deletions
diff --git a/fs/dcache.c b/fs/dcache.c
index 761e31bacbc2..bf3c4f9569eb 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -308,8 +308,9 @@ static void dentry_unlink_inode(struct dentry * dentry)
308 */ 308 */
309static void dentry_lru_add(struct dentry *dentry) 309static void dentry_lru_add(struct dentry *dentry)
310{ 310{
311 if (list_empty(&dentry->d_lru)) { 311 if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST))) {
312 spin_lock(&dcache_lru_lock); 312 spin_lock(&dcache_lru_lock);
313 dentry->d_flags |= DCACHE_LRU_LIST;
313 list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); 314 list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
314 dentry->d_sb->s_nr_dentry_unused++; 315 dentry->d_sb->s_nr_dentry_unused++;
315 dentry_stat.nr_unused++; 316 dentry_stat.nr_unused++;
@@ -320,7 +321,7 @@ static void dentry_lru_add(struct dentry *dentry)
320static void __dentry_lru_del(struct dentry *dentry) 321static void __dentry_lru_del(struct dentry *dentry)
321{ 322{
322 list_del_init(&dentry->d_lru); 323 list_del_init(&dentry->d_lru);
323 dentry->d_flags &= ~DCACHE_SHRINK_LIST; 324 dentry->d_flags &= ~(DCACHE_SHRINK_LIST | DCACHE_LRU_LIST);
324 dentry->d_sb->s_nr_dentry_unused--; 325 dentry->d_sb->s_nr_dentry_unused--;
325 dentry_stat.nr_unused--; 326 dentry_stat.nr_unused--;
326} 327}
@@ -341,6 +342,7 @@ static void dentry_lru_move_list(struct dentry *dentry, struct list_head *list)
341{ 342{
342 spin_lock(&dcache_lru_lock); 343 spin_lock(&dcache_lru_lock);
343 if (list_empty(&dentry->d_lru)) { 344 if (list_empty(&dentry->d_lru)) {
345 dentry->d_flags |= DCACHE_LRU_LIST;
344 list_add_tail(&dentry->d_lru, list); 346 list_add_tail(&dentry->d_lru, list);
345 dentry->d_sb->s_nr_dentry_unused++; 347 dentry->d_sb->s_nr_dentry_unused++;
346 dentry_stat.nr_unused++; 348 dentry_stat.nr_unused++;
@@ -509,24 +511,22 @@ relock:
509 */ 511 */
510void dput(struct dentry *dentry) 512void dput(struct dentry *dentry)
511{ 513{
512 if (!dentry) 514 if (unlikely(!dentry))
513 return; 515 return;
514 516
515repeat: 517repeat:
516 if (dentry->d_lockref.count == 1)
517 might_sleep();
518 if (lockref_put_or_lock(&dentry->d_lockref)) 518 if (lockref_put_or_lock(&dentry->d_lockref))
519 return; 519 return;
520 520
521 if (dentry->d_flags & DCACHE_OP_DELETE) { 521 /* Unreachable? Get rid of it */
522 if (unlikely(d_unhashed(dentry)))
523 goto kill_it;
524
525 if (unlikely(dentry->d_flags & DCACHE_OP_DELETE)) {
522 if (dentry->d_op->d_delete(dentry)) 526 if (dentry->d_op->d_delete(dentry))
523 goto kill_it; 527 goto kill_it;
524 } 528 }
525 529
526 /* Unreachable? Get rid of it */
527 if (d_unhashed(dentry))
528 goto kill_it;
529
530 dentry->d_flags |= DCACHE_REFERENCED; 530 dentry->d_flags |= DCACHE_REFERENCED;
531 dentry_lru_add(dentry); 531 dentry_lru_add(dentry);
532 532