Skip to content

Commit 9847423

Browse files
longman88torvalds
authored andcommitted
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>
1 parent 0f8f2aa commit 9847423

File tree

3 files changed

+35
-47
lines changed

3 files changed

+35
-47
lines changed

fs/dcache.c

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ static void __d_free(struct rcu_head *head)
229229
*/
230230
static void d_free(struct dentry *dentry)
231231
{
232-
BUG_ON(dentry->d_count);
232+
BUG_ON(dentry->d_lockref.count);
233233
this_cpu_dec(nr_dentry);
234234
if (dentry->d_op && dentry->d_op->d_release)
235235
dentry->d_op->d_release(dentry);
@@ -467,7 +467,7 @@ static inline struct dentry *dentry_kill(struct dentry *dentry, int ref)
467467
}
468468

469469
if (ref)
470-
dentry->d_count--;
470+
dentry->d_lockref.count--;
471471
/*
472472
* inform the fs via d_prune that this dentry is about to be
473473
* unhashed and destroyed.
@@ -513,15 +513,10 @@ void dput(struct dentry *dentry)
513513
return;
514514

515515
repeat:
516-
if (dentry->d_count == 1)
516+
if (dentry->d_lockref.count == 1)
517517
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))
523519
return;
524-
}
525520

526521
if (dentry->d_flags & DCACHE_OP_DELETE) {
527522
if (dentry->d_op->d_delete(dentry))
@@ -535,7 +530,7 @@ void dput(struct dentry *dentry)
535530
dentry->d_flags |= DCACHE_REFERENCED;
536531
dentry_lru_add(dentry);
537532

538-
dentry->d_count--;
533+
dentry->d_lockref.count--;
539534
spin_unlock(&dentry->d_lock);
540535
return;
541536

@@ -590,7 +585,7 @@ int d_invalidate(struct dentry * dentry)
590585
* We also need to leave mountpoints alone,
591586
* directory or not.
592587
*/
593-
if (dentry->d_count > 1 && dentry->d_inode) {
588+
if (dentry->d_lockref.count > 1 && dentry->d_inode) {
594589
if (S_ISDIR(dentry->d_inode->i_mode) || d_mountpoint(dentry)) {
595590
spin_unlock(&dentry->d_lock);
596591
return -EBUSY;
@@ -606,14 +601,12 @@ EXPORT_SYMBOL(d_invalidate);
606601
/* This must be called with d_lock held */
607602
static inline void __dget_dlock(struct dentry *dentry)
608603
{
609-
dentry->d_count++;
604+
dentry->d_lockref.count++;
610605
}
611606

612607
static inline void __dget(struct dentry *dentry)
613608
{
614-
spin_lock(&dentry->d_lock);
615-
__dget_dlock(dentry);
616-
spin_unlock(&dentry->d_lock);
609+
lockref_get(&dentry->d_lockref);
617610
}
618611

619612
struct dentry *dget_parent(struct dentry *dentry)
@@ -634,8 +627,8 @@ struct dentry *dget_parent(struct dentry *dentry)
634627
goto repeat;
635628
}
636629
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++;
639632
spin_unlock(&ret->d_lock);
640633
return ret;
641634
}
@@ -718,7 +711,7 @@ void d_prune_aliases(struct inode *inode)
718711
spin_lock(&inode->i_lock);
719712
hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
720713
spin_lock(&dentry->d_lock);
721-
if (!dentry->d_count) {
714+
if (!dentry->d_lockref.count) {
722715
__dget_dlock(dentry);
723716
__d_drop(dentry);
724717
spin_unlock(&dentry->d_lock);
@@ -763,12 +756,8 @@ static void try_prune_one_dentry(struct dentry *dentry)
763756
/* Prune ancestors. */
764757
dentry = parent;
765758
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))
770760
return;
771-
}
772761
dentry = dentry_kill(dentry, 1);
773762
}
774763
}
@@ -793,7 +782,7 @@ static void shrink_dentry_list(struct list_head *list)
793782
* the LRU because of laziness during lookup. Do not free
794783
* it - just keep it off the LRU list.
795784
*/
796-
if (dentry->d_count) {
785+
if (dentry->d_lockref.count) {
797786
dentry_lru_del(dentry);
798787
spin_unlock(&dentry->d_lock);
799788
continue;
@@ -913,7 +902,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
913902
dentry_lru_del(dentry);
914903
__d_shrink(dentry);
915904

916-
if (dentry->d_count != 0) {
905+
if (dentry->d_lockref.count != 0) {
917906
printk(KERN_ERR
918907
"BUG: Dentry %p{i=%lx,n=%s}"
919908
" still in use (%d)"
@@ -922,7 +911,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
922911
dentry->d_inode ?
923912
dentry->d_inode->i_ino : 0UL,
924913
dentry->d_name.name,
925-
dentry->d_count,
914+
dentry->d_lockref.count,
926915
dentry->d_sb->s_type->name,
927916
dentry->d_sb->s_id);
928917
BUG();
@@ -933,7 +922,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
933922
list_del(&dentry->d_u.d_child);
934923
} else {
935924
parent = dentry->d_parent;
936-
parent->d_count--;
925+
parent->d_lockref.count--;
937926
list_del(&dentry->d_u.d_child);
938927
}
939928

@@ -981,7 +970,7 @@ void shrink_dcache_for_umount(struct super_block *sb)
981970

982971
dentry = sb->s_root;
983972
sb->s_root = NULL;
984-
dentry->d_count--;
973+
dentry->d_lockref.count--;
985974
shrink_dcache_for_umount_subtree(dentry);
986975

987976
while (!hlist_bl_empty(&sb->s_anon)) {
@@ -1147,7 +1136,7 @@ static int select_parent(struct dentry *parent, struct list_head *dispose)
11471136
* loop in shrink_dcache_parent() might not make any progress
11481137
* and loop forever.
11491138
*/
1150-
if (dentry->d_count) {
1139+
if (dentry->d_lockref.count) {
11511140
dentry_lru_del(dentry);
11521141
} else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
11531142
dentry_lru_move_list(dentry, dispose);
@@ -1269,7 +1258,7 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
12691258
smp_wmb();
12701259
dentry->d_name.name = dname;
12711260

1272-
dentry->d_count = 1;
1261+
dentry->d_lockref.count = 1;
12731262
dentry->d_flags = 0;
12741263
spin_lock_init(&dentry->d_lock);
12751264
seqcount_init(&dentry->d_seq);
@@ -1970,7 +1959,7 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
19701959
goto next;
19711960
}
19721961

1973-
dentry->d_count++;
1962+
dentry->d_lockref.count++;
19741963
found = dentry;
19751964
spin_unlock(&dentry->d_lock);
19761965
break;
@@ -2069,7 +2058,7 @@ void d_delete(struct dentry * dentry)
20692058
spin_lock(&dentry->d_lock);
20702059
inode = dentry->d_inode;
20712060
isdir = S_ISDIR(inode->i_mode);
2072-
if (dentry->d_count == 1) {
2061+
if (dentry->d_lockref.count == 1) {
20732062
if (!spin_trylock(&inode->i_lock)) {
20742063
spin_unlock(&dentry->d_lock);
20752064
cpu_relax();
@@ -2948,15 +2937,15 @@ void d_genocide(struct dentry *root)
29482937
}
29492938
if (!(dentry->d_flags & DCACHE_GENOCIDE)) {
29502939
dentry->d_flags |= DCACHE_GENOCIDE;
2951-
dentry->d_count--;
2940+
dentry->d_lockref.count--;
29522941
}
29532942
spin_unlock(&dentry->d_lock);
29542943
}
29552944
if (this_parent != root) {
29562945
struct dentry *child = this_parent;
29572946
if (!(this_parent->d_flags & DCACHE_GENOCIDE)) {
29582947
this_parent->d_flags |= DCACHE_GENOCIDE;
2959-
this_parent->d_count--;
2948+
this_parent->d_lockref.count--;
29602949
}
29612950
this_parent = try_to_ascend(this_parent, locked, seq);
29622951
if (!this_parent)

fs/namei.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,8 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry)
536536
* a reference at this point.
537537
*/
538538
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++;
541541
spin_unlock(&dentry->d_lock);
542542
}
543543
spin_unlock(&parent->d_lock);
@@ -3327,7 +3327,7 @@ void dentry_unhash(struct dentry *dentry)
33273327
{
33283328
shrink_dcache_parent(dentry);
33293329
spin_lock(&dentry->d_lock);
3330-
if (dentry->d_count == 1)
3330+
if (dentry->d_lockref.count == 1)
33313331
__d_drop(dentry);
33323332
spin_unlock(&dentry->d_lock);
33333333
}

include/linux/dcache.h

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <linux/seqlock.h>
1010
#include <linux/cache.h>
1111
#include <linux/rcupdate.h>
12+
#include <linux/lockref.h>
1213

1314
struct nameidata;
1415
struct path;
@@ -100,6 +101,8 @@ extern unsigned int full_name_hash(const unsigned char *, unsigned int);
100101
# endif
101102
#endif
102103

104+
#define d_lock d_lockref.lock
105+
103106
struct dentry {
104107
/* RCU lookup touched fields */
105108
unsigned int d_flags; /* protected by d_lock */
@@ -112,8 +115,7 @@ struct dentry {
112115
unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
113116

114117
/* 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 */
117119
const struct dentry_operations *d_op;
118120
struct super_block *d_sb; /* The root of the dentry tree */
119121
unsigned long d_time; /* used by d_revalidate */
@@ -318,15 +320,15 @@ static inline int __d_rcu_to_refcount(struct dentry *dentry, unsigned seq)
318320
assert_spin_locked(&dentry->d_lock);
319321
if (!read_seqcount_retry(&dentry->d_seq, seq)) {
320322
ret = 1;
321-
dentry->d_count++;
323+
dentry->d_lockref.count++;
322324
}
323325

324326
return ret;
325327
}
326328

327329
static inline unsigned d_count(const struct dentry *dentry)
328330
{
329-
return dentry->d_count;
331+
return dentry->d_lockref.count;
330332
}
331333

332334
/* validate "insecure" dentry pointer */
@@ -357,17 +359,14 @@ extern char *dentry_path(struct dentry *, char *, int);
357359
static inline struct dentry *dget_dlock(struct dentry *dentry)
358360
{
359361
if (dentry)
360-
dentry->d_count++;
362+
dentry->d_lockref.count++;
361363
return dentry;
362364
}
363365

364366
static inline struct dentry *dget(struct dentry *dentry)
365367
{
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);
371370
return dentry;
372371
}
373372

0 commit comments

Comments
 (0)