From: Maneesh Soni <maneesh@in.ibm.com>
To: lse-tech@in.ibm.com
Cc: linux-kernel@vger.kernel.org, dipankar@in.ibm.com,
Paul.McKenney@us.ibm.com, viro@math.psu.edu, anton@samba.org,
andrea@suse.de, tytso@mit.edu
Subject: [PATCH][RFC] Peeling off dcache_lock - Ver 2
Date: Tue, 12 Feb 2002 19:41:34 +0530 [thread overview]
Message-ID: <20020212194134.N4411@in.ibm.com> (raw)
In-Reply-To: <20020121174039.D8289@in.ibm.com> <20020124180241.4d266b3e.rusty@rustcorp.com.au>
In-Reply-To: <20020124180241.4d266b3e.rusty@rustcorp.com.au>; from rusty@rustcorp.com.au on Thu, Jan 24, 2002 at 06:02:41PM +1100
This is the cleaned up dcache patch using Read-Copy update and lazy lru list
updation logic from
http://lse.sourceforge.net/locking/dcache/dcache_lock.html
The cleanups were suggested by Rusty Russell.
Change log:
o New patch name.
o Better name for DCACHE_DEFERRED_FREE, now it is DCACHE_UNLINKED
o Removed d_nexthash from struct dentry and replaced all
list_empty(dentry->d_hash) with d_unhashed(dentry).
o Changed d_count to non-atomic as all updates to d_count are done under
per dentry lock.
o Changed unhash() & __unhash() to dentry_unhash() and __dentry_unhash().
dentry_unhash() just calls __dentry_unhash() with per dentry lock held.
dcache_rcu-2.4.17-2.patch:
diff -urN linux-2.4.17/fs/autofs4/expire.c linux-2.4.17-dcache_rcu-2/fs/autofs4/expire.c
--- linux-2.4.17/fs/autofs4/expire.c Tue Jun 12 07:45:27 2001
+++ linux-2.4.17-dcache_rcu-2/fs/autofs4/expire.c Tue Feb 12 16:06:02 2002
@@ -84,7 +84,8 @@
struct list_head *next;
int count;
- count = atomic_read(&top->d_count);
+ spin_lock(&top->d_lock);
+ count = top->d_count;
DPRINTK(("is_tree_busy: top=%p initial count=%d\n",
top, count));
@@ -107,7 +108,8 @@
d_child);
next = next->next;
- count += atomic_read(&dentry->d_count) - 1;
+ spin_lock(&dentry->d_lock);
+ count += dentry->d_count - 1;
if (d_mountpoint(dentry))
adj += check_vfsmnt(topmnt, dentry);
@@ -121,15 +123,18 @@
count -= adj;
if (!list_empty(&dentry->d_subdirs)) {
+ spin_unlock(&dentry->d_lock);
this_parent = dentry;
goto repeat;
}
- if (atomic_read(&dentry->d_count) != adj) {
+ if (dentry->d_count != adj) {
DPRINTK(("is_tree_busy: busy leaf (d_count=%d adj=%d)\n",
- atomic_read(&dentry->d_count), adj));
+ dentry->d_count, adj));
+ spin_unlock(&dentry->d_lock);
return 1;
}
+ spin_unlock(&dentry->d_lock);
}
/* All done at this level ... ascend and resume the search. */
@@ -137,7 +142,8 @@
next = this_parent->d_child.next;
this_parent = this_parent->d_parent;
goto resume;
- }
+ }
+ spin_unlock(&top->d_lock);
DPRINTK(("is_tree_busy: count=%d\n", count));
return count != 0; /* remaining users? */
diff -urN linux-2.4.17/fs/autofs4/root.c linux-2.4.17-dcache_rcu-2/fs/autofs4/root.c
--- linux-2.4.17/fs/autofs4/root.c Tue Oct 24 10:27:38 2000
+++ linux-2.4.17-dcache_rcu-2/fs/autofs4/root.c Tue Feb 12 19:00:56 2002
@@ -403,7 +403,7 @@
spin_unlock(&dcache_lock);
return -ENOTEMPTY;
}
- list_del_init(&dentry->d_hash);
+ dentry_unhash(dentry);
spin_unlock(&dcache_lock);
dput(ino->dentry);
diff -urN linux-2.4.17/fs/coda/dir.c linux-2.4.17-dcache_rcu-2/fs/coda/dir.c
--- linux-2.4.17/fs/coda/dir.c Fri Dec 21 23:11:55 2001
+++ linux-2.4.17-dcache_rcu-2/fs/coda/dir.c Tue Feb 12 16:06:02 2002
@@ -464,7 +464,7 @@
CDEBUG(D_INODE, "old: %s, (%d length), new: %s"
"(%d length). old:d_count: %d, new:d_count: %d\n",
old_name, old_length, new_name, new_length,
- atomic_read(&old_dentry->d_count), atomic_read(&new_dentry->d_count));
+ old_dentry->d_count, new_dentry->d_count);
error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
coda_i2f(new_dir), old_length, new_length,
@@ -666,7 +666,7 @@
if (cii->c_flags & C_FLUSH)
coda_flag_inode_children(inode, C_FLUSH);
- if (atomic_read(&de->d_count) > 1) {
+ if (de->d_count > 1) {
/* pretend it's valid, but don't change the flags */
CDEBUG(D_DOWNCALL, "BOOM for: ino %ld, %s\n",
de->d_inode->i_ino, coda_f2s(&cii->c_fid));
diff -urN linux-2.4.17/fs/coda/file.c linux-2.4.17-dcache_rcu-2/fs/coda/file.c
--- linux-2.4.17/fs/coda/file.c Fri Dec 21 23:11:55 2001
+++ linux-2.4.17-dcache_rcu-2/fs/coda/file.c Tue Feb 12 16:06:02 2002
@@ -105,7 +105,7 @@
coda_vfs_stat.open++;
CDEBUG(D_SPECIAL, "OPEN inode number: %ld, count %d, flags %o.\n",
- f->f_dentry->d_inode->i_ino, atomic_read(&f->f_dentry->d_count), flags);
+ f->f_dentry->d_inode->i_ino, f->f_dentry->d_count, flags);
error = venus_open(i->i_sb, coda_i2f(i), coda_flags, &fh);
if (error || !fh) {
diff -urN linux-2.4.17/fs/coda/pioctl.c linux-2.4.17-dcache_rcu-2/fs/coda/pioctl.c
--- linux-2.4.17/fs/coda/pioctl.c Fri Dec 21 23:11:55 2001
+++ linux-2.4.17-dcache_rcu-2/fs/coda/pioctl.c Tue Feb 12 16:06:02 2002
@@ -97,7 +97,7 @@
CDEBUG(D_PIOCTL, "ioctl on inode %ld\n", target_inode->i_ino);
CDEBUG(D_DOWNCALL, "dput on ino: %ld, icount %d, dcount %d\n", target_inode->i_ino,
- atomic_read(&target_inode->i_count), atomic_read(&nd.dentry->d_count));
+ atomic_read(&target_inode->i_count), nd.dentry->d_count);
path_release(&nd);
return error;
}
diff -urN linux-2.4.17/fs/dcache.c linux-2.4.17-dcache_rcu-2/fs/dcache.c
--- linux-2.4.17/fs/dcache.c Fri Dec 21 23:11:55 2001
+++ linux-2.4.17-dcache_rcu-2/fs/dcache.c Tue Feb 12 19:03:42 2002
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <asm/uaccess.h>
+#include <linux/rcupdate.h>
#define DCACHE_PARANOIA 1
/* #define DCACHE_DEBUG 1 */
@@ -55,14 +56,20 @@
/* Statistics gathering. */
struct dentry_stat_t dentry_stat = {0, 0, 45, 0,};
-/* no dcache_lock, please */
+static void d_callback(void *arg)
+{
+ struct dentry * dentry = (struct dentry *)arg;
+
+ if (dname_external(dentry))
+ kfree((void *) dentry->d_name.name);
+ kmem_cache_free(dentry_cache, dentry);
+}
+
static inline void d_free(struct dentry *dentry)
{
if (dentry->d_op && dentry->d_op->d_release)
dentry->d_op->d_release(dentry);
- if (dname_external(dentry))
- kfree(dentry->d_name.name);
- kmem_cache_free(dentry_cache, dentry);
+ call_rcu(&dentry->d_rcu, d_callback, dentry);
dentry_stat.nr_dentry--;
}
@@ -119,14 +126,15 @@
{
if (!dentry)
return;
-
repeat:
- if (!atomic_dec_and_lock(&dentry->d_count, &dcache_lock))
+ spin_lock(&dcache_lock);
+ spin_lock(&dentry->d_lock);
+ if (--dentry->d_count) {
+ spin_unlock(&dentry->d_lock);
+ spin_unlock(&dcache_lock);
return;
+ }
- /* dput on a free dentry? */
- if (!list_empty(&dentry->d_lru))
- BUG();
/*
* AV: ->d_delete() is _NOT_ allowed to block now.
*/
@@ -135,18 +143,28 @@
goto unhash_it;
}
/* Unreachable? Get rid of it */
- if (list_empty(&dentry->d_hash))
+ if (d_unhashed(dentry))
goto kill_it;
- list_add(&dentry->d_lru, &dentry_unused);
- dentry_stat.nr_unused++;
+
+ if (list_empty(&dentry->d_lru)) {
+ dentry->d_vfs_flags &= ~DCACHE_REFERENCED;
+ list_add(&dentry->d_lru, &dentry_unused);
+ dentry_stat.nr_unused++;
+ }
+ spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
return;
unhash_it:
- list_del_init(&dentry->d_hash);
+ __dentry_unhash(dentry);
kill_it: {
struct dentry *parent;
+ spin_unlock(&dentry->d_lock);
+ if (!list_empty(&dentry->d_lru)) {
+ list_del(&dentry->d_lru);
+ dentry_stat.nr_unused--;
+ }
list_del(&dentry->d_child);
/* drops the lock, at that point nobody can reach this dentry */
dentry_iput(dentry);
@@ -177,7 +195,7 @@
* If it's already been dropped, return OK.
*/
spin_lock(&dcache_lock);
- if (list_empty(&dentry->d_hash)) {
+ if ( d_unhashed(dentry)) {
spin_unlock(&dcache_lock);
return 0;
}
@@ -201,33 +219,24 @@
* we might still populate it if it was a
* working directory or similar).
*/
- if (atomic_read(&dentry->d_count) > 1) {
+ spin_lock(&dentry->d_lock);
+ if (dentry->d_count > 1) {
if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
+ spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
return -EBUSY;
}
}
-
- list_del_init(&dentry->d_hash);
+ __dentry_unhash(dentry);
+ spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
- return 0;
-}
-
-/* This should be called _only_ with dcache_lock held */
-static inline struct dentry * __dget_locked(struct dentry *dentry)
-{
- atomic_inc(&dentry->d_count);
- if (atomic_read(&dentry->d_count) == 1) {
- dentry_stat.nr_unused--;
- list_del_init(&dentry->d_lru);
- }
- return dentry;
+ return 0;
}
struct dentry * dget_locked(struct dentry *dentry)
{
- return __dget_locked(dentry);
+ return dget(dentry);
}
/**
@@ -252,8 +261,8 @@
tmp = next;
next = tmp->next;
alias = list_entry(tmp, struct dentry, d_alias);
- if (!list_empty(&alias->d_hash)) {
- __dget_locked(alias);
+ if (!d_unhashed(alias)) {
+ dget(alias);
spin_unlock(&dcache_lock);
return alias;
}
@@ -263,7 +272,7 @@
}
/*
- * Try to kill dentries associated with this inode.
+ * Try to kill dentries associated with this inode.
* WARNING: you must own a reference to inode.
*/
void d_prune_aliases(struct inode *inode)
@@ -274,13 +283,16 @@
tmp = head;
while ((tmp = tmp->next) != head) {
struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
- if (!atomic_read(&dentry->d_count)) {
- __dget_locked(dentry);
+ spin_lock(&dentry->d_lock);
+ if (!dentry->d_count) {
+ __dget(dentry);
+ __dentry_unhash(dentry);
+ spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
- d_drop(dentry);
dput(dentry);
goto restart;
}
+ spin_unlock(&dentry->d_lock);
}
spin_unlock(&dcache_lock);
}
@@ -295,7 +307,8 @@
{
struct dentry * parent;
- list_del_init(&dentry->d_hash);
+ __dentry_unhash(dentry);
+ spin_unlock(&dentry->d_lock);
list_del(&dentry->d_child);
dentry_iput(dentry);
parent = dentry->d_parent;
@@ -331,19 +344,18 @@
break;
list_del_init(tmp);
dentry = list_entry(tmp, struct dentry, d_lru);
-
+
+ spin_lock(&dentry->d_lock);
/* If the dentry was recently referenced, don't free it. */
if (dentry->d_vfs_flags & DCACHE_REFERENCED) {
dentry->d_vfs_flags &= ~DCACHE_REFERENCED;
- list_add(&dentry->d_lru, &dentry_unused);
+ if (!dentry->d_count)
+ list_add(&dentry->d_lru, &dentry_unused);
+ spin_unlock(&dentry->d_lock);
continue;
}
dentry_stat.nr_unused--;
- /* Unused dentry with a count? */
- if (atomic_read(&dentry->d_count))
- BUG();
-
prune_one_dentry(dentry);
if (!--count)
break;
@@ -405,8 +417,11 @@
dentry = list_entry(tmp, struct dentry, d_lru);
if (dentry->d_sb != sb)
continue;
- if (atomic_read(&dentry->d_count))
+ spin_lock(&dentry->d_lock);
+ if (dentry->d_count) {
+ spin_unlock(&dentry->d_lock);
continue;
+ }
dentry_stat.nr_unused--;
list_del_init(tmp);
prune_one_dentry(dentry);
@@ -488,11 +503,14 @@
struct list_head *tmp = next;
struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
next = tmp->next;
- if (!atomic_read(&dentry->d_count)) {
- list_del(&dentry->d_lru);
+
+ list_del_init(&dentry->d_lru);
+ spin_lock(&dentry->d_lock);
+ if (!dentry->d_count) {
list_add(&dentry->d_lru, dentry_unused.prev);
found++;
}
+ spin_unlock(&dentry->d_lock);
/*
* Descend a level if the d_subdirs list is non-empty.
*/
@@ -605,9 +623,10 @@
memcpy(str, name->name, name->len);
str[name->len] = 0;
- atomic_set(&dentry->d_count, 1);
- dentry->d_vfs_flags = 0;
+ dentry->d_count = 1;
+ dentry->d_vfs_flags = DCACHE_UNLINKED;
dentry->d_flags = 0;
+ dentry->d_lock = SPIN_LOCK_UNLOCKED;
dentry->d_inode = NULL;
dentry->d_parent = NULL;
dentry->d_sb = NULL;
@@ -708,8 +727,8 @@
const unsigned char *str = name->name;
struct list_head *head = d_hash(parent,hash);
struct list_head *tmp;
+ struct dentry * found = NULL;
- spin_lock(&dcache_lock);
tmp = head->next;
for (;;) {
struct dentry * dentry = list_entry(tmp, struct dentry, d_hash);
@@ -729,13 +748,16 @@
if (memcmp(dentry->d_name.name, str, len))
continue;
}
- __dget_locked(dentry);
- dentry->d_vfs_flags |= DCACHE_REFERENCED;
- spin_unlock(&dcache_lock);
- return dentry;
+
+ spin_lock(&dentry->d_lock);
+ if (!(dentry->d_vfs_flags & DCACHE_UNLINKED)) {
+ found = __dget(dentry);
+ }
+ spin_unlock(&dentry->d_lock);
+
+ return found;
}
- spin_unlock(&dcache_lock);
- return NULL;
+ return found;
}
/**
@@ -774,7 +796,7 @@
lhp = base = d_hash(dparent, dentry->d_name.hash);
while ((lhp = lhp->next) != base) {
if (dentry == list_entry(lhp, struct dentry, d_hash)) {
- __dget_locked(dentry);
+ dget(dentry);
spin_unlock(&dcache_lock);
return 1;
}
@@ -811,7 +833,7 @@
* Are we the only user?
*/
spin_lock(&dcache_lock);
- if (atomic_read(&dentry->d_count) == 1) {
+ if (dentry->d_count == 1) {
dentry_iput(dentry);
return;
}
@@ -834,9 +856,12 @@
void d_rehash(struct dentry * entry)
{
struct list_head *list = d_hash(entry->d_parent, entry->d_name.hash);
- if (!list_empty(&entry->d_hash)) BUG();
spin_lock(&dcache_lock);
+ spin_lock(&entry->d_lock);
+ if (!list_empty(&entry->d_hash) && !d_unhashed(entry)) BUG();
list_add(&entry->d_hash, list);
+ entry->d_vfs_flags &= ~DCACHE_UNLINKED;
+ spin_unlock(&entry->d_lock);
spin_unlock(&dcache_lock);
}
@@ -909,7 +934,7 @@
list_add(&dentry->d_hash, &target->d_hash);
/* Unhash the target: dput() will then get rid of it */
- list_del_init(&target->d_hash);
+ dentry_unhash(target);
list_del(&dentry->d_child);
list_del(&target->d_child);
@@ -951,7 +976,7 @@
*--end = '\0';
buflen--;
- if (!IS_ROOT(dentry) && list_empty(&dentry->d_hash)) {
+ if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
buflen -= 10;
end -= 10;
memcpy(end, " (deleted)", 10);
@@ -1034,7 +1059,7 @@
error = -ENOENT;
/* Has the current directory has been unlinked? */
spin_lock(&dcache_lock);
- if (pwd->d_parent == pwd || !list_empty(&pwd->d_hash)) {
+ if (pwd->d_parent == pwd || !d_unhashed(pwd)) {
unsigned long len;
char * cwd;
@@ -1111,11 +1136,11 @@
this_parent = dentry;
goto repeat;
}
- atomic_dec(&dentry->d_count);
+ dentry->d_count--;
}
if (this_parent != root) {
next = this_parent->d_child.next;
- atomic_dec(&this_parent->d_count);
+ this_parent->d_count--;
this_parent = this_parent->d_parent;
goto resume;
}
diff -urN linux-2.4.17/fs/hpfs/namei.c linux-2.4.17-dcache_rcu-2/fs/hpfs/namei.c
--- linux-2.4.17/fs/hpfs/namei.c Sat Dec 30 03:37:57 2000
+++ linux-2.4.17-dcache_rcu-2/fs/hpfs/namei.c Tue Feb 12 16:06:02 2002
@@ -333,7 +333,7 @@
if (rep)
goto ret;
d_drop(dentry);
- if (atomic_read(&dentry->d_count) > 1 ||
+ if (dentry->d_count > 1 ||
permission(inode, MAY_WRITE) ||
get_write_access(inode)) {
d_rehash(dentry);
diff -urN linux-2.4.17/fs/intermezzo/journal.c linux-2.4.17-dcache_rcu-2/fs/intermezzo/journal.c
--- linux-2.4.17/fs/intermezzo/journal.c Fri Dec 21 23:11:55 2001
+++ linux-2.4.17-dcache_rcu-2/fs/intermezzo/journal.c Tue Feb 12 16:06:02 2002
@@ -186,7 +186,7 @@
*--end = '\0';
buflen--;
- if (dentry->d_parent != dentry && list_empty(&dentry->d_hash)) {
+ if (dentry->d_parent != dentry && d_unhashed(dentry)) {
buflen -= 10;
end -= 10;
memcpy(end, " (deleted)", 10);
diff -urN linux-2.4.17/fs/intermezzo/presto.c linux-2.4.17-dcache_rcu-2/fs/intermezzo/presto.c
--- linux-2.4.17/fs/intermezzo/presto.c Tue Nov 13 22:50:56 2001
+++ linux-2.4.17-dcache_rcu-2/fs/intermezzo/presto.c Tue Feb 12 16:06:02 2002
@@ -473,7 +473,7 @@
// XXX this check makes no sense as d_count can change anytime.
/* indicate if we were the only users while changing the flag */
- if ( atomic_read(&dentry->d_count) > 1 )
+ if ( dentry->d_count > 1 )
error = -EBUSY;
out:
diff -urN linux-2.4.17/fs/intermezzo/vfs.c linux-2.4.17-dcache_rcu-2/fs/intermezzo/vfs.c
--- linux-2.4.17/fs/intermezzo/vfs.c Tue Nov 13 22:50:56 2001
+++ linux-2.4.17-dcache_rcu-2/fs/intermezzo/vfs.c Tue Feb 12 16:06:02 2002
@@ -1201,10 +1201,10 @@
static void d_unhash(struct dentry *dentry)
{
dget(dentry);
- switch (atomic_read(&dentry->d_count)) {
+ switch (dentry->d_count) {
default:
shrink_dcache_parent(dentry);
- if (atomic_read(&dentry->d_count) != 2)
+ if (dentry->d_count != 2)
break;
case 2:
d_drop(dentry);
diff -urN linux-2.4.17/fs/locks.c linux-2.4.17-dcache_rcu-2/fs/locks.c
--- linux-2.4.17/fs/locks.c Thu Oct 11 20:22:18 2001
+++ linux-2.4.17-dcache_rcu-2/fs/locks.c Tue Feb 12 16:06:02 2002
@@ -1236,7 +1236,7 @@
* FIXME: What about F_RDLCK and files open for writing?
*/
if ((arg == F_WRLCK)
- && ((atomic_read(&dentry->d_count) > 1)
+ && ((dentry->d_count > 1)
|| (atomic_read(&inode->i_count) > 1)))
return -EAGAIN;
diff -urN linux-2.4.17/fs/namei.c linux-2.4.17-dcache_rcu-2/fs/namei.c
--- linux-2.4.17/fs/namei.c Thu Oct 18 03:16:29 2001
+++ linux-2.4.17-dcache_rcu-2/fs/namei.c Tue Feb 12 16:06:02 2002
@@ -1354,10 +1354,10 @@
static void d_unhash(struct dentry *dentry)
{
dget(dentry);
- switch (atomic_read(&dentry->d_count)) {
+ switch (dentry->d_count) {
default:
shrink_dcache_parent(dentry);
- if (atomic_read(&dentry->d_count) != 2)
+ if (dentry->d_count != 2)
break;
case 2:
d_drop(dentry);
diff -urN linux-2.4.17/fs/namespace.c linux-2.4.17-dcache_rcu-2/fs/namespace.c
--- linux-2.4.17/fs/namespace.c Fri Dec 21 23:11:55 2001
+++ linux-2.4.17-dcache_rcu-2/fs/namespace.c Tue Feb 12 16:06:02 2002
@@ -1002,7 +1002,7 @@
#if 1
shrink_dcache();
printk("change_root: old root has d_count=%d\n",
- atomic_read(&old_rootmnt->mnt_root->d_count));
+ old_rootmnt->mnt_root->d_count);
#endif
mount_devfs_fs ();
/*
diff -urN linux-2.4.17/fs/nfs/dir.c linux-2.4.17-dcache_rcu-2/fs/nfs/dir.c
--- linux-2.4.17/fs/nfs/dir.c Tue Jun 12 23:45:08 2001
+++ linux-2.4.17-dcache_rcu-2/fs/nfs/dir.c Tue Feb 12 16:06:02 2002
@@ -754,9 +754,9 @@
dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- atomic_read(&dentry->d_count));
+ dentry->d_count);
- if (atomic_read(&dentry->d_count) == 1)
+ if (dentry->d_count == 1)
goto out; /* No need to silly rename. */
@@ -833,11 +833,11 @@
d_drop(dentry);
rehash = 1;
}
- if (atomic_read(&dentry->d_count) > 1) {
+ if (dentry->d_count > 1) {
#ifdef NFS_PARANOIA
printk("nfs_safe_remove: %s/%s busy, d_count=%d\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- atomic_read(&dentry->d_count));
+ dentry->d_count);
#endif
goto out;
}
@@ -1005,7 +1005,7 @@
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,
- atomic_read(&new_dentry->d_count));
+ new_dentry->d_count);
/*
* First check whether the target is busy ... we can't
@@ -1019,7 +1019,7 @@
goto go_ahead;
if (S_ISDIR(new_inode->i_mode))
goto out;
- else if (atomic_read(&new_dentry->d_count) > 1) {
+ else if (new_dentry->d_count > 1) {
int err;
/* copy the target dentry's name */
dentry = d_alloc(new_dentry->d_parent,
@@ -1037,12 +1037,12 @@
}
/* dentry still busy? */
- if (atomic_read(&new_dentry->d_count) > 1) {
+ if (new_dentry->d_count > 1) {
#ifdef NFS_PARANOIA
printk("nfs_rename: target %s/%s busy, d_count=%d\n",
new_dentry->d_parent->d_name.name,
new_dentry->d_name.name,
- atomic_read(&new_dentry->d_count));
+ new_dentry->d_count);
#endif
goto out;
}
@@ -1052,7 +1052,7 @@
/*
* ... prune child dentries and writebacks if needed.
*/
- if (atomic_read(&old_dentry->d_count) > 1) {
+ if (old_dentry->d_count > 1) {
nfs_wb_all(old_inode);
shrink_dcache_parent(old_dentry);
}
diff -urN linux-2.4.17/fs/nfsd/nfsfh.c linux-2.4.17-dcache_rcu-2/fs/nfsd/nfsfh.c
--- linux-2.4.17/fs/nfsd/nfsfh.c Thu Oct 4 11:29:22 2001
+++ linux-2.4.17-dcache_rcu-2/fs/nfsd/nfsfh.c Tue Feb 12 16:06:02 2002
@@ -348,7 +348,7 @@
spin_lock(&dcache_lock);
list_for_each(lp, &child->d_inode->i_dentry) {
struct dentry *tmp = list_entry(lp,struct dentry, d_alias);
- if (!list_empty(&tmp->d_hash) &&
+ if (!d_unhashed(tmp) &&
tmp->d_parent == parent) {
child = dget_locked(tmp);
spin_unlock(&dcache_lock);
diff -urN linux-2.4.17/fs/nfsd/vfs.c linux-2.4.17-dcache_rcu-2/fs/nfsd/vfs.c
--- linux-2.4.17/fs/nfsd/vfs.c Fri Dec 21 23:11:55 2001
+++ linux-2.4.17-dcache_rcu-2/fs/nfsd/vfs.c Tue Feb 12 16:06:02 2002
@@ -1280,8 +1280,8 @@
#ifdef MSNFS
if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
- ((atomic_read(&odentry->d_count) > 1)
- || (atomic_read(&ndentry->d_count) > 1))) {
+ ((odentry->d_count > 1)
+ || (ndentry->d_count > 1))) {
err = nfserr_perm;
} else
#endif
@@ -1348,7 +1348,7 @@
if (type != S_IFDIR) { /* It's UNLINK */
#ifdef MSNFS
if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
- (atomic_read(&rdentry->d_count) > 1)) {
+ (rdentry->d_count > 1)) {
err = nfserr_perm;
} else
#endif
diff -urN linux-2.4.17/fs/readdir.c linux-2.4.17-dcache_rcu-2/fs/readdir.c
--- linux-2.4.17/fs/readdir.c Mon Aug 13 03:29:08 2001
+++ linux-2.4.17-dcache_rcu-2/fs/readdir.c Tue Feb 12 16:06:02 2002
@@ -79,7 +79,7 @@
while(1) {
struct dentry *de = list_entry(list, struct dentry, d_child);
- if (!list_empty(&de->d_hash) && de->d_inode) {
+ if (!d_unhashed(de) && de->d_inode) {
spin_unlock(&dcache_lock);
if (filldir(dirent, de->d_name.name, de->d_name.len, filp->f_pos, de->d_inode->i_ino, DT_UNKNOWN) < 0)
break;
diff -urN linux-2.4.17/include/linux/dcache.h linux-2.4.17-dcache_rcu-2/include/linux/dcache.h
--- linux-2.4.17/include/linux/dcache.h Fri Nov 23 01:16:18 2001
+++ linux-2.4.17-dcache_rcu-2/include/linux/dcache.h Tue Feb 12 18:57:52 2002
@@ -5,6 +5,8 @@
#include <asm/atomic.h>
#include <linux/mount.h>
+#include <linux/rcupdate.h>
+#include <asm/system.h>
/*
* linux/include/linux/dcache.h
@@ -64,12 +66,14 @@
#define DNAME_INLINE_LEN 16
struct dentry {
- atomic_t d_count;
+ unsigned int d_count;
+ spinlock_t d_lock; /* lock for d_count & d_vfs_flags */
+ unsigned long d_vfs_flags; /* moved here to be on same cacheline */
unsigned int d_flags;
struct inode * d_inode; /* Where the name belongs to - NULL is negative */
struct dentry * d_parent; /* parent directory */
struct list_head d_hash; /* lookup hash list */
- struct list_head d_lru; /* d_count = 0 LRU list */
+ struct list_head d_lru; /* LRU list */
struct list_head d_child; /* child of parent list */
struct list_head d_subdirs; /* our children */
struct list_head d_alias; /* inode alias list */
@@ -78,8 +82,8 @@
unsigned long d_time; /* used by d_revalidate */
struct dentry_operations *d_op;
struct super_block * d_sb; /* The root of the dentry tree */
- unsigned long d_vfs_flags;
void * d_fsdata; /* fs-specific data */
+ struct rcu_head d_rcu;
unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
};
@@ -123,39 +127,16 @@
* s_nfsd_free_path semaphore will be down
*/
#define DCACHE_REFERENCED 0x0008 /* Recently used, don't discard. */
+#define DCACHE_UNLINKED 0x0010 /* Marked for deferred freeing */
extern spinlock_t dcache_lock;
-/**
- * d_drop - drop a dentry
- * @dentry: dentry to drop
- *
- * d_drop() unhashes the entry from the parent
- * dentry hashes, so that it won't be found through
- * a VFS lookup any more. Note that this is different
- * from deleting the dentry - d_delete will try to
- * mark the dentry negative if possible, giving a
- * successful _negative_ lookup, while d_drop will
- * just make the cache lookup fail.
- *
- * d_drop() is used mainly for stuff that wants
- * to invalidate a dentry for some reason (NFS
- * timeouts or autofs deletes).
- */
-
-static __inline__ void d_drop(struct dentry * dentry)
-{
- spin_lock(&dcache_lock);
- list_del(&dentry->d_hash);
- INIT_LIST_HEAD(&dentry->d_hash);
- spin_unlock(&dcache_lock);
-}
-
static __inline__ int dname_external(struct dentry *d)
{
return d->d_name.name != d->d_iname;
}
+
/*
* These are the low-level FS interfaces to the dcache..
*/
@@ -227,6 +208,47 @@
/* Allocation counts.. */
+extern struct dentry * dget_locked(struct dentry *);
+
+static inline void __dentry_unhash(struct dentry *d)
+{
+ d->d_vfs_flags |= DCACHE_UNLINKED;
+ wmb();
+ list_del(&d->d_hash);
+ wmb();
+}
+
+static inline void dentry_unhash(struct dentry *d)
+{
+ spin_lock(&d->d_lock);
+ __dentry_unhash(d);
+ spin_unlock(&d->d_lock);
+}
+
+/**
+ * d_drop - drop a dentry
+ * @dentry: dentry to drop
+ *
+ * d_drop() unhashes the entry from the parent
+ * dentry hashes, so that it won't be found through
+ * a VFS lookup any more. Note that this is different
+ * from deleting the dentry - d_delete will try to
+ * mark the dentry negative if possible, giving a
+ * successful _negative_ lookup, while d_drop will
+ * just make the cache lookup fail.
+ *
+ * d_drop() is used mainly for stuff that wants
+ * to invalidate a dentry for some reason (NFS
+ * timeouts or autofs deletes).
+ */
+
+static inline void d_drop(struct dentry * dentry)
+{
+ spin_lock(&dcache_lock);
+ dentry_unhash(dentry);
+ spin_unlock(&dcache_lock);
+}
+
/**
* dget, dget_locked - get a reference to a dentry
* @dentry: dentry to get a reference to
@@ -240,17 +262,25 @@
* and call dget_locked() instead of dget().
*/
-static __inline__ struct dentry * dget(struct dentry *dentry)
+static inline struct dentry * dget(struct dentry *dentry)
{
if (dentry) {
- if (!atomic_read(&dentry->d_count))
- BUG();
- atomic_inc(&dentry->d_count);
+ spin_lock(&dentry->d_lock);
+ dentry->d_count++;
+ dentry->d_vfs_flags |= DCACHE_REFERENCED;
+ spin_unlock(&dentry->d_lock);
}
return dentry;
}
-extern struct dentry * dget_locked(struct dentry *);
+static __inline__ struct dentry * __dget(struct dentry *dentry)
+{
+ if (dentry) {
+ dentry->d_count++;
+ dentry->d_vfs_flags |= DCACHE_REFERENCED;
+ }
+ return dentry;
+}
/**
* d_unhashed - is dentry hashed
@@ -261,7 +291,7 @@
static __inline__ int d_unhashed(struct dentry *dentry)
{
- return list_empty(&dentry->d_hash);
+ return (dentry->d_vfs_flags & DCACHE_UNLINKED);
}
extern void dput(struct dentry *);
--
Maneesh Soni
IBM Linux Technology Center,
IBM India Software Lab, Bangalore.
Phone: +91-80-5044999 email: maneesh@in.ibm.com
http://lse.sourceforge.net/locking/rcupdate.html
next prev parent reply other threads:[~2002-02-12 14:09 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-01-21 12:10 [RFC] Peeling off dcache_lock Maneesh Soni
2002-01-24 7:02 ` Rusty Russell
[not found] ` <20020125114410.Z8289@in.ibm.com>
2002-01-27 3:42 ` Rusty Russell
2002-02-12 14:11 ` Maneesh Soni [this message]
2002-01-25 9:30 ` Dipankar Sarma
2002-01-29 0:33 ` Rusty Russell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20020212194134.N4411@in.ibm.com \
--to=maneesh@in.ibm.com \
--cc=Paul.McKenney@us.ibm.com \
--cc=andrea@suse.de \
--cc=anton@samba.org \
--cc=dipankar@in.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lse-tech@in.ibm.com \
--cc=tytso@mit.edu \
--cc=viro@math.psu.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.