+++ /dev/null
- fs/inode.c | 1
- fs/namei.c | 66 ++++++++++++++++++++++++++++++++++++++---------------
- include/linux/fs.h | 11 ++++----
- 3 files changed, 54 insertions(+), 24 deletions(-)
-
-Index: linux-2.6.7/fs/namei.c
-===================================================================
---- linux-2.6.7.orig/fs/namei.c 2004-09-06 22:53:19.000000000 +0400
-+++ linux-2.6.7/fs/namei.c 2004-09-07 14:39:44.000000000 +0400
-@@ -103,6 +103,38 @@
- * any extra contention...
- */
-
-+void *lock_dir(struct inode *dir, struct qstr *name)
-+{
-+ unsigned long hash;
-+
-+ if (!IS_PDIROPS(dir)) {
-+ down(&dir->i_sem);
-+ return 0;
-+ }
-+
-+ /* OK. fs understands parallel directory operations.
-+ * so, we try to acquire lock for hash of requested
-+ * filename in order to prevent any operations with
-+ * same name in same time -bzzz */
-+
-+ /* calculate name hash */
-+ hash = full_name_hash(name->name, name->len);
-+
-+ /* lock this hash */
-+ return dynlock_lock(&dir->i_dcache_lock, hash, 1, GFP_ATOMIC);
-+}
-+EXPORT_SYMBOL(lock_dir);
-+
-+void unlock_dir(struct inode *dir, void *lock)
-+{
-+ if (!IS_PDIROPS(dir)) {
-+ up(&dir->i_sem);
-+ return;
-+ }
-+ dynlock_unlock(&dir->i_dcache_lock, lock);
-+}
-+EXPORT_SYMBOL(unlock_dir);
-+
- /* In order to reduce some races, while at the same time doing additional
- * checking and hopefully speeding things up, we copy filenames to the
- * kernel data space before using them..
-@@ -362,8 +394,9 @@
- {
- struct dentry * result;
- struct inode *dir = parent->d_inode;
-+ void *lock;
-
-- down(&dir->i_sem);
-+ lock = lock_dir(dir, name);
- /*
- * First re-do the cached lookup just in case it was created
- * while we waited for the directory semaphore..
-@@ -391,7 +424,7 @@
- else
- result = dentry;
- }
-- up(&dir->i_sem);
-+ unlock_dir(dir, lock);
- return result;
- }
-
-@@ -399,7 +432,7 @@
- * Uhhuh! Nasty case: the cache was re-populated while
- * we waited on the semaphore. Need to revalidate.
- */
-- up(&dir->i_sem);
-+ unlock_dir(dir, lock);
- if (result->d_op && result->d_op->d_revalidate) {
- if (!result->d_op->d_revalidate(result, nd) && !d_invalidate(result)) {
- dput(result);
-@@ -1367,7 +1400,7 @@
-
- dir = nd->dentry;
- nd->flags &= ~LOOKUP_PARENT;
-- down(&dir->d_inode->i_sem);
-+ nd->lock = lock_dir(dir->d_inode, &nd->last);
- nd->flags |= LOOKUP_LAST;
- dentry = __lookup_hash(&nd->last, nd->dentry, nd);
- nd->flags &= ~LOOKUP_LAST;
-@@ -1375,7 +1408,7 @@
- do_last:
- error = PTR_ERR(dentry);
- if (IS_ERR(dentry)) {
-- up(&dir->d_inode->i_sem);
-+ unlock_dir(dir->d_inode, nd->lock);
- goto exit;
- }
-
-@@ -1384,7 +1417,7 @@
- if (!IS_POSIXACL(dir->d_inode))
- mode &= ~current->fs->umask;
- error = vfs_create(dir->d_inode, dentry, mode, nd);
-- up(&dir->d_inode->i_sem);
-+ unlock_dir(dir->d_inode, nd->lock);
- dput(nd->dentry);
- nd->dentry = dentry;
- if (error)
-@@ -1398,7 +1431,7 @@
- /*
- * It already exists.
- */
-- up(&dir->d_inode->i_sem);
-+ unlock_dir(dir->d_inode, nd->lock);
-
- error = -EEXIST;
- if (flag & O_EXCL)
-@@ -1474,7 +1507,7 @@
- goto exit;
- }
- dir = nd->dentry;
-- down(&dir->d_inode->i_sem);
-+ nd->lock = lock_dir(dir->d_inode, &nd->last);
- nd->flags |= LOOKUP_LAST;
- dentry = __lookup_hash(&nd->last, nd->dentry, nd);
- nd->flags &= ~LOOKUP_LAST;
-@@ -1494,7 +1527,7 @@
- {
- struct dentry *dentry;
-
-- down(&nd->dentry->d_inode->i_sem);
-+ nd->lock = lock_dir(nd->dentry->d_inode, &nd->last);
- dentry = ERR_PTR(-EEXIST);
- if (nd->last_type != LAST_NORM)
- goto fail;
-@@ -1589,7 +1622,7 @@
- }
- dput(dentry);
- }
-- up(&nd.dentry->d_inode->i_sem);
-+ unlock_dir(nd.dentry->d_inode, nd.lock);
- out2:
- path_release(&nd);
- out:
-@@ -1652,7 +1685,7 @@
- error = vfs_mkdir(nd.dentry->d_inode, dentry, mode);
- dput(dentry);
- }
-- up(&nd.dentry->d_inode->i_sem);
-+ unlock_dir(nd.dentry->d_inode, nd.lock);
- out2:
- path_release(&nd);
- out:
-@@ -1735,14 +1735,14 @@
- error = -EBUSY;
- goto exit1;
- }
-- down(&nd.dentry->d_inode->i_sem);
-+ nd.lock = lock_dir(nd.dentry->d_inode, &nd.last);
- dentry = lookup_hash(&nd.last, nd.dentry);
- error = PTR_ERR(dentry);
- if (!IS_ERR(dentry)) {
- error = vfs_rmdir(nd.dentry->d_inode, dentry);
- dput(dentry);
- }
-- up(&nd.dentry->d_inode->i_sem);
-+ unlock_dir(nd.dentry->d_inode, nd.lock);
- exit1:
- path_release(&nd);
- exit:
-@@ -1808,7 +1808,7 @@
- error = -EISDIR;
- if (nd.last_type != LAST_NORM)
- goto exit1;
-- down(&nd.dentry->d_inode->i_sem);
-+ nd.lock = lock_dir(nd.dentry->d_inode, &nd.last);
- dentry = lookup_hash(&nd.last, nd.dentry);
- error = PTR_ERR(dentry);
- if (!IS_ERR(dentry)) {
-@@ -1856,7 +1889,7 @@
- exit2:
- dput(dentry);
- }
-- up(&nd.dentry->d_inode->i_sem);
-+ unlock_dir(nd.dentry->d_inode, nd.lock);
- exit1:
- path_release(&nd);
- exit:
-@@ -1927,7 +1960,7 @@
- error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO);
- dput(dentry);
- }
-- up(&nd.dentry->d_inode->i_sem);
-+ unlock_dir(nd.dentry->d_inode, nd.lock);
- out2:
- path_release(&nd);
- out:
-@@ -2021,7 +2054,7 @@
- error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
- dput(new_dentry);
- }
-- up(&nd.dentry->d_inode->i_sem);
-+ unlock_dir(nd.dentry->d_inode, nd.lock);
- out_release:
- path_release(&nd);
- out:
-Index: linux-2.6.7/fs/inode.c
-===================================================================
---- linux-2.6.7.orig/fs/inode.c 2004-09-06 22:53:19.000000000 +0400
-+++ linux-2.6.7/fs/inode.c 2004-09-07 14:39:44.000000000 +0400
-@@ -165,6 +165,7 @@
- }
- memset(&inode->u, 0, sizeof(inode->u));
- inode->i_mapping = mapping;
-+ dynlock_init(&inode->i_dcache_lock);
- }
- return inode;
- }
-Index: linux-2.6.7/include/linux/fs.h
-===================================================================
---- linux-2.6.7.orig/include/linux/fs.h 2004-09-07 14:12:12.000000000 +0400
-+++ linux-2.6.7/include/linux/fs.h 2004-09-07 14:39:44.000000000 +0400
-@@ -19,6 +19,7 @@
- #include <linux/prio_tree.h>
- #include <linux/kobject.h>
- #include <asm/atomic.h>
-+#include <linux/dynlocks.h>
-
- struct iovec;
- struct nameidata;
-@@ -141,6 +142,7 @@
- #define S_NOQUOTA 64 /* Inode is not counted to quota */
- #define S_DIRSYNC 128 /* Directory modifications are synchronous */
- #define S_NOCMTIME 256 /* Do not update file c/mtime */
-+#define S_PDIROPS 512 /* Parallel directory operations */
-
- /*
- * Note that nosuid etc flags are inode-specific: setting some file-system
-@@ -172,6 +174,7 @@
- #define IS_NODIRATIME(inode) __IS_FLG(inode, MS_NODIRATIME)
- #define IS_POSIXACL(inode) __IS_FLG(inode, MS_POSIXACL)
- #define IS_ONE_SECOND(inode) __IS_FLG(inode, MS_ONE_SECOND)
-+#define IS_PDIROPS(inode) __IS_FLG(inode, S_PDIROPS)
-
- #define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD)
- #define IS_NOCMTIME(inode) ((inode)->i_flags & S_NOCMTIME)
-@@ -463,6 +466,7 @@
- atomic_t i_writecount;
- void *i_security;
- __u32 i_generation;
-+ struct dynlock i_dcache_lock; /* for parallel directory ops */
- union {
- void *generic_ip;
- } u;
-Index: linux-2.6.7/include/linux/namei.h
-===================================================================
---- linux-2.6.7.orig/include/linux/namei.h 2004-09-06 22:53:19.000000000 +0400
-+++ linux-2.6.7/include/linux/namei.h 2004-09-07 14:40:06.000000000 +0400
-@@ -52,6 +52,7 @@
- unsigned int flags;
- int last_type;
-+ void *lock;
-
- /* Intent data */
- union {
- struct open_intent open;