Commit 98474236f72e5a8b89c14cd7c74f0bb77a4b1a99

Authored by Waiman Long
Committed by Linus Torvalds
1 parent 0f8f2aaaab

vfs: make the dentry cache use the lockref infrastructure

This just replaces the dentry count/lock combination with the lockref
structure that contains both a count and a spinlock, and does the
mechanical conversion to use the lockref infrastructure.

There are no semantic changes here, it's purely syntactic.  The
reference lockref implementation uses the spinlock exactly the same way
that the old dcache code did, and the bulk of this patch is just
expanding the internal "d_count" use in the dcache code to use
"d_lockref.count" instead.

This is purely preparation for the real change to make the reference
count updates be lockless during the 3.12 merge window.

[ As with the previous commit, this is a rewritten version of a concept
  originally from Waiman, so credit goes to him, blame for any errors
  goes to me.

  Waiman's patch had some semantic differences for taking advantage of
  the lockless update in dget_parent(), while this patch is
  intentionally a pure search-and-replace change with no semantic
  changes.     - Linus ]

Signed-off-by: Waiman Long <Waiman.Long@hp.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 3 changed files with 35 additions and 47 deletions Side-by-side Diff

... ... @@ -229,7 +229,7 @@
229 229 */
230 230 static void d_free(struct dentry *dentry)
231 231 {
232   - BUG_ON(dentry->d_count);
  232 + BUG_ON(dentry->d_lockref.count);
233 233 this_cpu_dec(nr_dentry);
234 234 if (dentry->d_op && dentry->d_op->d_release)
235 235 dentry->d_op->d_release(dentry);
... ... @@ -467,7 +467,7 @@
467 467 }
468 468  
469 469 if (ref)
470   - dentry->d_count--;
  470 + dentry->d_lockref.count--;
471 471 /*
472 472 * inform the fs via d_prune that this dentry is about to be
473 473 * unhashed and destroyed.
474 474  
475 475  
... ... @@ -513,15 +513,10 @@
513 513 return;
514 514  
515 515 repeat:
516   - if (dentry->d_count == 1)
  516 + if (dentry->d_lockref.count == 1)
517 517 might_sleep();
518   - spin_lock(&dentry->d_lock);
519   - BUG_ON(!dentry->d_count);
520   - if (dentry->d_count > 1) {
521   - dentry->d_count--;
522   - spin_unlock(&dentry->d_lock);
  518 + if (lockref_put_or_lock(&dentry->d_lockref))
523 519 return;
524   - }
525 520  
526 521 if (dentry->d_flags & DCACHE_OP_DELETE) {
527 522 if (dentry->d_op->d_delete(dentry))
... ... @@ -535,7 +530,7 @@
535 530 dentry->d_flags |= DCACHE_REFERENCED;
536 531 dentry_lru_add(dentry);
537 532  
538   - dentry->d_count--;
  533 + dentry->d_lockref.count--;
539 534 spin_unlock(&dentry->d_lock);
540 535 return;
541 536  
... ... @@ -590,7 +585,7 @@
590 585 * We also need to leave mountpoints alone,
591 586 * directory or not.
592 587 */
593   - if (dentry->d_count > 1 && dentry->d_inode) {
  588 + if (dentry->d_lockref.count > 1 && dentry->d_inode) {
594 589 if (S_ISDIR(dentry->d_inode->i_mode) || d_mountpoint(dentry)) {
595 590 spin_unlock(&dentry->d_lock);
596 591 return -EBUSY;
597 592  
... ... @@ -606,14 +601,12 @@
606 601 /* This must be called with d_lock held */
607 602 static inline void __dget_dlock(struct dentry *dentry)
608 603 {
609   - dentry->d_count++;
  604 + dentry->d_lockref.count++;
610 605 }
611 606  
612 607 static inline void __dget(struct dentry *dentry)
613 608 {
614   - spin_lock(&dentry->d_lock);
615   - __dget_dlock(dentry);
616   - spin_unlock(&dentry->d_lock);
  609 + lockref_get(&dentry->d_lockref);
617 610 }
618 611  
619 612 struct dentry *dget_parent(struct dentry *dentry)
... ... @@ -634,8 +627,8 @@
634 627 goto repeat;
635 628 }
636 629 rcu_read_unlock();
637   - BUG_ON(!ret->d_count);
638   - ret->d_count++;
  630 + BUG_ON(!ret->d_lockref.count);
  631 + ret->d_lockref.count++;
639 632 spin_unlock(&ret->d_lock);
640 633 return ret;
641 634 }
... ... @@ -718,7 +711,7 @@
718 711 spin_lock(&inode->i_lock);
719 712 hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
720 713 spin_lock(&dentry->d_lock);
721   - if (!dentry->d_count) {
  714 + if (!dentry->d_lockref.count) {
722 715 __dget_dlock(dentry);
723 716 __d_drop(dentry);
724 717 spin_unlock(&dentry->d_lock);
725 718  
... ... @@ -763,12 +756,8 @@
763 756 /* Prune ancestors. */
764 757 dentry = parent;
765 758 while (dentry) {
766   - spin_lock(&dentry->d_lock);
767   - if (dentry->d_count > 1) {
768   - dentry->d_count--;
769   - spin_unlock(&dentry->d_lock);
  759 + if (lockref_put_or_lock(&dentry->d_lockref))
770 760 return;
771   - }
772 761 dentry = dentry_kill(dentry, 1);
773 762 }
774 763 }
... ... @@ -793,7 +782,7 @@
793 782 * the LRU because of laziness during lookup. Do not free
794 783 * it - just keep it off the LRU list.
795 784 */
796   - if (dentry->d_count) {
  785 + if (dentry->d_lockref.count) {
797 786 dentry_lru_del(dentry);
798 787 spin_unlock(&dentry->d_lock);
799 788 continue;
... ... @@ -913,7 +902,7 @@
913 902 dentry_lru_del(dentry);
914 903 __d_shrink(dentry);
915 904  
916   - if (dentry->d_count != 0) {
  905 + if (dentry->d_lockref.count != 0) {
917 906 printk(KERN_ERR
918 907 "BUG: Dentry %p{i=%lx,n=%s}"
919 908 " still in use (%d)"
... ... @@ -922,7 +911,7 @@
922 911 dentry->d_inode ?
923 912 dentry->d_inode->i_ino : 0UL,
924 913 dentry->d_name.name,
925   - dentry->d_count,
  914 + dentry->d_lockref.count,
926 915 dentry->d_sb->s_type->name,
927 916 dentry->d_sb->s_id);
928 917 BUG();
... ... @@ -933,7 +922,7 @@
933 922 list_del(&dentry->d_u.d_child);
934 923 } else {
935 924 parent = dentry->d_parent;
936   - parent->d_count--;
  925 + parent->d_lockref.count--;
937 926 list_del(&dentry->d_u.d_child);
938 927 }
939 928  
... ... @@ -981,7 +970,7 @@
981 970  
982 971 dentry = sb->s_root;
983 972 sb->s_root = NULL;
984   - dentry->d_count--;
  973 + dentry->d_lockref.count--;
985 974 shrink_dcache_for_umount_subtree(dentry);
986 975  
987 976 while (!hlist_bl_empty(&sb->s_anon)) {
... ... @@ -1147,7 +1136,7 @@
1147 1136 * loop in shrink_dcache_parent() might not make any progress
1148 1137 * and loop forever.
1149 1138 */
1150   - if (dentry->d_count) {
  1139 + if (dentry->d_lockref.count) {
1151 1140 dentry_lru_del(dentry);
1152 1141 } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
1153 1142 dentry_lru_move_list(dentry, dispose);
... ... @@ -1269,7 +1258,7 @@
1269 1258 smp_wmb();
1270 1259 dentry->d_name.name = dname;
1271 1260  
1272   - dentry->d_count = 1;
  1261 + dentry->d_lockref.count = 1;
1273 1262 dentry->d_flags = 0;
1274 1263 spin_lock_init(&dentry->d_lock);
1275 1264 seqcount_init(&dentry->d_seq);
... ... @@ -1970,7 +1959,7 @@
1970 1959 goto next;
1971 1960 }
1972 1961  
1973   - dentry->d_count++;
  1962 + dentry->d_lockref.count++;
1974 1963 found = dentry;
1975 1964 spin_unlock(&dentry->d_lock);
1976 1965 break;
... ... @@ -2069,7 +2058,7 @@
2069 2058 spin_lock(&dentry->d_lock);
2070 2059 inode = dentry->d_inode;
2071 2060 isdir = S_ISDIR(inode->i_mode);
2072   - if (dentry->d_count == 1) {
  2061 + if (dentry->d_lockref.count == 1) {
2073 2062 if (!spin_trylock(&inode->i_lock)) {
2074 2063 spin_unlock(&dentry->d_lock);
2075 2064 cpu_relax();
... ... @@ -2948,7 +2937,7 @@
2948 2937 }
2949 2938 if (!(dentry->d_flags & DCACHE_GENOCIDE)) {
2950 2939 dentry->d_flags |= DCACHE_GENOCIDE;
2951   - dentry->d_count--;
  2940 + dentry->d_lockref.count--;
2952 2941 }
2953 2942 spin_unlock(&dentry->d_lock);
2954 2943 }
... ... @@ -2956,7 +2945,7 @@
2956 2945 struct dentry *child = this_parent;
2957 2946 if (!(this_parent->d_flags & DCACHE_GENOCIDE)) {
2958 2947 this_parent->d_flags |= DCACHE_GENOCIDE;
2959   - this_parent->d_count--;
  2948 + this_parent->d_lockref.count--;
2960 2949 }
2961 2950 this_parent = try_to_ascend(this_parent, locked, seq);
2962 2951 if (!this_parent)
... ... @@ -536,8 +536,8 @@
536 536 * a reference at this point.
537 537 */
538 538 BUG_ON(!IS_ROOT(dentry) && dentry->d_parent != parent);
539   - BUG_ON(!parent->d_count);
540   - parent->d_count++;
  539 + BUG_ON(!parent->d_lockref.count);
  540 + parent->d_lockref.count++;
541 541 spin_unlock(&dentry->d_lock);
542 542 }
543 543 spin_unlock(&parent->d_lock);
... ... @@ -3327,7 +3327,7 @@
3327 3327 {
3328 3328 shrink_dcache_parent(dentry);
3329 3329 spin_lock(&dentry->d_lock);
3330   - if (dentry->d_count == 1)
  3330 + if (dentry->d_lockref.count == 1)
3331 3331 __d_drop(dentry);
3332 3332 spin_unlock(&dentry->d_lock);
3333 3333 }
include/linux/dcache.h
... ... @@ -9,6 +9,7 @@
9 9 #include <linux/seqlock.h>
10 10 #include <linux/cache.h>
11 11 #include <linux/rcupdate.h>
  12 +#include <linux/lockref.h>
12 13  
13 14 struct nameidata;
14 15 struct path;
... ... @@ -100,6 +101,8 @@
100 101 # endif
101 102 #endif
102 103  
  104 +#define d_lock d_lockref.lock
  105 +
103 106 struct dentry {
104 107 /* RCU lookup touched fields */
105 108 unsigned int d_flags; /* protected by d_lock */
... ... @@ -112,8 +115,7 @@
112 115 unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
113 116  
114 117 /* Ref lookup also touches following */
115   - unsigned int d_count; /* protected by d_lock */
116   - spinlock_t d_lock; /* per dentry lock */
  118 + struct lockref d_lockref; /* per-dentry lock and refcount */
117 119 const struct dentry_operations *d_op;
118 120 struct super_block *d_sb; /* The root of the dentry tree */
119 121 unsigned long d_time; /* used by d_revalidate */
... ... @@ -318,7 +320,7 @@
318 320 assert_spin_locked(&dentry->d_lock);
319 321 if (!read_seqcount_retry(&dentry->d_seq, seq)) {
320 322 ret = 1;
321   - dentry->d_count++;
  323 + dentry->d_lockref.count++;
322 324 }
323 325  
324 326 return ret;
... ... @@ -326,7 +328,7 @@
326 328  
327 329 static inline unsigned d_count(const struct dentry *dentry)
328 330 {
329   - return dentry->d_count;
  331 + return dentry->d_lockref.count;
330 332 }
331 333  
332 334 /* validate "insecure" dentry pointer */
333 335  
... ... @@ -357,17 +359,14 @@
357 359 static inline struct dentry *dget_dlock(struct dentry *dentry)
358 360 {
359 361 if (dentry)
360   - dentry->d_count++;
  362 + dentry->d_lockref.count++;
361 363 return dentry;
362 364 }
363 365  
364 366 static inline struct dentry *dget(struct dentry *dentry)
365 367 {
366   - if (dentry) {
367   - spin_lock(&dentry->d_lock);
368   - dget_dlock(dentry);
369   - spin_unlock(&dentry->d_lock);
370   - }
  368 + if (dentry)
  369 + lockref_get(&dentry->d_lockref);
371 370 return dentry;
372 371 }
373 372