summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorJohn Stultz <johnstul@us.ibm.com>2010-02-22 19:58:20 -0800
committerThomas Gleixner <tglx@linutronix.de>2010-04-27 17:33:01 +0200
commit9e0b2cfd72583db7ad50e3e73958926fb65e0557 (patch)
treeb265079c95ea1846026c5664e82c169404fc4e31 /fs
parenta3426080b810723f1bed95b8d08146738126d324 (diff)
downloadlwn-9e0b2cfd72583db7ad50e3e73958926fb65e0557.tar.gz
lwn-9e0b2cfd72583db7ad50e3e73958926fb65e0557.zip
Revert d_count back to an atomic_t
This patch reverts the portion of Nick's vfs scalability patch that converts the dentry d_count from an atomic_t to an int protected by the d_lock. This greatly improves vfs scalability with the -rt kernel, as the extra lock contention on the d_lock hurts very badly when CONFIG_PREEMPT_RT is enabled and the spinlocks become rtmutexes. Signed-off-by: John Stultz <johnstul@us.ibm.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'fs')
-rw-r--r--fs/autofs4/expire.c8
-rw-r--r--fs/autofs4/root.c2
-rw-r--r--fs/configfs/dir.c3
-rw-r--r--fs/dcache.c59
-rw-r--r--fs/locks.c2
-rw-r--r--fs/namei.c4
-rw-r--r--fs/nfs/dir.c10
-rw-r--r--fs/nfsd/vfs.c4
8 files changed, 43 insertions, 49 deletions
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index 5693f251f431..dc629eea0b91 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -228,7 +228,7 @@ static int autofs4_tree_busy(struct vfsmount *mnt,
else
ino_count++;
- if (p->d_count > ino_count) {
+ if (atomic_read(&p->d_count) > ino_count) {
top_ino->last_used = jiffies;
dput(p);
return 1;
@@ -375,7 +375,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
/* Path walk currently on this dentry? */
ino_count = atomic_read(&ino->count) + 2;
- if (dentry->d_count > ino_count)
+ if (atomic_read(&dentry->d_count) > ino_count)
goto next;
/* Can we umount this guy */
@@ -397,7 +397,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
if (!exp_leaves) {
/* Path walk currently on this dentry? */
ino_count = atomic_read(&ino->count) + 1;
- if (dentry->d_count > ino_count)
+ if (atomic_read(&dentry->d_count) > ino_count)
goto next;
if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) {
@@ -411,7 +411,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
} else {
/* Path walk currently on this dentry? */
ino_count = atomic_read(&ino->count) + 1;
- if (dentry->d_count > ino_count)
+ if (atomic_read(&dentry->d_count) > ino_count)
goto next;
expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index f652c4cd583b..5b260883d103 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -570,7 +570,7 @@ restart:
spin_lock(&active->d_lock);
/* Already gone? */
- if (active->d_count == 0)
+ if (atomic_read(&dentry->d_count) == 0)
goto next;
if (active->d_inode && IS_DEADDIR(active->d_inode)) {
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index bb3cbd08d75d..c3638b63b8ce 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -399,7 +399,8 @@ static void remove_dir(struct dentry * d)
if (d->d_inode)
simple_rmdir(parent->d_inode,d);
- pr_debug(" o %s removing done (%d)\n",d->d_name.name, d->d_count);
+ pr_debug(" o %s removing done (%d)\n",d->d_name.name,
+ atomic_read(&d->d_count));
dput(parent);
}
diff --git a/fs/dcache.c b/fs/dcache.c
index 9439ad01d45c..c2a4d2ebe0e4 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -121,7 +121,7 @@ static void d_callback(struct rcu_head *head)
*/
static void d_free(struct dentry *dentry)
{
- BUG_ON(dentry->d_count);
+ BUG_ON(atomic_read(&dentry->d_count));
if (dentry->d_op && dentry->d_op->d_release)
dentry->d_op->d_release(dentry);
/* if dentry was never inserted into hash, immediate free is OK */
@@ -261,15 +261,13 @@ EXPORT_SYMBOL(d_drop);
static inline struct dentry *__dget_dlock(struct dentry *dentry)
{
- dentry->d_count++;
+ atomic_inc(&dentry->d_count);
return dentry;
}
static inline struct dentry *__dget(struct dentry *dentry)
{
- spin_lock(&dentry->d_lock);
__dget_dlock(dentry);
- spin_unlock(&dentry->d_lock);
return dentry;
}
@@ -283,15 +281,15 @@ repeat:
if (!ret)
goto out;
if (dentry == ret) {
- ret->d_count++;
+ atomic_inc(&ret->d_count);
goto out;
}
if (!spin_trylock(&ret->d_lock)) {
spin_unlock(&dentry->d_lock);
goto repeat;
}
- BUG_ON(!ret->d_count);
- ret->d_count++;
+ BUG_ON(!atomic_read(&ret->d_count));
+ atomic_inc(&ret->d_count);
spin_unlock(&ret->d_lock);
out:
spin_unlock(&dentry->d_lock);
@@ -337,15 +335,12 @@ void dput(struct dentry *dentry)
return;
repeat:
- if (dentry->d_count == 1)
+ if (atomic_read(&dentry->d_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 (!atomic_dec_and_lock(&dentry->d_count, &dentry->d_lock))
return;
- }
+
/*
* AV: ->d_delete() is _NOT_ allowed to block now.
@@ -363,7 +358,6 @@ repeat:
dentry->d_flags |= DCACHE_REFERENCED;
dentry_lru_add(dentry);
}
- dentry->d_count--;
spin_unlock(&dentry->d_lock);
return;
@@ -386,8 +380,7 @@ relock2:
goto relock2;
}
}
- dentry->d_count--;
- if (dentry->d_count) {
+ if (atomic_read(&dentry->d_count)) {
/* This case should be fine */
spin_unlock(&dentry->d_lock);
if (parent && parent != dentry)
@@ -445,7 +438,7 @@ int d_invalidate(struct dentry * dentry)
* we might still populate it if it was a
* working directory or similar).
*/
- if (dentry->d_count > 1) {
+ if (atomic_read(&dentry->d_count) > 1) {
if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
spin_unlock(&dentry->d_lock);
return -EBUSY;
@@ -527,7 +520,7 @@ restart:
spin_lock(&inode->i_lock);
list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
spin_lock(&dentry->d_lock);
- if (!dentry->d_count) {
+ if (!atomic_read(&dentry->d_count)) {
__dget_dlock(dentry);
__d_drop(dentry);
spin_unlock(&dentry->d_lock);
@@ -572,8 +565,8 @@ again:
}
parent = dentry->d_parent;
}
- dentry->d_count--;
- if (dentry->d_count) {
+ atomic_dec(&dentry->d_count);
+ if (atomic_read(&dentry->d_count)) {
if (parent)
spin_unlock(&parent->d_lock);
spin_unlock(&dentry->d_lock);
@@ -664,7 +657,7 @@ again1:
* the LRU because of laziness during lookup. Do not free
* it - just keep it off the LRU list.
*/
- if (dentry->d_count) {
+ if (atomic_read(&dentry->d_count)) {
__dentry_lru_del_init(dentry);
spin_unlock(&dentry->d_lock);
continue;
@@ -831,7 +824,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
do {
struct inode *inode;
- if (dentry->d_count != 0) {
+ if (atomic_read(&dentry->d_count) != 0) {
printk(KERN_ERR
"BUG: Dentry %p{i=%lx,n=%s}"
" still in use (%d)"
@@ -840,7 +833,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,
+ atomic_read(&dentry->d_count),
dentry->d_sb->s_type->name,
dentry->d_sb->s_id);
BUG();
@@ -852,7 +845,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
} else {
parent = dentry->d_parent;
spin_lock(&parent->d_lock);
- parent->d_count--;
+ atomic_dec(&parent->d_count);
list_del(&dentry->d_u.d_child);
spin_unlock(&parent->d_lock);
}
@@ -909,7 +902,7 @@ void shrink_dcache_for_umount(struct super_block *sb)
dentry = sb->s_root;
sb->s_root = NULL;
spin_lock(&dentry->d_lock);
- dentry->d_count--;
+ atomic_dec(&dentry->d_count);
spin_unlock(&dentry->d_lock);
shrink_dcache_for_umount_subtree(dentry);
@@ -1046,7 +1039,7 @@ resume:
* move only zero ref count dentries to the end
* of the unused list for prune_dcache
*/
- if (!dentry->d_count) {
+ if (!atomic_read(&dentry->d_count)) {
dentry_lru_add_tail(dentry);
found++;
}
@@ -1185,7 +1178,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
memcpy(dname, name->name, name->len);
dname[name->len] = 0;
- dentry->d_count = 1;
+ atomic_set(&dentry->d_count, 1);
dentry->d_flags = DCACHE_UNHASHED;
spin_lock_init(&dentry->d_lock);
seqcount_init(&dentry->d_seq);
@@ -1631,7 +1624,7 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name)
goto next;
}
- dentry->d_count++;
+ atomic_inc(&dentry->d_count);
found = dentry;
spin_unlock(&dentry->d_lock);
break;
@@ -1817,7 +1810,7 @@ again:
spin_lock(&dentry->d_lock);
inode = dentry->d_inode;
isdir = S_ISDIR(inode->i_mode);
- if (dentry->d_count == 1) {
+ if (atomic_read(&dentry->d_count) == 1) {
if (inode && !spin_trylock(&inode->i_lock)) {
spin_unlock(&dentry->d_lock);
goto again;
@@ -2060,7 +2053,7 @@ static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias)
{
struct mutex *m1 = NULL, *m2 = NULL;
struct dentry *ret;
- struct inode *inode;
+ struct inode *inode = NULL;
/* If alias and dentry share a parent, then no extra locks required */
if (alias->d_parent == dentry->d_parent)
@@ -2583,7 +2576,7 @@ resume:
spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_);
goto repeat;
}
- dentry->d_count--;
+ atomic_dec(&dentry->d_count);
spin_unlock(&dentry->d_lock);
}
if (this_parent != root) {
@@ -2591,7 +2584,7 @@ resume:
struct dentry *child;
tmp = this_parent->d_parent;
- this_parent->d_count--;
+ atomic_dec(&this_parent->d_count);
rcu_read_lock();
spin_unlock(&this_parent->d_lock);
child = this_parent;
diff --git a/fs/locks.c b/fs/locks.c
index 0e074d5417b0..9fdd6796e0ec 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1374,7 +1374,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
goto out;
if ((arg == F_WRLCK)
- && (dentry->d_count > 1 || inode->i_count > 1))
+ && (atomic_read(&dentry->d_count) > 1 || inode->i_count > 1))
goto out;
}
diff --git a/fs/namei.c b/fs/namei.c
index 2e247dc950eb..488a6c07235e 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1038,7 +1038,7 @@ return_base:
spin_unlock(&nd->path.dentry->d_lock);
return -EAGAIN;
}
- nd->path.dentry->d_count++;
+ atomic_inc(&nd->path.dentry->d_count);
spin_unlock(&nd->path.dentry->d_lock);
return 0;
}
@@ -2482,7 +2482,7 @@ void dentry_unhash(struct dentry *dentry)
dget(dentry);
shrink_dcache_parent(dentry);
spin_lock(&dentry->d_lock);
- if (dentry->d_count == 2)
+ if (atomic_read(&dentry->d_count) == 2)
__d_drop(dentry);
spin_unlock(&dentry->d_lock);
}
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 6527b589d5b2..d896d3e55024 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1325,7 +1325,7 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- dentry->d_count);
+ atomic_read(&dentry->d_count));
nfs_inc_stats(dir, NFSIOS_SILLYRENAME);
/*
@@ -1433,7 +1433,7 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry)
dir->i_ino, dentry->d_name.name);
spin_lock(&dentry->d_lock);
- if (dentry->d_count > 1) {
+ if (atomic_read(&dentry->d_count) > 1) {
spin_unlock(&dentry->d_lock);
/* Start asynchronous writeout of the inode */
write_inode_now(dentry->d_inode, 0);
@@ -1581,7 +1581,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n",
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
- new_dentry->d_count);
+ atomic_read(&new_dentry->d_count));
/*
* For non-directories, check whether the target is busy and if so,
@@ -1599,7 +1599,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
rehash = new_dentry;
}
- if (new_dentry->d_count > 2) {
+ if (atomic_read(&new_dentry->d_count) > 2) {
int err;
/* copy the target dentry's name */
@@ -1622,7 +1622,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
/*
* ... prune child dentries and writebacks if needed.
*/
- if (old_dentry->d_count > 1) {
+ if (atomic_read(&old_dentry->d_count) > 1) {
if (S_ISREG(old_inode->i_mode))
nfs_wb_all(old_inode);
shrink_dcache_parent(old_dentry);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index b0fe5fc5fb7e..8de004cf26d5 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -1759,7 +1759,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
goto out_dput_new;
if (svc_msnfs(ffhp) &&
- ((odentry->d_count > 1) || (ndentry->d_count > 1))) {
+ ((atomic_read(&odentry->d_count) > 1) || (atomic_read(&ndentry->d_count) > 1))) {
host_err = -EPERM;
goto out_dput_new;
}
@@ -1845,7 +1845,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
if (type != S_IFDIR) { /* It's UNLINK */
#ifdef MSNFS
if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
- (rdentry->d_count > 1)) {
+ (atomic_read(&rdentry->d_count) > 1)) {
host_err = -EPERM;
} else
#endif