diff options
author | John Stultz <johnstul@us.ibm.com> | 2010-02-22 19:58:20 -0800 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2010-04-27 17:33:01 +0200 |
commit | 9e0b2cfd72583db7ad50e3e73958926fb65e0557 (patch) | |
tree | b265079c95ea1846026c5664e82c169404fc4e31 /fs | |
parent | a3426080b810723f1bed95b8d08146738126d324 (diff) | |
download | lwn-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.c | 8 | ||||
-rw-r--r-- | fs/autofs4/root.c | 2 | ||||
-rw-r--r-- | fs/configfs/dir.c | 3 | ||||
-rw-r--r-- | fs/dcache.c | 59 | ||||
-rw-r--r-- | fs/locks.c | 2 | ||||
-rw-r--r-- | fs/namei.c | 4 | ||||
-rw-r--r-- | fs/nfs/dir.c | 10 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 4 |
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 |