Skip to content

Commit

Permalink
vfs: make the dentry cache use the lockref infrastructure
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
longman88 authored and torvalds committed Aug 29, 2013
1 parent 0f8f2aa commit 9847423
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 47 deletions.
57 changes: 23 additions & 34 deletions fs/dcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ static void __d_free(struct rcu_head *head)
*/
static void d_free(struct dentry *dentry)
{
BUG_ON(dentry->d_count);
BUG_ON(dentry->d_lockref.count);
this_cpu_dec(nr_dentry);
if (dentry->d_op && dentry->d_op->d_release)
dentry->d_op->d_release(dentry);
Expand Down Expand Up @@ -467,7 +467,7 @@ static inline struct dentry *dentry_kill(struct dentry *dentry, int ref)
}

if (ref)
dentry->d_count--;
dentry->d_lockref.count--;
/*
* inform the fs via d_prune that this dentry is about to be
* unhashed and destroyed.
Expand Down Expand Up @@ -513,15 +513,10 @@ void dput(struct dentry *dentry)
return;

repeat:
if (dentry->d_count == 1)
if (dentry->d_lockref.count == 1)
might_sleep();
spin_lock(&dentry->d_lock);
BUG_ON(!dentry->d_count);
if (dentry->d_count > 1) {
dentry->d_count--;
spin_unlock(&dentry->d_lock);
if (lockref_put_or_lock(&dentry->d_lockref))
return;
}

if (dentry->d_flags & DCACHE_OP_DELETE) {
if (dentry->d_op->d_delete(dentry))
Expand All @@ -535,7 +530,7 @@ void dput(struct dentry *dentry)
dentry->d_flags |= DCACHE_REFERENCED;
dentry_lru_add(dentry);

dentry->d_count--;
dentry->d_lockref.count--;
spin_unlock(&dentry->d_lock);
return;

Expand Down Expand Up @@ -590,7 +585,7 @@ int d_invalidate(struct dentry * dentry)
* We also need to leave mountpoints alone,
* directory or not.
*/
if (dentry->d_count > 1 && dentry->d_inode) {
if (dentry->d_lockref.count > 1 && dentry->d_inode) {
if (S_ISDIR(dentry->d_inode->i_mode) || d_mountpoint(dentry)) {
spin_unlock(&dentry->d_lock);
return -EBUSY;
Expand All @@ -606,14 +601,12 @@ EXPORT_SYMBOL(d_invalidate);
/* This must be called with d_lock held */
static inline void __dget_dlock(struct dentry *dentry)
{
dentry->d_count++;
dentry->d_lockref.count++;
}

static inline void __dget(struct dentry *dentry)
{
spin_lock(&dentry->d_lock);
__dget_dlock(dentry);
spin_unlock(&dentry->d_lock);
lockref_get(&dentry->d_lockref);
}

struct dentry *dget_parent(struct dentry *dentry)
Expand All @@ -634,8 +627,8 @@ struct dentry *dget_parent(struct dentry *dentry)
goto repeat;
}
rcu_read_unlock();
BUG_ON(!ret->d_count);
ret->d_count++;
BUG_ON(!ret->d_lockref.count);
ret->d_lockref.count++;
spin_unlock(&ret->d_lock);
return ret;
}
Expand Down Expand Up @@ -718,7 +711,7 @@ void d_prune_aliases(struct inode *inode)
spin_lock(&inode->i_lock);
hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
spin_lock(&dentry->d_lock);
if (!dentry->d_count) {
if (!dentry->d_lockref.count) {
__dget_dlock(dentry);
__d_drop(dentry);
spin_unlock(&dentry->d_lock);
Expand Down Expand Up @@ -763,12 +756,8 @@ static void try_prune_one_dentry(struct dentry *dentry)
/* Prune ancestors. */
dentry = parent;
while (dentry) {
spin_lock(&dentry->d_lock);
if (dentry->d_count > 1) {
dentry->d_count--;
spin_unlock(&dentry->d_lock);
if (lockref_put_or_lock(&dentry->d_lockref))
return;
}
dentry = dentry_kill(dentry, 1);
}
}
Expand All @@ -793,7 +782,7 @@ static void shrink_dentry_list(struct list_head *list)
* the LRU because of laziness during lookup. Do not free
* it - just keep it off the LRU list.
*/
if (dentry->d_count) {
if (dentry->d_lockref.count) {
dentry_lru_del(dentry);
spin_unlock(&dentry->d_lock);
continue;
Expand Down Expand Up @@ -913,7 +902,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
dentry_lru_del(dentry);
__d_shrink(dentry);

if (dentry->d_count != 0) {
if (dentry->d_lockref.count != 0) {
printk(KERN_ERR
"BUG: Dentry %p{i=%lx,n=%s}"
" still in use (%d)"
Expand All @@ -922,7 +911,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
dentry->d_inode ?
dentry->d_inode->i_ino : 0UL,
dentry->d_name.name,
dentry->d_count,
dentry->d_lockref.count,
dentry->d_sb->s_type->name,
dentry->d_sb->s_id);
BUG();
Expand All @@ -933,7 +922,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
list_del(&dentry->d_u.d_child);
} else {
parent = dentry->d_parent;
parent->d_count--;
parent->d_lockref.count--;
list_del(&dentry->d_u.d_child);
}

Expand Down Expand Up @@ -981,7 +970,7 @@ void shrink_dcache_for_umount(struct super_block *sb)

dentry = sb->s_root;
sb->s_root = NULL;
dentry->d_count--;
dentry->d_lockref.count--;
shrink_dcache_for_umount_subtree(dentry);

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

dentry->d_count = 1;
dentry->d_lockref.count = 1;
dentry->d_flags = 0;
spin_lock_init(&dentry->d_lock);
seqcount_init(&dentry->d_seq);
Expand Down Expand Up @@ -1970,7 +1959,7 @@ struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name)
goto next;
}

dentry->d_count++;
dentry->d_lockref.count++;
found = dentry;
spin_unlock(&dentry->d_lock);
break;
Expand Down Expand Up @@ -2069,7 +2058,7 @@ void d_delete(struct dentry * dentry)
spin_lock(&dentry->d_lock);
inode = dentry->d_inode;
isdir = S_ISDIR(inode->i_mode);
if (dentry->d_count == 1) {
if (dentry->d_lockref.count == 1) {
if (!spin_trylock(&inode->i_lock)) {
spin_unlock(&dentry->d_lock);
cpu_relax();
Expand Down Expand Up @@ -2948,15 +2937,15 @@ void d_genocide(struct dentry *root)
}
if (!(dentry->d_flags & DCACHE_GENOCIDE)) {
dentry->d_flags |= DCACHE_GENOCIDE;
dentry->d_count--;
dentry->d_lockref.count--;
}
spin_unlock(&dentry->d_lock);
}
if (this_parent != root) {
struct dentry *child = this_parent;
if (!(this_parent->d_flags & DCACHE_GENOCIDE)) {
this_parent->d_flags |= DCACHE_GENOCIDE;
this_parent->d_count--;
this_parent->d_lockref.count--;
}
this_parent = try_to_ascend(this_parent, locked, seq);
if (!this_parent)
Expand Down
6 changes: 3 additions & 3 deletions fs/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,8 +536,8 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry)
* a reference at this point.
*/
BUG_ON(!IS_ROOT(dentry) && dentry->d_parent != parent);
BUG_ON(!parent->d_count);
parent->d_count++;
BUG_ON(!parent->d_lockref.count);
parent->d_lockref.count++;
spin_unlock(&dentry->d_lock);
}
spin_unlock(&parent->d_lock);
Expand Down Expand Up @@ -3327,7 +3327,7 @@ void dentry_unhash(struct dentry *dentry)
{
shrink_dcache_parent(dentry);
spin_lock(&dentry->d_lock);
if (dentry->d_count == 1)
if (dentry->d_lockref.count == 1)
__d_drop(dentry);
spin_unlock(&dentry->d_lock);
}
Expand Down
19 changes: 9 additions & 10 deletions include/linux/dcache.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <linux/seqlock.h>
#include <linux/cache.h>
#include <linux/rcupdate.h>
#include <linux/lockref.h>

struct nameidata;
struct path;
Expand Down Expand Up @@ -100,6 +101,8 @@ extern unsigned int full_name_hash(const unsigned char *, unsigned int);
# endif
#endif

#define d_lock d_lockref.lock

struct dentry {
/* RCU lookup touched fields */
unsigned int d_flags; /* protected by d_lock */
Expand All @@ -112,8 +115,7 @@ struct dentry {
unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */

/* Ref lookup also touches following */
unsigned int d_count; /* protected by d_lock */
spinlock_t d_lock; /* per dentry lock */
struct lockref d_lockref; /* per-dentry lock and refcount */
const struct dentry_operations *d_op;
struct super_block *d_sb; /* The root of the dentry tree */
unsigned long d_time; /* used by d_revalidate */
Expand Down Expand Up @@ -318,15 +320,15 @@ static inline int __d_rcu_to_refcount(struct dentry *dentry, unsigned seq)
assert_spin_locked(&dentry->d_lock);
if (!read_seqcount_retry(&dentry->d_seq, seq)) {
ret = 1;
dentry->d_count++;
dentry->d_lockref.count++;
}

return ret;
}

static inline unsigned d_count(const struct dentry *dentry)
{
return dentry->d_count;
return dentry->d_lockref.count;
}

/* validate "insecure" dentry pointer */
Expand Down Expand Up @@ -357,17 +359,14 @@ extern char *dentry_path(struct dentry *, char *, int);
static inline struct dentry *dget_dlock(struct dentry *dentry)
{
if (dentry)
dentry->d_count++;
dentry->d_lockref.count++;
return dentry;
}

static inline struct dentry *dget(struct dentry *dentry)
{
if (dentry) {
spin_lock(&dentry->d_lock);
dget_dlock(dentry);
spin_unlock(&dentry->d_lock);
}
if (dentry)
lockref_get(&dentry->d_lockref);
return dentry;
}

Expand Down

0 comments on commit 9847423

Please sign in to comment.