[PATCH 3/4] dcache: change rename_lock to a sequence read/write lock

2013-02-19 Thread Waiman Long
The d_path() and related kernel functions currently take a writer
lock on rename_lock because they need to follow pointers. By changing
rename_lock to be the new sequence read/write lock, a reader lock
can be taken and multiple d_path() threads can proceed concurrently
without blocking each other.

It is unlikely that the frequency of filesystem changes and d_path()
name lookup will be high enough to cause writer starvation, the current
limitation of the read/write lock should be acceptable in that case.

All the sites where rename_lock is referenced were modified to use the
sequence read/write lock declaration and access functions.

Signed-off-by: Waiman Long 
---
 fs/autofs4/waitq.c |6 ++--
 fs/ceph/mds_client.c   |4 +-
 fs/cifs/dir.c  |4 +-
 fs/dcache.c|   87 ---
 fs/nfs/namespace.c |6 ++--
 include/linux/dcache.h |4 +-
 kernel/auditsc.c   |5 ++-
 7 files changed, 59 insertions(+), 57 deletions(-)

diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 03bc1d3..95eee02 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -199,7 +199,7 @@ rename_retry:
buf = *name;
len = 0;
 
-   seq = read_seqbegin(_lock);
+   seq = read_seqrwbegin(_lock);
rcu_read_lock();
spin_lock(>fs_lock);
for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent)
@@ -208,7 +208,7 @@ rename_retry:
if (!len || --len > NAME_MAX) {
spin_unlock(>fs_lock);
rcu_read_unlock();
-   if (read_seqretry(_lock, seq))
+   if (read_seqrwretry(_lock, seq))
goto rename_retry;
return 0;
}
@@ -224,7 +224,7 @@ rename_retry:
}
spin_unlock(>fs_lock);
rcu_read_unlock();
-   if (read_seqretry(_lock, seq))
+   if (read_seqrwretry(_lock, seq))
goto rename_retry;
 
return len;
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 9165eb8..da6bd2c 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -1458,7 +1458,7 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int 
*plen, u64 *base,
 
 retry:
len = 0;
-   seq = read_seqbegin(_lock);
+   seq = read_seqrwbegin(_lock);
rcu_read_lock();
for (temp = dentry; !IS_ROOT(temp);) {
struct inode *inode = temp->d_inode;
@@ -1508,7 +1508,7 @@ retry:
temp = temp->d_parent;
}
rcu_read_unlock();
-   if (pos != 0 || read_seqretry(_lock, seq)) {
+   if (pos != 0 || read_seqrwretry(_lock, seq)) {
pr_err("build_path did not end path lookup where "
   "expected, namelen is %d, pos is %d\n", len, pos);
/* presumably this is only possible if racing with a
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 8719bbe..4842523 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -96,7 +96,7 @@ build_path_from_dentry(struct dentry *direntry)
dfsplen = 0;
 cifs_bp_rename_retry:
namelen = dfsplen;
-   seq = read_seqbegin(_lock);
+   seq = read_seqrwbegin(_lock);
rcu_read_lock();
for (temp = direntry; !IS_ROOT(temp);) {
namelen += (1 + temp->d_name.len);
@@ -136,7 +136,7 @@ cifs_bp_rename_retry:
}
}
rcu_read_unlock();
-   if (namelen != dfsplen || read_seqretry(_lock, seq)) {
+   if (namelen != dfsplen || read_seqrwretry(_lock, seq)) {
cFYI(1, "did not end path lookup where expected. namelen=%d "
"dfsplen=%d", namelen, dfsplen);
/* presumably this is only possible if racing with a rename
diff --git a/fs/dcache.c b/fs/dcache.c
index 20cc789..b1487e2 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -29,6 +29,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -82,7 +83,7 @@ int sysctl_vfs_cache_pressure __read_mostly = 100;
 EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
 
 static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lru_lock);
-__cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
+__cacheline_aligned_in_smp DEFINE_SEQRWLOCK(rename_lock);
 
 EXPORT_SYMBOL(rename_lock);
 
@@ -1030,7 +1031,7 @@ static struct dentry *try_to_ascend(struct dentry *old, 
int locked, unsigned seq
 */
if (new != old->d_parent ||
 (old->d_flags & DCACHE_DENTRY_KILLED) ||
-(!locked && read_seqretry(_lock, seq))) {
+(!locked && read_seqrwretry(_lock, seq))) {
spin_unlock(>d_lock);
new = NULL;
}
@@ -1059,7 +1060,7 @@ int have_submounts(struct dentry *parent)
unsigned seq;
int locked = 0;
 
-   seq = read_seqbegin(_lock);
+   seq = read_seqrwbegin(_lock);
 again:
this_parent = parent;
 
@@ -1102,23 +1103,23 @@ resume:
goto resume;
}
   

[PATCH 3/4] dcache: change rename_lock to a sequence read/write lock

2013-02-19 Thread Waiman Long
The d_path() and related kernel functions currently take a writer
lock on rename_lock because they need to follow pointers. By changing
rename_lock to be the new sequence read/write lock, a reader lock
can be taken and multiple d_path() threads can proceed concurrently
without blocking each other.

It is unlikely that the frequency of filesystem changes and d_path()
name lookup will be high enough to cause writer starvation, the current
limitation of the read/write lock should be acceptable in that case.

All the sites where rename_lock is referenced were modified to use the
sequence read/write lock declaration and access functions.

Signed-off-by: Waiman Long waiman.l...@hp.com
---
 fs/autofs4/waitq.c |6 ++--
 fs/ceph/mds_client.c   |4 +-
 fs/cifs/dir.c  |4 +-
 fs/dcache.c|   87 ---
 fs/nfs/namespace.c |6 ++--
 include/linux/dcache.h |4 +-
 kernel/auditsc.c   |5 ++-
 7 files changed, 59 insertions(+), 57 deletions(-)

diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 03bc1d3..95eee02 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -199,7 +199,7 @@ rename_retry:
buf = *name;
len = 0;
 
-   seq = read_seqbegin(rename_lock);
+   seq = read_seqrwbegin(rename_lock);
rcu_read_lock();
spin_lock(sbi-fs_lock);
for (tmp = dentry ; tmp != root ; tmp = tmp-d_parent)
@@ -208,7 +208,7 @@ rename_retry:
if (!len || --len  NAME_MAX) {
spin_unlock(sbi-fs_lock);
rcu_read_unlock();
-   if (read_seqretry(rename_lock, seq))
+   if (read_seqrwretry(rename_lock, seq))
goto rename_retry;
return 0;
}
@@ -224,7 +224,7 @@ rename_retry:
}
spin_unlock(sbi-fs_lock);
rcu_read_unlock();
-   if (read_seqretry(rename_lock, seq))
+   if (read_seqrwretry(rename_lock, seq))
goto rename_retry;
 
return len;
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 9165eb8..da6bd2c 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -1458,7 +1458,7 @@ char *ceph_mdsc_build_path(struct dentry *dentry, int 
*plen, u64 *base,
 
 retry:
len = 0;
-   seq = read_seqbegin(rename_lock);
+   seq = read_seqrwbegin(rename_lock);
rcu_read_lock();
for (temp = dentry; !IS_ROOT(temp);) {
struct inode *inode = temp-d_inode;
@@ -1508,7 +1508,7 @@ retry:
temp = temp-d_parent;
}
rcu_read_unlock();
-   if (pos != 0 || read_seqretry(rename_lock, seq)) {
+   if (pos != 0 || read_seqrwretry(rename_lock, seq)) {
pr_err(build_path did not end path lookup where 
   expected, namelen is %d, pos is %d\n, len, pos);
/* presumably this is only possible if racing with a
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 8719bbe..4842523 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -96,7 +96,7 @@ build_path_from_dentry(struct dentry *direntry)
dfsplen = 0;
 cifs_bp_rename_retry:
namelen = dfsplen;
-   seq = read_seqbegin(rename_lock);
+   seq = read_seqrwbegin(rename_lock);
rcu_read_lock();
for (temp = direntry; !IS_ROOT(temp);) {
namelen += (1 + temp-d_name.len);
@@ -136,7 +136,7 @@ cifs_bp_rename_retry:
}
}
rcu_read_unlock();
-   if (namelen != dfsplen || read_seqretry(rename_lock, seq)) {
+   if (namelen != dfsplen || read_seqrwretry(rename_lock, seq)) {
cFYI(1, did not end path lookup where expected. namelen=%d 
dfsplen=%d, namelen, dfsplen);
/* presumably this is only possible if racing with a rename
diff --git a/fs/dcache.c b/fs/dcache.c
index 20cc789..b1487e2 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -29,6 +29,7 @@
 #include asm/uaccess.h
 #include linux/security.h
 #include linux/seqlock.h
+#include linux/seqrwlock.h
 #include linux/swap.h
 #include linux/bootmem.h
 #include linux/fs_struct.h
@@ -82,7 +83,7 @@ int sysctl_vfs_cache_pressure __read_mostly = 100;
 EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
 
 static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lru_lock);
-__cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
+__cacheline_aligned_in_smp DEFINE_SEQRWLOCK(rename_lock);
 
 EXPORT_SYMBOL(rename_lock);
 
@@ -1030,7 +1031,7 @@ static struct dentry *try_to_ascend(struct dentry *old, 
int locked, unsigned seq
 */
if (new != old-d_parent ||
 (old-d_flags  DCACHE_DENTRY_KILLED) ||
-(!locked  read_seqretry(rename_lock, seq))) {
+(!locked  read_seqrwretry(rename_lock, seq))) {
spin_unlock(new-d_lock);
new = NULL;
}
@@ -1059,7 +1060,7 @@ int have_submounts(struct dentry *parent)
unsigned seq;