--- /dev/null
+diff -rupN linux-2.6.18-128.1.6_1/fs/ext3/Makefile linux-2.6.18-128.1.6_2/fs/ext3/Makefile
+--- linux-2.6.18-128.1.6_1/fs/ext3/Makefile 2009-08-13 19:19:54.000000000 +0530
++++ linux-2.6.18-128.1.6_2/fs/ext3/Makefile 2009-08-13 19:20:30.000000000 +0530
+@@ -5,7 +5,8 @@
+ obj-$(CONFIG_EXT3_FS) += ext3.o
+
+ ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o iopen.o \
+- ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o mballoc.o
++ ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \
++ mballoc.o dynlocks.o
+
+ ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
+ ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o
+diff -rupN linux-2.6.18-128.1.6_1/fs/ext3/super.c linux-2.6.18-128.1.6_2/fs/ext3/super.c
+--- linux-2.6.18-128.1.6_1/fs/ext3/super.c 2009-08-13 19:19:54.000000000 +0530
++++ linux-2.6.18-128.1.6_2/fs/ext3/super.c 2009-08-13 19:23:23.000000000 +0530
+@@ -3529,6 +3530,7 @@ static int __init init_ext3_fs(void)
+ err = init_inodecache();
+ if (err)
+ goto out1;
++ dynlock_cache_init();
+ err = register_filesystem(&ext3_fs_type);
+ if (err)
+ goto out;
+@@ -3546,6 +3548,7 @@ out1:
+ static void __exit exit_ext3_fs(void)
+ {
+ unregister_filesystem(&ext3_fs_type);
++ dynlock_cache_exit();
+ destroy_inodecache();
+ exit_ext3_xattr();
+ exit_ext3_proc();
+
--- /dev/null
+diff -rupN linux-2.6.18-128.1.6_1/fs/ext3/dynlocks.c linux-2.6.18-128.1.6_2/fs/ext3/dynlocks.c
+--- linux-2.6.18-128.1.6_1/fs/ext3/dynlocks.c 1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.18-128.1.6_2/fs/ext3/dynlocks.c 2009-08-13 20:42:59.000000000 +0530
+@@ -0,0 +1,236 @@
++/*
++ * Dynamic Locks
++ *
++ * struct dynlock is lockspace
++ * one may request lock (exclusive or shared) for some value
++ * in that lockspace
++ *
++ */
++
++#include <linux/dynlocks.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++
++#define DYNLOCK_HANDLE_MAGIC 0xd19a10c
++#define DYNLOCK_HANDLE_DEAD 0xd1956ee
++#define DYNLOCK_LIST_MAGIC 0x11ee91e6
++
++static kmem_cache_t * dynlock_cachep = NULL;
++
++struct dynlock_handle {
++ unsigned dh_magic;
++ struct list_head dh_list;
++ unsigned long dh_value; /* lock value */
++ int dh_refcount; /* number of users */
++ int dh_readers;
++ int dh_writers;
++ int dh_pid; /* holder of the lock */
++ wait_queue_head_t dh_wait;
++};
++
++int __init dynlock_cache_init(void)
++{
++ int rc = 0;
++
++ printk(KERN_INFO "init dynlocks cache\n");
++ dynlock_cachep = kmem_cache_create("dynlock_cache",
++ sizeof(struct dynlock_handle),
++ 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL, NULL);
++ if (dynlock_cachep == NULL) {
++ printk(KERN_ERR "Not able to create dynlock cache");
++ rc = -ENOMEM;
++ }
++ return rc;
++}
++
++void __exit dynlock_cache_exit(void)
++{
++ printk(KERN_INFO "exit dynlocks cache\n");
++ kmem_cache_destroy(dynlock_cachep);
++}
++
++/*
++ * dynlock_init
++ *
++ * initialize lockspace
++ *
++ */
++void dynlock_init(struct dynlock *dl)
++{
++ spin_lock_init(&dl->dl_list_lock);
++ INIT_LIST_HEAD(&dl->dl_list);
++ dl->dl_magic = DYNLOCK_LIST_MAGIC;
++}
++EXPORT_SYMBOL(dynlock_init);
++
++/*
++ * dynlock_lock
++ *
++ * acquires lock (exclusive or shared) in specified lockspace
++ * each lock in lockspace is allocated separately, so user have
++ * to specify GFP flags.
++ * routine returns pointer to lock. this pointer is intended to
++ * be passed to dynlock_unlock
++ *
++ */
++struct dynlock_handle *dynlock_lock(struct dynlock *dl, unsigned long value,
++ enum dynlock_type lt, gfp_t gfp)
++{
++ struct dynlock_handle *nhl = NULL;
++ struct dynlock_handle *hl;
++
++ BUG_ON(dl == NULL);
++ BUG_ON(dl->dl_magic != DYNLOCK_LIST_MAGIC);
++
++repeat:
++ /* find requested lock in lockspace */
++ spin_lock(&dl->dl_list_lock);
++ BUG_ON(dl->dl_list.next == NULL);
++ BUG_ON(dl->dl_list.prev == NULL);
++ list_for_each_entry(hl, &dl->dl_list, dh_list) {
++ BUG_ON(hl->dh_list.next == NULL);
++ BUG_ON(hl->dh_list.prev == NULL);
++ BUG_ON(hl->dh_magic != DYNLOCK_HANDLE_MAGIC);
++ if (hl->dh_value == value) {
++ /* lock is found */
++ if (nhl) {
++ /* someone else just allocated
++ * lock we didn't find and just created
++ * so, we drop our lock
++ */
++ kmem_cache_free(dynlock_cachep, nhl);
++ nhl = NULL;
++ }
++ hl->dh_refcount++;
++ goto found;
++ }
++ }
++ /* lock not found */
++ if (nhl) {
++ /* we already have allocated lock. use it */
++ hl = nhl;
++ nhl = NULL;
++ list_add(&hl->dh_list, &dl->dl_list);
++ goto found;
++ }
++ spin_unlock(&dl->dl_list_lock);
++
++ /* lock not found and we haven't allocated lock yet. allocate it */
++ nhl = kmem_cache_alloc(dynlock_cachep, gfp);
++ if (nhl == NULL)
++ return NULL;
++ nhl->dh_refcount = 1;
++ nhl->dh_value = value;
++ nhl->dh_readers = 0;
++ nhl->dh_writers = 0;
++ nhl->dh_magic = DYNLOCK_HANDLE_MAGIC;
++ init_waitqueue_head(&nhl->dh_wait);
++
++ /* while lock is being allocated, someone else may allocate it
++ * and put onto to list. check this situation
++ */
++ goto repeat;
++
++found:
++ if (lt == DLT_WRITE) {
++ /* exclusive lock: user don't want to share lock at all
++ * NOTE: one process may take the same lock several times
++ * this functionaly is useful for rename operations */
++ while ((hl->dh_writers && hl->dh_pid != current->pid) ||
++ hl->dh_readers) {
++ spin_unlock(&dl->dl_list_lock);
++ wait_event(hl->dh_wait,
++ hl->dh_writers == 0 && hl->dh_readers == 0);
++ spin_lock(&dl->dl_list_lock);
++ }
++ hl->dh_writers++;
++ } else {
++ /* shared lock: user do not want to share lock with writer */
++ while (hl->dh_writers) {
++ spin_unlock(&dl->dl_list_lock);
++ wait_event(hl->dh_wait, hl->dh_writers == 0);
++ spin_lock(&dl->dl_list_lock);
++ }
++ hl->dh_readers++;
++ }
++ hl->dh_pid = current->pid;
++ spin_unlock(&dl->dl_list_lock);
++
++ return hl;
++}
++EXPORT_SYMBOL(dynlock_lock);
++
++
++/*
++ * dynlock_unlock
++ *
++ * user have to specify lockspace (dl) and pointer to lock structure
++ * returned by dynlock_lock()
++ *
++ */
++void dynlock_unlock(struct dynlock *dl, struct dynlock_handle *hl)
++{
++ int wakeup = 0;
++
++ BUG_ON(dl == NULL);
++ BUG_ON(hl == NULL);
++ BUG_ON(dl->dl_magic != DYNLOCK_LIST_MAGIC);
++
++ if (hl->dh_magic != DYNLOCK_HANDLE_MAGIC)
++ printk(KERN_EMERG "wrong lock magic: %#x\n", hl->dh_magic);
++
++ BUG_ON(hl->dh_magic != DYNLOCK_HANDLE_MAGIC);
++ BUG_ON(hl->dh_writers != 0 && current->pid != hl->dh_pid);
++
++ spin_lock(&dl->dl_list_lock);
++ if (hl->dh_writers) {
++ BUG_ON(hl->dh_readers != 0);
++ hl->dh_writers--;
++ if (hl->dh_writers == 0)
++ wakeup = 1;
++ } else if (hl->dh_readers) {
++ hl->dh_readers--;
++ if (hl->dh_readers == 0)
++ wakeup = 1;
++ } else {
++ BUG();
++ }
++ if (wakeup) {
++ hl->dh_pid = 0;
++ wake_up(&hl->dh_wait);
++ }
++ if (--(hl->dh_refcount) == 0) {
++ hl->dh_magic = DYNLOCK_HANDLE_DEAD;
++ list_del(&hl->dh_list);
++ kmem_cache_free(dynlock_cachep, hl);
++ }
++ spin_unlock(&dl->dl_list_lock);
++}
++EXPORT_SYMBOL(dynlock_unlock);
++
++int dynlock_is_locked(struct dynlock *dl, unsigned long value)
++{
++ struct dynlock_handle *hl;
++ int result = 0;
++
++ /* find requested lock in lockspace */
++ spin_lock(&dl->dl_list_lock);
++ BUG_ON(dl->dl_list.next == NULL);
++ BUG_ON(dl->dl_list.prev == NULL);
++ list_for_each_entry(hl, &dl->dl_list, dh_list) {
++ BUG_ON(hl->dh_list.next == NULL);
++ BUG_ON(hl->dh_list.prev == NULL);
++ BUG_ON(hl->dh_magic != DYNLOCK_HANDLE_MAGIC);
++ if (hl->dh_value == value && hl->dh_pid == current->pid) {
++ /* lock is found */
++ result = 1;
++ break;
++ }
++ }
++ spin_unlock(&dl->dl_list_lock);
++ return result;
++}
++EXPORT_SYMBOL(dynlock_is_locked);
+diff -rupN linux-2.6.18-128.1.6_1/include/linux/dynlocks.h linux-2.6.18-128.1.6_2/include/linux/dynlocks.h
+--- linux-2.6.18-128.1.6_1/include/linux/dynlocks.h 1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.18-128.1.6_2/include/linux/dynlocks.h 2009-08-13 20:43:18.000000000 +0530
+@@ -0,0 +1,34 @@
++#ifndef _LINUX_DYNLOCKS_H
++#define _LINUX_DYNLOCKS_H
++
++#include <linux/list.h>
++#include <linux/wait.h>
++
++struct dynlock_handle;
++
++/*
++ * lock's namespace:
++ * - list of locks
++ * - lock to protect this list
++ */
++struct dynlock {
++ unsigned dl_magic;
++ struct list_head dl_list;
++ spinlock_t dl_list_lock;
++};
++
++enum dynlock_type {
++ DLT_WRITE,
++ DLT_READ
++};
++
++int dynlock_cache_init(void);
++void dynlock_cache_exit(void);
++void dynlock_init(struct dynlock *dl);
++struct dynlock_handle *dynlock_lock(struct dynlock *dl, unsigned long value,
++ enum dynlock_type lt, gfp_t gfp);
++void dynlock_unlock(struct dynlock *dl, struct dynlock_handle *lock);
++int dynlock_is_locked(struct dynlock *dl, unsigned long value);
++
++#endif
++
if (ext3_should_journal_data(inode))
ret = 3 * (bpp + indirects) + 2;
else
-Index: linux-2.6.16.54-0.2.5/fs/ext3/Makefile
+Index: linux-2.6.18.8/fs/ext3/Makefile
===================================================================
---- linux-2.6.16.54-0.2.5.orig/fs/ext3/Makefile
-+++ linux-2.6.16.54-0.2.5/fs/ext3/Makefile
-@@ -5,7 +5,8 @@
+--- linux-2.6.18.8.orig/fs/ext3/Makefile 2007-07-17 09:18:11.000000000 +0200
++++ linux-2.6.18.8/fs/ext3/Makefile 2007-07-17 11:08:11.000000000 +0200
+@@ -5,7 +5,7 @@
obj-$(CONFIG_EXT3_FS) += ext3.o
ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o iopen.o \
- ioctl.o namei.o super.o symlink.o hash.o resize.o
-+ ioctl.o namei.o super.o symlink.o hash.o resize.o \
-+ extents.o
++ ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o
ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o
--- /dev/null
+Index: linux-stage/fs/ext3/namei.c
+===================================================================
+--- linux-stage.orig/fs/ext3/namei.c 2009-08-10 22:31:03.000000000 +0800
++++ linux-stage/fs/ext3/namei.c 2009-08-10 22:33:38.000000000 +0800
+@@ -1471,6 +1471,72 @@
+ }
+ #endif
+
++/* update ".." for hash-indexed directory, split the item "." if necessary */
++static int ext3_update_dotdot(handle_t *handle, struct dentry *dentry,
++ struct inode *inode)
++{
++ struct inode * dir = dentry->d_parent->d_inode;
++ struct buffer_head * dir_block;
++ struct ext3_dir_entry_2 * de;
++ int len, journal = 0, err = 0;
++
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ if (IS_DIRSYNC(dir))
++ handle->h_sync = 1;
++
++ dir_block = ext3_bread(handle, dir, 0, 0, &err);
++ if (!dir_block)
++ goto out;
++
++ de = (struct ext3_dir_entry_2 *)dir_block->b_data;
++ /* the first item must be "." */
++ assert(de->name_len == 1 && de->name[0] == '.');
++ len = le16_to_cpu(de->rec_len);
++ assert(len >= EXT3_DIR_REC_LEN(1));
++ if (len > EXT3_DIR_REC_LEN(1)) {
++ BUFFER_TRACE(dir_block, "get_write_access");
++ err = ext3_journal_get_write_access(handle, dir_block);
++ if (err)
++ goto out_journal;
++
++ journal = 1;
++ de->rec_len = cpu_to_le16(EXT3_DIR_REC_LEN(1));
++ }
++
++ len -= EXT3_DIR_REC_LEN(1);
++ assert(len == 0 || len >= EXT3_DIR_REC_LEN(2));
++ de = (struct ext3_dir_entry_2 *)
++ ((char *) de + le16_to_cpu(de->rec_len));
++ if (!journal) {
++ BUFFER_TRACE(dir_block, "get_write_access");
++ err = ext3_journal_get_write_access(handle, dir_block);
++ if (err)
++ goto out_journal;
++ }
++
++ de->inode = cpu_to_le32(inode->i_ino);
++ if (len > 0)
++ de->rec_len = cpu_to_le16(len);
++ else
++ assert(le16_to_cpu(de->rec_len) >= EXT3_DIR_REC_LEN(2));
++ de->name_len = 2;
++ strcpy (de->name, "..");
++ ext3_set_de_type(dir->i_sb, de, S_IFDIR);
++
++out_journal:
++ if (journal) {
++ BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata");
++ err = ext3_journal_dirty_metadata(handle, dir_block);
++ ext3_mark_inode_dirty(handle, dir);
++ }
++ brelse (dir_block);
++
++out:
++ return err;
++}
++
+ /*
+ * ext3_add_entry()
+ *
+@@ -1502,6 +1568,9 @@
+ return -EINVAL;
+ #ifdef CONFIG_EXT3_INDEX
+ if (is_dx(dir)) {
++ if (dentry->d_name.len == 2 &&
++ memcmp(dentry->d_name.name, "..", 2) == 0)
++ return ext3_update_dotdot(handle, dentry, inode);
+ retval = ext3_dx_add_entry(handle, dentry, inode);
+ if (!retval || (retval != ERR_BAD_DX_DIR))
+ return retval;
/*
* TODO: optimization is possible here
* probably we need not scaning at all,
-Index: linux-2.6.16.46-0.14/fs/ext3/Makefile
+Index: linux-2.6.18.8/fs/ext3/Makefile
===================================================================
---- linux-2.6.16.46-0.14.orig/fs/ext3/Makefile
-+++ linux-2.6.16.46-0.14/fs/ext3/Makefile
-@@ -6,7 +6,7 @@ obj-$(CONFIG_EXT3_FS) += ext3.o
+--- linux-2.6.18.8.orig/fs/ext3/Makefile
++++ linux-2.6.18.8/fs/ext3/Makefile
+@@ -5,7 +5,7 @@
+ obj-$(CONFIG_EXT3_FS) += ext3.o
ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o iopen.o \
- ioctl.o namei.o super.o symlink.o hash.o resize.o \
-- extents.o
-+ extents.o mballoc.o
+- ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o
++ ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o mballoc.o
ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o
return -EMLINK;
retry:
+@@ -1782,7 +1793,7 @@ retry:
+ inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize;
+ dir_block = ext3_bread (handle, inode, 0, 1, &err);
+ if (!dir_block) {
+- inode->i_nlink--; /* is this nlink == 0? */
++ drop_nlink(inode); /* is this nlink == 0? */
+ ext3_mark_inode_dirty(handle, inode);
+ iput (inode);
+ goto out_stop;
@@ -1758,7 +1764,7 @@ retry:
iput (inode);
goto out_stop;
--- /dev/null
+Index: linux-2.6.16.60-0.33_org/fs/ext3/hash.c
+===================================================================
+--- linux-2.6.16.60-0.33_org/fs/ext3/hash.c 2009-07-01 18:16:50.000000000 +0530
++++ linux-2.6.16.60-0.33_new/fs/ext3/hash.c 2009-07-01 18:26:58.000000000 +0530
+@@ -8,7 +8,7 @@
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ */
+-
++#include <linux/module.h>
+ #include <linux/fs.h>
+ #include <linux/jbd.h>
+ #include <linux/sched.h>
+@@ -173,3 +173,4 @@ int ext3fs_dirhash(const char *name, int
+ hinfo->minor_hash = minor_hash;
+ return 0;
+ }
++EXPORT_SYMBOL(ext3fs_dirhash);
+Index: linux-2.6.16.60-0.33_org/fs/ext3/namei.c
+===================================================================
+--- linux-2.6.16.60-0.33_org/fs/ext3/namei.c 2009-07-01 18:16:50.000000000 +0530
++++ linux-2.6.16.60-0.33_new/fs/ext3/namei.c 2009-07-01 18:24:49.000000000 +0530
+@@ -75,6 +75,7 @@ struct buffer_head *ext3_append(handle_t
+
+ return bh;
+ }
++EXPORT_SYMBOL(ext3_append);
+
+ #ifndef assert
+ #define assert(test) J_ASSERT(test)
+Index: linux-2.6.16.60-0.33_org/fs/ext3/super.c
+===================================================================
+--- linux-2.6.16.60-0.33_org/fs/ext3/super.c 2009-07-01 18:16:50.000000000 +0530
++++ linux-2.6.16.60-0.33_new/fs/ext3/super.c 2009-07-01 18:24:27.000000000 +0530
+@@ -260,6 +260,7 @@ void __ext3_std_error (struct super_bloc
+
+ ext3_handle_error(sb);
+ }
++EXPORT_SYMBOL(__ext3_std_error);
+
+ /*
+ * ext3_abort is a much stronger failure handler than ext3_error. The
+Index: linux-2.6.16.60-0.33_org/include/linux/ext3_fs.h
+===================================================================
+--- linux-2.6.16.60-0.33_org/include/linux/ext3_fs.h 2009-07-01 18:16:50.000000000 +0530
++++ linux-2.6.16.60-0.33_new/include/linux/ext3_fs.h 2009-07-01 18:22:09.000000000 +0530
+@@ -1055,6 +1055,8 @@ extern void ext3_abort (struct super_blo
+ extern void ext3_warning (struct super_block *, const char *, const char *, ...)
+ __attribute__ ((format (printf, 3, 4)));
+ extern void ext3_update_dynamic_rev (struct super_block *sb);
++extern void __ext3_std_error (struct super_block * sb, const char * function,
++ int errno);
+
+ #define ext3_std_error(sb, errno) \
+ do { \
+@@ -1076,6 +1078,8 @@ extern struct file_operations ext3_file_
+ /* namei.c */
+ extern struct inode_operations ext3_dir_inode_operations;
+ extern struct inode_operations ext3_special_inode_operations;
++extern struct buffer_head *ext3_append(handle_t *handle, struct inode *inode,
++ u32 *block, int *err);
+
+ /* symlink.c */
+ extern struct inode_operations ext3_symlink_inode_operations;
+
--- /dev/null
+diff -rupN linux-2.6.18-128.1.6_1/fs/ext3/namei.c linux-2.6.18-128.1.6_2/fs/ext3/namei.c
+--- linux-2.6.18-128.1.6_1/fs/ext3/namei.c 2009-08-13 19:07:07.000000000 +0530
++++ linux-2.6.18-128.1.6_2/fs/ext3/namei.c 2009-08-13 19:10:43.000000000 +0530
+@@ -24,6 +24,7 @@
+ * Theodore Ts'o, 2002
+ */
+
++#include <linux/module.h>
+ #include <linux/fs.h>
+ #include <linux/pagemap.h>
+ #include <linux/jbd.h>
+@@ -841,7 +842,7 @@ static inline int search_dirblock(struct
+ * The returned buffer_head has ->b_count elevated. The caller is expected
+ * to brelse() it when appropriate.
+ */
+-static struct buffer_head * ext3_find_entry (struct dentry *dentry,
++struct buffer_head * ext3_find_entry (struct dentry *dentry,
+ struct ext3_dir_entry_2 ** res_dir)
+ {
+ struct super_block * sb;
+@@ -953,6 +954,7 @@ cleanup_and_exit:
+ brelse (bh_use[ra_ptr]);
+ return ret;
+ }
++EXPORT_SYMBOL(ext3_find_entry);
+
+ #ifdef CONFIG_EXT3_INDEX
+ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
+@@ -1489,7 +1491,7 @@ static int make_indexed_dir(handle_t *ha
+ * may not sleep between calling this and putting something into
+ * the entry, as someone else might have used it while you slept.
+ */
+-static int ext3_add_entry (handle_t *handle, struct dentry *dentry,
++int ext3_add_entry (handle_t *handle, struct dentry *dentry,
+ struct inode *inode)
+ {
+ struct inode *dir = dentry->d_parent->d_inode;
+@@ -1542,6 +1544,7 @@ static int ext3_add_entry (handle_t *han
+ de->rec_len = cpu_to_le16(blocksize);
+ return add_dirent_to_buf(handle, dentry, inode, de, bh);
+ }
++EXPORT_SYMBOL(ext3_add_entry);
+
+ #ifdef CONFIG_EXT3_INDEX
+ /*
+@@ -1684,10 +1687,10 @@ cleanup:
+ * ext3_delete_entry deletes a directory entry by merging it with the
+ * previous entry
+ */
+-static int ext3_delete_entry (handle_t *handle,
+- struct inode * dir,
+- struct ext3_dir_entry_2 * de_del,
+- struct buffer_head * bh)
++int ext3_delete_entry (handle_t *handle,
++ struct inode * dir,
++ struct ext3_dir_entry_2 * de_del,
++ struct buffer_head * bh)
+ {
+ struct ext3_dir_entry_2 * de, * pde;
+ int i;
+@@ -1719,6 +1722,7 @@ static int ext3_delete_entry (handle_t *
+ }
+ return -ENOENT;
+ }
++EXPORT_SYMBOL(ext3_delete_entry);
+
+ /*
+ * ext3_mark_inode_dirty is somewhat expensive, so unlike ext2 we
+@@ -1774,6 +1778,26 @@ static struct inode * ext3_new_inode_wan
+ return ext3_new_inode(handle, dir, mode, inum);
+ }
+
++struct inode * ext3_create_inode(handle_t *handle, struct inode * dir, int mode)
++{
++ struct inode *inode;
++
++ inode = ext3_new_inode(handle, dir, mode, 0);
++ if (!IS_ERR(inode)) {
++ if (S_ISCHR(mode) || S_ISBLK(mode) || S_ISFIFO(mode)) {
++#ifdef CONFIG_LDISKFS_FS_XATTR
++ inode->i_op = &ext3_special_inode_operations;
++#endif
++ } else {
++ inode->i_op = &ext3_file_inode_operations;
++ inode->i_fop = &ext3_file_operations;
++ ext3_set_aops(inode);
++ }
++ }
++ return inode;
++}
++EXPORT_SYMBOL(ext3_create_inode);
++
+ /*
+ * By the time this is called, we already have created
+ * the directory cache entry for the new file, but it
+@@ -1848,42 +1872,28 @@ retry:
+ return err;
+ }
+
+-static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode)
++/* Initialize @inode as a subdirectory of @dir, and add the
++ * "." and ".." entries into the first directory block. */
++int ext3_add_dot_dotdot(handle_t *handle, struct inode * dir,
++ struct inode *inode)
+ {
+- handle_t *handle;
+- struct inode * inode;
+ struct buffer_head * dir_block;
+ struct ext3_dir_entry_2 * de;
+- int err, retries = 0;
+-
+- if (EXT3_DIR_LINK_MAX(dir))
+- return -EMLINK;
++ int err = 0;
+
+-retry:
+- handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
+- EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
+- 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ if (IS_DIRSYNC(dir))
+ handle->h_sync = 1;
+
+- inode = ext3_new_inode_wantedi (handle, dir, S_IFDIR | mode, dentry);
+- err = PTR_ERR(inode);
+- if (IS_ERR(inode))
+- goto out_stop;
+-
+ inode->i_op = &ext3_dir_inode_operations;
+ inode->i_fop = &ext3_dir_operations;
+ inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize;
+ dir_block = ext3_bread (handle, inode, 0, 1, &err);
+- if (!dir_block) {
+- drop_nlink(inode); /* is this nlink == 0? */
+- ext3_mark_inode_dirty(handle, inode);
+- iput (inode);
+- goto out_stop;
+- }
++ if (!dir_block)
++ goto get_out;
++
+ BUFFER_TRACE(dir_block, "get_write_access");
+ ext3_journal_get_write_access(handle, dir_block);
+ de = (struct ext3_dir_entry_2 *) dir_block->b_data;
+@@ -1904,6 +1914,45 @@ retry:
+ ext3_journal_dirty_metadata(handle, dir_block);
+ brelse (dir_block);
+ ext3_mark_inode_dirty(handle, inode);
++
++get_out:
++ return err;
++
++}
++EXPORT_SYMBOL(ext3_add_dot_dotdot);
++
++static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode)
++{
++ handle_t *handle;
++ struct inode * inode;
++ int err, retries = 0;
++
++ if (EXT3_DIR_LINK_MAX(dir))
++ return -EMLINK;
++
++retry:
++ handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
++ EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
++ 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ if (IS_DIRSYNC(dir))
++ handle->h_sync = 1;
++
++ inode = ext3_new_inode_wantedi (handle, dir, S_IFDIR | mode, dentry);
++ err = PTR_ERR(inode);
++ if (IS_ERR(inode))
++ goto out_stop;
++
++ err = ext3_add_dot_dotdot(handle, dir, inode);
++ if (err) {
++ inode->i_nlink = 0;
++ ext3_mark_inode_dirty(handle, inode);
++ iput (inode);
++ goto out_stop;
++ }
++
+ err = ext3_add_entry (handle, dentry, inode);
+ if (err) {
+ inode->i_nlink = 0;
+diff -rupN linux-2.6.18-128.1.6_1/include/linux/ext3_fs.h linux-2.6.18-128.1.6_2/include/linux/ext3_fs.h
+--- linux-2.6.18-128.1.6_1/include/linux/ext3_fs.h 2009-08-13 19:07:07.000000000 +0530
++++ linux-2.6.18-128.1.6_2/include/linux/ext3_fs.h 2009-08-13 19:14:07.000000000 +0530
+@@ -1076,6 +1076,10 @@ extern int ext3_group_extend(struct supe
+ ext3_fsblk_t n_blocks_count);
+
+ /* super.c */
++extern int ext3_xattr_set_handle(handle_t *handle, struct inode *inode,
++ int name_index, const char *name,
++ const void *value, size_t value_len,
++ int flags);
+ extern struct proc_dir_entry *proc_root_ext3;
+ extern int __init init_ext3_proc(void);
+ extern void exit_ext3_proc(void);
+@@ -1107,6 +1111,19 @@ extern struct inode_operations ext3_file
+ extern const struct file_operations ext3_file_operations;
+
+ /* namei.c */
++extern struct inode *ext3_create_inode(handle_t *handle,
++ struct inode * dir, int mode);
++extern int ext3_add_entry(handle_t *handle, struct dentry *dentry,
++ struct inode *inode);
++extern int ext3_delete_entry(handle_t *handle,
++ struct inode * dir,
++ struct ext3_dir_entry_2 * de_del,
++ struct buffer_head * bh);
++extern struct buffer_head * ext3_find_entry(struct dentry *dentry,
++ struct ext3_dir_entry_2
++ ** res_dir);
++extern int ext3_add_dot_dotdot(handle_t *handle, struct inode *dir,
++ struct inode *inode);
+ extern struct inode_operations ext3_dir_inode_operations;
+ extern struct inode_operations ext3_special_inode_operations;
+
+
--- /dev/null
+diff -rupN linux-2.6.18-128.1.6_1/fs/ext3/namei.c linux-2.6.18-128.1.6_2/fs/ext3/namei.c
+--- linux-2.6.18-128.1.6_1/fs/ext3/namei.c 2009-08-13 19:27:12.000000000 +0530
++++ linux-2.6.18-128.1.6_2/fs/ext3/namei.c 2009-08-13 19:33:34.000000000 +0530
+@@ -51,19 +51,25 @@
+ #define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
+ #define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b))
+
+-static struct buffer_head *ext3_append(handle_t *handle,
++struct buffer_head *ext3_append(handle_t *handle,
+ struct inode *inode,
+ u32 *block, int *err)
+ {
+ struct buffer_head *bh;
++ struct ext3_inode_info *ei = EXT3_I(inode);
++
++ /* with parallel dir operations all appends
++ * have to be serialized -bzzz */
++ down(&ei->i_append_sem);
+
+ *block = inode->i_size >> inode->i_sb->s_blocksize_bits;
+
+- if ((bh = ext3_bread(handle, inode, *block, 1, err))) {
++ bh = ext3_bread(handle, inode, *block, 1, err);
++ if (bh != NULL) {
+ inode->i_size += inode->i_sb->s_blocksize;
+- EXT3_I(inode)->i_disksize = inode->i_size;
+- ext3_journal_get_write_access(handle,bh);
++ ei->i_disksize = inode->i_size;
+ }
++ up(&ei->i_append_sem);
+ return bh;
+ }
+
+diff -rupN linux-2.6.18-128.1.6_1/fs/ext3/super.c linux-2.6.18-128.1.6_2/fs/ext3/super.c
+--- linux-2.6.18-128.1.6_1/fs/ext3/super.c 2009-08-13 19:27:12.000000000 +0530
++++ linux-2.6.18-128.1.6_2/fs/ext3/super.c 2009-08-13 19:27:40.000000000 +0530
+@@ -481,6 +481,9 @@ static struct inode *ext3_alloc_inode(st
+ ei->i_acl = EXT3_ACL_NOT_CACHED;
+ ei->i_default_acl = EXT3_ACL_NOT_CACHED;
+ #endif
++ dynlock_init(&ei->i_htree_lock);
++ sema_init(&ei->i_append_sem, 1);
++
+ ei->i_block_alloc_info = NULL;
+ ei->vfs_inode.i_version = 1;
+
+diff -rupN linux-2.6.18-128.1.6_1/include/linux/ext3_fs_i.h linux-2.6.18-128.1.6_2/include/linux/ext3_fs_i.h
+--- linux-2.6.18-128.1.6_1/include/linux/ext3_fs_i.h 2009-08-13 19:27:12.000000000 +0530
++++ linux-2.6.18-128.1.6_2/include/linux/ext3_fs_i.h 2009-08-13 19:31:22.000000000 +0530
+@@ -16,6 +16,7 @@
+ #ifndef _LINUX_EXT3_FS_I
+ #define _LINUX_EXT3_FS_I
+
++#include <linux/dynlocks.h>
+ #include <linux/rwsem.h>
+ #include <linux/rbtree.h>
+ #include <linux/seqlock.h>
+@@ -104,6 +105,10 @@ struct ext3_inode_info {
+ /* block reservation info */
+ struct ext3_block_alloc_info *i_block_alloc_info;
+
++ /* following fields for parallel directory operations -bzzz */
++ struct dynlock i_htree_lock;
++ struct semaphore i_append_sem;
++
+ __u32 i_dir_start_lookup;
+ #ifdef CONFIG_EXT3_FS_XATTR
+ /*
--- /dev/null
+diff -rupN linux-2.6.27.21-0.1_1//fs/ext4/Makefile linux-2.6.27.21-0.1_2//fs/ext4/Makefile
+--- linux-2.6.27.21-0.1_1//fs/ext4/Makefile 2009-08-21 15:12:51.000000000 +0530
++++ linux-2.6.27.21-0.1_2//fs/ext4/Makefile 2009-08-21 15:13:23.000000000 +0530
+@@ -6,7 +6,7 @@ obj-$(CONFIG_EXT4DEV_FS) += ext4dev.o
+
+ ext4dev-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o iopen.o \
+ ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \
+- ext4_jbd2.o migrate.o mballoc.o
++ ext4_jbd2.o migrate.o mballoc.o dynlocks.o
+
+ ext4dev-$(CONFIG_EXT4DEV_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
+ ext4dev-$(CONFIG_EXT4DEV_FS_POSIX_ACL) += acl.o
+diff -rupN linux-2.6.27.21-0.1_1//fs/ext4/super.c linux-2.6.27.21-0.1_2//fs/ext4/super.c
+--- linux-2.6.27.21-0.1_1//fs/ext4/super.c 2009-08-21 15:12:51.000000000 +0530
++++ linux-2.6.27.21-0.1_2//fs/ext4/super.c 2009-08-21 15:18:18.000000000 +0530
+@@ -4126,6 +4126,7 @@ static int __init init_ext4_fs(void)
+ err = init_inodecache();
+ if (err)
+ goto out1;
++ dynlock_cache_init();
+ err = register_filesystem(&ext4_fs_type);
+ if (err)
+ goto out;
+@@ -4149,6 +4150,7 @@ static void __exit exit_ext4_fs(void)
+ unregister_filesystem(&ext4_fs_type);
+ unregister_filesystem(&ext4dev_fs_type);
+ destroy_inodecache();
++ dynlock_cache_exit();
+ exit_ext4_xattr();
+ exit_ext4_mballoc();
+ remove_proc_entry("fs/ext4", NULL);
+
--- /dev/null
+diff -rupN 2.6.27.21/fs/ext4/dynlocks.c 2.6.27.21_1//fs/ext4/dynlocks.c
+--- 2.6.27.21/fs/ext4/dynlocks.c 1970-01-01 05:30:00.000000000 +0530
++++ 2.6.27.21_1//fs/ext4/dynlocks.c 2009-08-23 10:39:59.000000000 +0530
+@@ -0,0 +1,238 @@
++/*
++ * Dynamic Locks
++ *
++ * struct dynlock is lockspace
++ * one may request lock (exclusive or shared) for some value
++ * in that lockspace
++ *
++ */
++
++#include <linux/dynlocks.h>
++#include <linux/module.h>
++#include <linux/slab_def.h>
++#include <linux/sched.h>
++
++#define DYNLOCK_HANDLE_MAGIC 0xd19a10c
++#define DYNLOCK_HANDLE_DEAD 0xd1956ee
++#define DYNLOCK_LIST_MAGIC 0x11ee91e6
++
++typedef struct kmem_cache kmem_cache_t;
++
++static kmem_cache_t * dynlock_cachep = NULL;
++
++struct dynlock_handle {
++ unsigned dh_magic;
++ struct list_head dh_list;
++ unsigned long dh_value; /* lock value */
++ int dh_refcount; /* number of users */
++ int dh_readers;
++ int dh_writers;
++ int dh_pid; /* holder of the lock */
++ wait_queue_head_t dh_wait;
++};
++
++int __init dynlock_cache_init(void)
++{
++ int rc = 0;
++
++ printk(KERN_INFO "init dynlocks cache\n");
++ dynlock_cachep = kmem_cache_create("dynlock_cache",
++ sizeof(struct dynlock_handle),
++ 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL);
++ if (dynlock_cachep == NULL) {
++ printk(KERN_ERR "Not able to create dynlock cache");
++ rc = -ENOMEM;
++ }
++ return rc;
++}
++
++void __exit dynlock_cache_exit(void)
++{
++ printk(KERN_INFO "exit dynlocks cache\n");
++ kmem_cache_destroy(dynlock_cachep);
++}
++
++/*
++ * dynlock_init
++ *
++ * initialize lockspace
++ *
++ */
++void dynlock_init(struct dynlock *dl)
++{
++ spin_lock_init(&dl->dl_list_lock);
++ INIT_LIST_HEAD(&dl->dl_list);
++ dl->dl_magic = DYNLOCK_LIST_MAGIC;
++}
++EXPORT_SYMBOL(dynlock_init);
++
++/*
++ * dynlock_lock
++ *
++ * acquires lock (exclusive or shared) in specified lockspace
++ * each lock in lockspace is allocated separately, so user have
++ * to specify GFP flags.
++ * routine returns pointer to lock. this pointer is intended to
++ * be passed to dynlock_unlock
++ *
++ */
++struct dynlock_handle *dynlock_lock(struct dynlock *dl, unsigned long value,
++ enum dynlock_type lt, gfp_t gfp)
++{
++ struct dynlock_handle *nhl = NULL;
++ struct dynlock_handle *hl;
++
++ BUG_ON(dl == NULL);
++ BUG_ON(dl->dl_magic != DYNLOCK_LIST_MAGIC);
++
++repeat:
++ /* find requested lock in lockspace */
++ spin_lock(&dl->dl_list_lock);
++ BUG_ON(dl->dl_list.next == NULL);
++ BUG_ON(dl->dl_list.prev == NULL);
++ list_for_each_entry(hl, &dl->dl_list, dh_list) {
++ BUG_ON(hl->dh_list.next == NULL);
++ BUG_ON(hl->dh_list.prev == NULL);
++ BUG_ON(hl->dh_magic != DYNLOCK_HANDLE_MAGIC);
++ if (hl->dh_value == value) {
++ /* lock is found */
++ if (nhl) {
++ /* someone else just allocated
++ * lock we didn't find and just created
++ * so, we drop our lock
++ */
++ kmem_cache_free(dynlock_cachep, nhl);
++ nhl = NULL;
++ }
++ hl->dh_refcount++;
++ goto found;
++ }
++ }
++ /* lock not found */
++ if (nhl) {
++ /* we already have allocated lock. use it */
++ hl = nhl;
++ nhl = NULL;
++ list_add(&hl->dh_list, &dl->dl_list);
++ goto found;
++ }
++ spin_unlock(&dl->dl_list_lock);
++
++ /* lock not found and we haven't allocated lock yet. allocate it */
++ nhl = kmem_cache_alloc(dynlock_cachep, gfp);
++ if (nhl == NULL)
++ return NULL;
++ nhl->dh_refcount = 1;
++ nhl->dh_value = value;
++ nhl->dh_readers = 0;
++ nhl->dh_writers = 0;
++ nhl->dh_magic = DYNLOCK_HANDLE_MAGIC;
++ init_waitqueue_head(&nhl->dh_wait);
++
++ /* while lock is being allocated, someone else may allocate it
++ * and put onto to list. check this situation
++ */
++ goto repeat;
++
++found:
++ if (lt == DLT_WRITE) {
++ /* exclusive lock: user don't want to share lock at all
++ * NOTE: one process may take the same lock several times
++ * this functionaly is useful for rename operations */
++ while ((hl->dh_writers && hl->dh_pid != current->pid) ||
++ hl->dh_readers) {
++ spin_unlock(&dl->dl_list_lock);
++ wait_event(hl->dh_wait,
++ hl->dh_writers == 0 && hl->dh_readers == 0);
++ spin_lock(&dl->dl_list_lock);
++ }
++ hl->dh_writers++;
++ } else {
++ /* shared lock: user do not want to share lock with writer */
++ while (hl->dh_writers) {
++ spin_unlock(&dl->dl_list_lock);
++ wait_event(hl->dh_wait, hl->dh_writers == 0);
++ spin_lock(&dl->dl_list_lock);
++ }
++ hl->dh_readers++;
++ }
++ hl->dh_pid = current->pid;
++ spin_unlock(&dl->dl_list_lock);
++
++ return hl;
++}
++EXPORT_SYMBOL(dynlock_lock);
++
++
++/*
++ * dynlock_unlock
++ *
++ * user have to specify lockspace (dl) and pointer to lock structure
++ * returned by dynlock_lock()
++ *
++ */
++void dynlock_unlock(struct dynlock *dl, struct dynlock_handle *hl)
++{
++ int wakeup = 0;
++
++ BUG_ON(dl == NULL);
++ BUG_ON(hl == NULL);
++ BUG_ON(dl->dl_magic != DYNLOCK_LIST_MAGIC);
++
++ if (hl->dh_magic != DYNLOCK_HANDLE_MAGIC)
++ printk(KERN_EMERG "wrong lock magic: %#x\n", hl->dh_magic);
++
++ BUG_ON(hl->dh_magic != DYNLOCK_HANDLE_MAGIC);
++ BUG_ON(hl->dh_writers != 0 && current->pid != hl->dh_pid);
++
++ spin_lock(&dl->dl_list_lock);
++ if (hl->dh_writers) {
++ BUG_ON(hl->dh_readers != 0);
++ hl->dh_writers--;
++ if (hl->dh_writers == 0)
++ wakeup = 1;
++ } else if (hl->dh_readers) {
++ hl->dh_readers--;
++ if (hl->dh_readers == 0)
++ wakeup = 1;
++ } else {
++ BUG();
++ }
++ if (wakeup) {
++ hl->dh_pid = 0;
++ wake_up(&hl->dh_wait);
++ }
++ if (--(hl->dh_refcount) == 0) {
++ hl->dh_magic = DYNLOCK_HANDLE_DEAD;
++ list_del(&hl->dh_list);
++ kmem_cache_free(dynlock_cachep, hl);
++ }
++ spin_unlock(&dl->dl_list_lock);
++}
++EXPORT_SYMBOL(dynlock_unlock);
++
++int dynlock_is_locked(struct dynlock *dl, unsigned long value)
++{
++ struct dynlock_handle *hl;
++ int result = 0;
++
++ /* find requested lock in lockspace */
++ spin_lock(&dl->dl_list_lock);
++ BUG_ON(dl->dl_list.next == NULL);
++ BUG_ON(dl->dl_list.prev == NULL);
++ list_for_each_entry(hl, &dl->dl_list, dh_list) {
++ BUG_ON(hl->dh_list.next == NULL);
++ BUG_ON(hl->dh_list.prev == NULL);
++ BUG_ON(hl->dh_magic != DYNLOCK_HANDLE_MAGIC);
++ if (hl->dh_value == value && hl->dh_pid == current->pid) {
++ /* lock is found */
++ result = 1;
++ break;
++ }
++ }
++ spin_unlock(&dl->dl_list_lock);
++ return result;
++}
++EXPORT_SYMBOL(dynlock_is_locked);
+diff -rupN 2.6.27.21/include/linux/dynlocks.h 2.6.27.21_1//include/linux/dynlocks.h
+--- 2.6.27.21/include/linux/dynlocks.h 1970-01-01 05:30:00.000000000 +0530
++++ 2.6.27.21_1//include/linux/dynlocks.h 2009-08-23 10:40:07.000000000 +0530
+@@ -0,0 +1,34 @@
++#ifndef _LINUX_DYNLOCKS_H
++#define _LINUX_DYNLOCKS_H
++
++#include <linux/list.h>
++#include <linux/wait.h>
++
++struct dynlock_handle;
++
++/*
++ * lock's namespace:
++ * - list of locks
++ * - lock to protect this list
++ */
++struct dynlock {
++ unsigned dl_magic;
++ struct list_head dl_list;
++ spinlock_t dl_list_lock;
++};
++
++enum dynlock_type {
++ DLT_WRITE,
++ DLT_READ
++};
++
++int dynlock_cache_init(void);
++void dynlock_cache_exit(void);
++void dynlock_init(struct dynlock *dl);
++struct dynlock_handle *dynlock_lock(struct dynlock *dl, unsigned long value,
++ enum dynlock_type lt, gfp_t gfp);
++void dynlock_unlock(struct dynlock *dl, struct dynlock_handle *lock);
++int dynlock_is_locked(struct dynlock *dl, unsigned long value);
++
++#endif
++
--- /dev/null
+diff -rupN linux-2.6.18-128.1.6_1/fs/ext4/dynlocks.c linux-2.6.18-128.1.6_2/fs/ext4/dynlocks.c
+--- linux-2.6.18-128.1.6_1/fs/ext4/dynlocks.c 1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.18-128.1.6_2/fs/ext4/dynlocks.c 2009-08-13 20:42:59.000000000 +0530
+@@ -0,0 +1,236 @@
++/*
++ * Dynamic Locks
++ *
++ * struct dynlock is lockspace
++ * one may request lock (exclusive or shared) for some value
++ * in that lockspace
++ *
++ */
++
++#include <linux/dynlocks.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/sched.h>
++
++#define DYNLOCK_HANDLE_MAGIC 0xd19a10c
++#define DYNLOCK_HANDLE_DEAD 0xd1956ee
++#define DYNLOCK_LIST_MAGIC 0x11ee91e6
++
++static kmem_cache_t * dynlock_cachep = NULL;
++
++struct dynlock_handle {
++ unsigned dh_magic;
++ struct list_head dh_list;
++ unsigned long dh_value; /* lock value */
++ int dh_refcount; /* number of users */
++ int dh_readers;
++ int dh_writers;
++ int dh_pid; /* holder of the lock */
++ wait_queue_head_t dh_wait;
++};
++
++int __init dynlock_cache_init(void)
++{
++ int rc = 0;
++
++ printk(KERN_INFO "init dynlocks cache\n");
++ dynlock_cachep = kmem_cache_create("dynlock_cache",
++ sizeof(struct dynlock_handle),
++ 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL, NULL);
++ if (dynlock_cachep == NULL) {
++ printk(KERN_ERR "Not able to create dynlock cache");
++ rc = -ENOMEM;
++ }
++ return rc;
++}
++
++void __exit dynlock_cache_exit(void)
++{
++ printk(KERN_INFO "exit dynlocks cache\n");
++ kmem_cache_destroy(dynlock_cachep);
++}
++
++/*
++ * dynlock_init
++ *
++ * initialize lockspace
++ *
++ */
++void dynlock_init(struct dynlock *dl)
++{
++ spin_lock_init(&dl->dl_list_lock);
++ INIT_LIST_HEAD(&dl->dl_list);
++ dl->dl_magic = DYNLOCK_LIST_MAGIC;
++}
++EXPORT_SYMBOL(dynlock_init);
++
++/*
++ * dynlock_lock
++ *
++ * acquires lock (exclusive or shared) in specified lockspace
++ * each lock in lockspace is allocated separately, so user have
++ * to specify GFP flags.
++ * routine returns pointer to lock. this pointer is intended to
++ * be passed to dynlock_unlock
++ *
++ */
++struct dynlock_handle *dynlock_lock(struct dynlock *dl, unsigned long value,
++ enum dynlock_type lt, gfp_t gfp)
++{
++ struct dynlock_handle *nhl = NULL;
++ struct dynlock_handle *hl;
++
++ BUG_ON(dl == NULL);
++ BUG_ON(dl->dl_magic != DYNLOCK_LIST_MAGIC);
++
++repeat:
++ /* find requested lock in lockspace */
++ spin_lock(&dl->dl_list_lock);
++ BUG_ON(dl->dl_list.next == NULL);
++ BUG_ON(dl->dl_list.prev == NULL);
++ list_for_each_entry(hl, &dl->dl_list, dh_list) {
++ BUG_ON(hl->dh_list.next == NULL);
++ BUG_ON(hl->dh_list.prev == NULL);
++ BUG_ON(hl->dh_magic != DYNLOCK_HANDLE_MAGIC);
++ if (hl->dh_value == value) {
++ /* lock is found */
++ if (nhl) {
++ /* someone else just allocated
++ * lock we didn't find and just created
++ * so, we drop our lock
++ */
++ kmem_cache_free(dynlock_cachep, nhl);
++ nhl = NULL;
++ }
++ hl->dh_refcount++;
++ goto found;
++ }
++ }
++ /* lock not found */
++ if (nhl) {
++ /* we already have allocated lock. use it */
++ hl = nhl;
++ nhl = NULL;
++ list_add(&hl->dh_list, &dl->dl_list);
++ goto found;
++ }
++ spin_unlock(&dl->dl_list_lock);
++
++ /* lock not found and we haven't allocated lock yet. allocate it */
++ nhl = kmem_cache_alloc(dynlock_cachep, gfp);
++ if (nhl == NULL)
++ return NULL;
++ nhl->dh_refcount = 1;
++ nhl->dh_value = value;
++ nhl->dh_readers = 0;
++ nhl->dh_writers = 0;
++ nhl->dh_magic = DYNLOCK_HANDLE_MAGIC;
++ init_waitqueue_head(&nhl->dh_wait);
++
++ /* while lock is being allocated, someone else may allocate it
++ * and put onto to list. check this situation
++ */
++ goto repeat;
++
++found:
++ if (lt == DLT_WRITE) {
++ /* exclusive lock: user don't want to share lock at all
++ * NOTE: one process may take the same lock several times
++ * this functionaly is useful for rename operations */
++ while ((hl->dh_writers && hl->dh_pid != current->pid) ||
++ hl->dh_readers) {
++ spin_unlock(&dl->dl_list_lock);
++ wait_event(hl->dh_wait,
++ hl->dh_writers == 0 && hl->dh_readers == 0);
++ spin_lock(&dl->dl_list_lock);
++ }
++ hl->dh_writers++;
++ } else {
++ /* shared lock: user do not want to share lock with writer */
++ while (hl->dh_writers) {
++ spin_unlock(&dl->dl_list_lock);
++ wait_event(hl->dh_wait, hl->dh_writers == 0);
++ spin_lock(&dl->dl_list_lock);
++ }
++ hl->dh_readers++;
++ }
++ hl->dh_pid = current->pid;
++ spin_unlock(&dl->dl_list_lock);
++
++ return hl;
++}
++EXPORT_SYMBOL(dynlock_lock);
++
++
++/*
++ * dynlock_unlock
++ *
++ * user have to specify lockspace (dl) and pointer to lock structure
++ * returned by dynlock_lock()
++ *
++ */
++void dynlock_unlock(struct dynlock *dl, struct dynlock_handle *hl)
++{
++ int wakeup = 0;
++
++ BUG_ON(dl == NULL);
++ BUG_ON(hl == NULL);
++ BUG_ON(dl->dl_magic != DYNLOCK_LIST_MAGIC);
++
++ if (hl->dh_magic != DYNLOCK_HANDLE_MAGIC)
++ printk(KERN_EMERG "wrong lock magic: %#x\n", hl->dh_magic);
++
++ BUG_ON(hl->dh_magic != DYNLOCK_HANDLE_MAGIC);
++ BUG_ON(hl->dh_writers != 0 && current->pid != hl->dh_pid);
++
++ spin_lock(&dl->dl_list_lock);
++ if (hl->dh_writers) {
++ BUG_ON(hl->dh_readers != 0);
++ hl->dh_writers--;
++ if (hl->dh_writers == 0)
++ wakeup = 1;
++ } else if (hl->dh_readers) {
++ hl->dh_readers--;
++ if (hl->dh_readers == 0)
++ wakeup = 1;
++ } else {
++ BUG();
++ }
++ if (wakeup) {
++ hl->dh_pid = 0;
++ wake_up(&hl->dh_wait);
++ }
++ if (--(hl->dh_refcount) == 0) {
++ hl->dh_magic = DYNLOCK_HANDLE_DEAD;
++ list_del(&hl->dh_list);
++ kmem_cache_free(dynlock_cachep, hl);
++ }
++ spin_unlock(&dl->dl_list_lock);
++}
++EXPORT_SYMBOL(dynlock_unlock);
++
++int dynlock_is_locked(struct dynlock *dl, unsigned long value)
++{
++ struct dynlock_handle *hl;
++ int result = 0;
++
++ /* find requested lock in lockspace */
++ spin_lock(&dl->dl_list_lock);
++ BUG_ON(dl->dl_list.next == NULL);
++ BUG_ON(dl->dl_list.prev == NULL);
++ list_for_each_entry(hl, &dl->dl_list, dh_list) {
++ BUG_ON(hl->dh_list.next == NULL);
++ BUG_ON(hl->dh_list.prev == NULL);
++ BUG_ON(hl->dh_magic != DYNLOCK_HANDLE_MAGIC);
++ if (hl->dh_value == value && hl->dh_pid == current->pid) {
++ /* lock is found */
++ result = 1;
++ break;
++ }
++ }
++ spin_unlock(&dl->dl_list_lock);
++ return result;
++}
++EXPORT_SYMBOL(dynlock_is_locked);
+diff -rupN linux-2.6.18-128.1.6_1/include/linux/dynlocks.h linux-2.6.18-128.1.6_2/include/linux/dynlocks.h
+--- linux-2.6.18-128.1.6_1/include/linux/dynlocks.h 1970-01-01 05:30:00.000000000 +0530
++++ linux-2.6.18-128.1.6_2/include/linux/dynlocks.h 2009-08-13 20:43:18.000000000 +0530
+@@ -0,0 +1,34 @@
++#ifndef _LINUX_DYNLOCKS_H
++#define _LINUX_DYNLOCKS_H
++
++#include <linux/list.h>
++#include <linux/wait.h>
++
++struct dynlock_handle;
++
++/*
++ * lock's namespace:
++ * - list of locks
++ * - lock to protect this list
++ */
++struct dynlock {
++ unsigned dl_magic;
++ struct list_head dl_list;
++ spinlock_t dl_list_lock;
++};
++
++enum dynlock_type {
++ DLT_WRITE,
++ DLT_READ
++};
++
++int dynlock_cache_init(void);
++void dynlock_cache_exit(void);
++void dynlock_init(struct dynlock *dl);
++struct dynlock_handle *dynlock_lock(struct dynlock *dl, unsigned long value,
++ enum dynlock_type lt, gfp_t gfp);
++void dynlock_unlock(struct dynlock *dl, struct dynlock_handle *lock);
++int dynlock_is_locked(struct dynlock *dl, unsigned long value);
++
++#endif
++
--- /dev/null
+Index: linux-stage/fs/ext4/namei.c
+===================================================================
+--- linux-stage.orig/fs/ext4/namei.c 2009-08-10 22:44:33.000000000 +0800
++++ linux-stage/fs/ext4/namei.c 2009-08-10 22:48:22.000000000 +0800
+@@ -1493,6 +1493,72 @@
+ return add_dirent_to_buf(handle, dentry, inode, de, bh);
+ }
+
++/* update ".." for hash-indexed directory, split the item "." if necessary */
++static int ext4_update_dotdot(handle_t *handle, struct dentry *dentry,
++ struct inode *inode)
++{
++ struct inode * dir = dentry->d_parent->d_inode;
++ struct buffer_head * dir_block;
++ struct ext4_dir_entry_2 * de;
++ int len, journal = 0, err = 0;
++
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ if (IS_DIRSYNC(dir))
++ handle->h_sync = 1;
++
++ dir_block = ext4_bread(handle, dir, 0, 0, &err);
++ if (!dir_block)
++ goto out;
++
++ de = (struct ext4_dir_entry_2 *)dir_block->b_data;
++ /* the first item must be "." */
++ assert(de->name_len == 1 && de->name[0] == '.');
++ len = le16_to_cpu(de->rec_len);
++ assert(len >= EXT4_DIR_REC_LEN(1));
++ if (len > EXT4_DIR_REC_LEN(1)) {
++ BUFFER_TRACE(dir_block, "get_write_access");
++ err = ext4_journal_get_write_access(handle, dir_block);
++ if (err)
++ goto out_journal;
++
++ journal = 1;
++ de->rec_len = cpu_to_le16(EXT4_DIR_REC_LEN(1));
++ }
++
++ len -= EXT4_DIR_REC_LEN(1);
++ assert(len == 0 || len >= EXT4_DIR_REC_LEN(2));
++ de = (struct ext4_dir_entry_2 *)
++ ((char *) de + le16_to_cpu(de->rec_len));
++ if (!journal) {
++ BUFFER_TRACE(dir_block, "get_write_access");
++ err = ext4_journal_get_write_access(handle, dir_block);
++ if (err)
++ goto out_journal;
++ }
++
++ de->inode = cpu_to_le32(inode->i_ino);
++ if (len > 0)
++ de->rec_len = cpu_to_le16(len);
++ else
++ assert(le16_to_cpu(de->rec_len) >= EXT4_DIR_REC_LEN(2));
++ de->name_len = 2;
++ strcpy (de->name, "..");
++ ext4_set_de_type(dir->i_sb, de, S_IFDIR);
++
++out_journal:
++ if (journal) {
++ BUFFER_TRACE(dir_block, "call ext4_journal_dirty_metadata");
++ err = ext4_journal_dirty_metadata(handle, dir_block);
++ ext4_mark_inode_dirty(handle, dir);
++ }
++ brelse (dir_block);
++
++out:
++ return err;
++}
++
+ /*
+ * ext4_add_entry()
+ *
+@@ -1521,6 +1587,9 @@
+ if (!dentry->d_name.len)
+ return -EINVAL;
+ if (is_dx(dir)) {
++ if (dentry->d_name.len == 2 &&
++ memcmp(dentry->d_name.name, "..", 2) == 0)
++ return ext4_update_dotdot(handle, dentry, inode);
+ retval = ext4_dx_add_entry(handle, dentry, inode);
+ if (!retval || (retval != ERR_BAD_DX_DIR))
+ return retval;
--- /dev/null
+diff -rupN 2.6.27.21_2/fs/ext4/ext4.h 2.6.27.21_3/fs/ext4/ext4.h
+--- 2.6.27.21_2/fs/ext4/ext4.h 2009-07-17 12:19:59.000000000 +0530
++++ 2.6.27.21_3/fs/ext4/ext4.h 2009-07-17 12:38:59.000000000 +0530
+@@ -1181,6 +1181,9 @@ extern int ext4_orphan_add(handle_t *, s
+ extern int ext4_orphan_del(handle_t *, struct inode *);
+ extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
+ __u32 start_minor_hash, __u32 *next_hash);
++extern struct buffer_head *ext4_append(handle_t *handle,
++ struct inode *inode,
++ ext4_lblk_t *block, int *err);
+
+ /* resize.c */
+ extern int ext4_group_add(struct super_block *sb,
+diff -rupN 2.6.27.21_2/fs/ext4/hash.c 2.6.27.21_3/fs/ext4/hash.c
+--- 2.6.27.21_2/fs/ext4/hash.c 2009-07-17 12:12:56.000000000 +0530
++++ 2.6.27.21_3/fs/ext4/hash.c 2009-07-17 12:40:22.000000000 +0530
+@@ -9,6 +9,7 @@
+ * License.
+ */
+
++#include <linux/module.h>
+ #include <linux/fs.h>
+ #include <linux/jbd2.h>
+ #include <linux/cryptohash.h>
+@@ -206,3 +207,4 @@ int ext4fs_dirhash(const char *name, int
+ hinfo->minor_hash = minor_hash;
+ return 0;
+ }
++EXPORT_SYMBOL(ext4fs_dirhash);
+diff -rupN 2.6.27.21_2/fs/ext4/namei.c 2.6.27.21_3/fs/ext4/namei.c
+--- 2.6.27.21_2/fs/ext4/namei.c 2009-07-17 12:23:51.000000000 +0530
++++ 2.6.27.21_3/fs/ext4/namei.c 2009-07-17 12:37:59.000000000 +0530
+@@ -51,9 +51,9 @@
+ #define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
+ #define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b))
+
+-static struct buffer_head *ext4_append(handle_t *handle,
+- struct inode *inode,
+- ext4_lblk_t *block, int *err)
++struct buffer_head *ext4_append(handle_t *handle,
++ struct inode *inode,
++ ext4_lblk_t *block, int *err)
+ {
+ struct buffer_head *bh;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+@@ -72,6 +72,7 @@ static struct buffer_head *ext4_append(h
+ up(&ei->i_append_sem);
+ return bh;
+ }
++EXPORT_SYMBOL(ext4_append);
+
+ #ifndef assert
+ #define assert(test) J_ASSERT(test)
+diff -rupN 2.6.27.21_2/fs/ext4/super.c 2.6.27.21_3/fs/ext4/super.c
+--- 2.6.27.21_2/fs/ext4/super.c 2009-07-17 12:12:57.000000000 +0530
++++ 2.6.27.21_3/fs/ext4/super.c 2009-07-17 12:40:52.000000000 +0530
+@@ -377,6 +377,7 @@ void __ext4_std_error(struct super_block
+
+ ext4_handle_error(sb);
+ }
++EXPORT_SYMBOL(__ext4_std_error);
+
+ /*
+ * ext4_abort is a much stronger failure handler than ext4_error. The
--- /dev/null
+diff -rupN linux-2.6.27.21-0.1_1//fs/ext4/ext4.h linux-2.6.27.21-0.1_2//fs/ext4/ext4.h
+--- linux-2.6.27.21-0.1_1//fs/ext4/ext4.h 2009-08-24 15:32:00.000000000 +0530
++++ linux-2.6.27.21-0.1_2//fs/ext4/ext4.h 2009-08-24 15:32:55.000000000 +0530
+@@ -1171,6 +1171,18 @@ extern int ext4_fiemap(struct inode *, s
+ /* migrate.c */
+ extern int ext4_ext_migrate(struct inode *);
+ /* namei.c */
++extern struct inode *ext4_create_inode(handle_t *handle,
++ struct inode * dir, int mode);
++extern int ext4_add_entry(handle_t *handle, struct dentry *dentry,
++ struct inode *inode);
++extern int ext4_delete_entry(handle_t *handle, struct inode * dir,
++ struct ext4_dir_entry_2 * de_del,
++ struct buffer_head * bh);
++extern struct buffer_head * ext4_find_entry (struct inode *dir,
++ const struct qstr *d_name,
++ struct ext4_dir_entry_2 ** res_dir);
++extern int ext4_add_dot_dotdot(handle_t *handle, struct inode *dir,
++ struct inode *inode);
+ extern int ext4_orphan_add(handle_t *, struct inode *);
+ extern int ext4_orphan_del(handle_t *, struct inode *);
+ extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
+diff -rupN linux-2.6.27.21-0.1_1//fs/ext4/namei.c linux-2.6.27.21-0.1_2//fs/ext4/namei.c
+--- linux-2.6.27.21-0.1_1//fs/ext4/namei.c 2009-08-24 15:32:00.000000000 +0530
++++ linux-2.6.27.21-0.1_2//fs/ext4/namei.c 2009-08-24 15:43:56.000000000 +0530
+@@ -24,6 +24,7 @@
+ * Theodore Ts'o, 2002
+ */
+
++#include <linux/module.h>
+ #include <linux/fs.h>
+ #include <linux/pagemap.h>
+ #include <linux/jbd2.h>
+@@ -882,9 +883,9 @@ static inline int search_dirblock(struct
+ * The returned buffer_head has ->b_count elevated. The caller is expected
+ * to brelse() it when appropriate.
+ */
+-static struct buffer_head * ext4_find_entry (struct inode *dir,
+- const struct qstr *d_name,
+- struct ext4_dir_entry_2 ** res_dir)
++struct buffer_head * ext4_find_entry (struct inode *dir,
++ const struct qstr *d_name,
++ struct ext4_dir_entry_2 ** res_dir)
+ {
+ struct super_block *sb;
+ struct buffer_head *bh_use[NAMEI_RA_SIZE];
+@@ -991,6 +992,7 @@ cleanup_and_exit:
+ brelse(bh_use[ra_ptr]);
+ return ret;
+ }
++EXPORT_SYMBOL(ext4_find_entry);
+
+ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, const struct qstr *d_name,
+ struct ext4_dir_entry_2 **res_dir, int *err)
+@@ -1511,8 +1513,8 @@ static int make_indexed_dir(handle_t *ha
+ * may not sleep between calling this and putting something into
+ * the entry, as someone else might have used it while you slept.
+ */
+-static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
+- struct inode *inode)
++int ext4_add_entry(handle_t *handle, struct dentry *dentry,
++ struct inode *inode)
+ {
+ struct inode *dir = dentry->d_parent->d_inode;
+ struct buffer_head *bh;
+@@ -1557,6 +1559,7 @@ static int ext4_add_entry(handle_t *hand
+ de->rec_len = ext4_rec_len_to_disk(blocksize);
+ return add_dirent_to_buf(handle, dentry, inode, de, bh);
+ }
++EXPORT_SYMBOL(ext4_add_entry);
+
+ /*
+ * Returns 0 for success, or a negative error value
+@@ -1699,10 +1702,10 @@ cleanup:
+ * ext4_delete_entry deletes a directory entry by merging it with the
+ * previous entry
+ */
+-static int ext4_delete_entry(handle_t *handle,
+- struct inode *dir,
+- struct ext4_dir_entry_2 *de_del,
+- struct buffer_head *bh)
++int ext4_delete_entry(handle_t *handle,
++ struct inode *dir,
++ struct ext4_dir_entry_2 *de_del,
++ struct buffer_head *bh)
+ {
+ struct ext4_dir_entry_2 *de, *pde;
+ int i;
+@@ -1733,7 +1736,7 @@ static int ext4_delete_entry(handle_t *h
+ }
+ return -ENOENT;
+ }
+-
++EXPORT_SYMBOL(ext4_delete_entry);
+ /*
+ * DIR_NLINK feature is set if 1) nlinks > EXT4_LINK_MAX or 2) nlinks == 2,
+ * since this indicates that nlinks count was previously 1.
+@@ -1796,6 +1799,26 @@ static unsigned ext4_dentry_goal(struct
+ return inum;
+ }
+
++struct inode * ext4_create_inode(handle_t *handle, struct inode * dir, int mode)
++{
++ struct inode *inode;
++
++ inode = ext4_new_inode(handle, dir, mode);
++ if (!IS_ERR(inode)) {
++ if (S_ISCHR(mode) || S_ISBLK(mode) || S_ISFIFO(mode)) {
++#ifdef CONFIG_LDISKFS_FS_XATTR
++ inode->i_op = &ext4_special_inode_operations;
++#endif
++ } else {
++ inode->i_op = &ext4_file_inode_operations;
++ inode->i_fop = &ext4_file_operations;
++ ext4_set_aops(inode);
++ }
++ }
++ return inode;
++}
++EXPORT_SYMBOL(ext4_create_inode);
++
+ /*
+ * By the time this is called, we already have created
+ * the directory cache entry for the new file, but it
+@@ -1872,51 +1895,43 @@ retry:
+ return err;
+ }
+
+-static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++/* Initialize @inode as a subdirectory of @dir, and add the
++ * "." and ".." entries into the first directory block. */
++int ext4_add_dot_dotdot(handle_t *handle, struct inode * dir,
++ struct inode *inode)
+ {
+- handle_t *handle;
+- struct inode *inode;
+- struct buffer_head *dir_block;
+- struct ext4_dir_entry_2 *de;
+- int err, retries = 0;
+-
+- if (EXT4_DIR_LINK_MAX(dir))
+- return -EMLINK;
++ struct buffer_head * dir_block;
++ struct ext4_dir_entry_2 * de;
++ int err = 0;
+
+-retry:
+- handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
+- EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
+- 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ if (IS_DIRSYNC(dir))
+ handle->h_sync = 1;
+
+- inode = ext4_new_inode_goal(handle, dir, S_IFDIR | mode,
+- ext4_dentry_goal(dir->i_sb, dentry));
+- err = PTR_ERR(inode);
+- if (IS_ERR(inode))
+- goto out_stop;
+-
+ inode->i_op = &ext4_dir_inode_operations;
+ inode->i_fop = &ext4_dir_operations;
+ inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
+- dir_block = ext4_bread(handle, inode, 0, 1, &err);
+- if (!dir_block)
+- goto out_clear_inode;
++ dir_block = ext4_bread (handle, inode, 0, 1, &err);
++ if (!dir_block) {
++ clear_nlink(inode);
++ ext4_mark_inode_dirty(handle, inode);
++ iput (inode);
++ goto get_out;
++ }
+ BUFFER_TRACE(dir_block, "get_write_access");
+ ext4_journal_get_write_access(handle, dir_block);
+ de = (struct ext4_dir_entry_2 *) dir_block->b_data;
+ de->inode = cpu_to_le32(inode->i_ino);
+ de->name_len = 1;
+ de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len));
+- strcpy(de->name, ".");
++ strcpy (de->name, ".");
+ ext4_set_de_type(dir->i_sb, de, S_IFDIR);
+ de = ext4_next_entry(de);
+ de->inode = cpu_to_le32(dir->i_ino);
+ de->rec_len = ext4_rec_len_to_disk(inode->i_sb->s_blocksize -
+- EXT4_DIR_REC_LEN(1));
++ EXT4_DIR_REC_LEN(1));
+ de->name_len = 2;
+ strcpy(de->name, "..");
+ ext4_set_de_type(dir->i_sb, de, S_IFDIR);
+@@ -1925,9 +1940,43 @@ retry:
+ ext4_journal_dirty_metadata(handle, dir_block);
+ brelse(dir_block);
+ ext4_mark_inode_dirty(handle, inode);
++get_out:
++ return err;
++}
++EXPORT_SYMBOL(ext4_add_dot_dotdot);
++
++
++static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode)
++{
++ handle_t *handle;
++ struct inode *inode;
++ int err, retries = 0;
++
++ if (EXT4_DIR_LINK_MAX(dir))
++ return -EMLINK;
++
++retry:
++ handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
++ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
++ 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ if (IS_DIRSYNC(dir))
++ handle->h_sync = 1;
++
++ inode = ext4_new_inode_goal(handle, dir, S_IFDIR | mode,
++ ext4_dentry_goal(dir->i_sb, dentry));
++ err = PTR_ERR(inode);
++ if (IS_ERR(inode))
++ goto out_stop;
++
++ err = ext4_add_dot_dotdot(handle, dir, inode);
++ if (err)
++ goto out_stop;
++
+ err = ext4_add_entry(handle, dentry, inode);
+ if (err) {
+-out_clear_inode:
+ clear_nlink(inode);
+ ext4_mark_inode_dirty(handle, inode);
+ iput(inode);
--- /dev/null
+diff -rupN linux-2.6.18-128.1.6_1//fs/ext4/ext4.h linux-2.6.18-128.1.6_2//fs/ext4/ext4.h
+--- linux-2.6.18-128.1.6_1//fs/ext4/ext4.h 2009-08-24 15:54:11.000000000 +0530
++++ linux-2.6.18-128.1.6_2//fs/ext4/ext4.h 2009-08-24 15:54:52.000000000 +0530
+@@ -1144,6 +1144,18 @@ extern int ext4_fiemap(struct inode *, s
+ extern int ext4_ext_migrate(struct inode *, struct file *, unsigned int,
+ unsigned long);
+ /* namei.c */
++extern struct inode *ext4_create_inode(handle_t *handle,
++ struct inode * dir, int mode);
++extern int ext4_add_entry(handle_t *handle, struct dentry *dentry,
++ struct inode *inode);
++extern int ext4_delete_entry(handle_t *handle, struct inode * dir,
++ struct ext4_dir_entry_2 * de_del,
++ struct buffer_head * bh);
++extern struct buffer_head * ext4_find_entry(struct dentry *dentry,
++ struct ext4_dir_entry_2
++ ** res_dir);
++extern int ext4_add_dot_dotdot(handle_t *handle, struct inode *dir,
++ struct inode *inode);
+ extern int ext4_orphan_add(handle_t *, struct inode *);
+ extern int ext4_orphan_del(handle_t *, struct inode *);
+ extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
+diff -rupN linux-2.6.18-128.1.6_1//fs/ext4/inode.c linux-2.6.18-128.1.6_2//fs/ext4/inode.c
+--- linux-2.6.18-128.1.6_1//fs/ext4/inode.c 2009-08-24 15:54:11.000000000 +0530
++++ linux-2.6.18-128.1.6_2//fs/ext4/inode.c 2009-08-24 15:54:52.000000000 +0530
+@@ -2891,6 +2891,7 @@ bad_inode:
+ iput(inode);
+ return ERR_PTR(ret);
+ }
++EXPORT_SYMBOL(ext4_iget);
+
+ static int ext4_inode_blocks_set(handle_t *handle,
+ struct ext4_inode *raw_inode,
+diff -rupN linux-2.6.18-128.1.6_1//fs/ext4/namei.c linux-2.6.18-128.1.6_2//fs/ext4/namei.c
+--- linux-2.6.18-128.1.6_1//fs/ext4/namei.c 2009-08-24 15:54:11.000000000 +0530
++++ linux-2.6.18-128.1.6_2//fs/ext4/namei.c 2009-08-24 15:55:18.000000000 +0530
+@@ -24,6 +24,7 @@
+ * Theodore Ts'o, 2002
+ */
+
++#include <linux/module.h>
+ #include <linux/fs.h>
+ #include <linux/pagemap.h>
+ #include <linux/jbd2.h>
+@@ -878,8 +879,8 @@ static inline int search_dirblock(struct
+ * The returned buffer_head has ->b_count elevated. The caller is expected
+ * to brelse() it when appropriate.
+ */
+-static struct buffer_head * ext4_find_entry (struct dentry *dentry,
+- struct ext4_dir_entry_2 ** res_dir)
++struct buffer_head * ext4_find_entry (struct dentry *dentry,
++ struct ext4_dir_entry_2 ** res_dir)
+ {
+ struct super_block * sb;
+ struct buffer_head * bh_use[NAMEI_RA_SIZE];
+@@ -986,6 +987,7 @@ cleanup_and_exit:
+ brelse (bh_use[ra_ptr]);
+ return ret;
+ }
++EXPORT_SYMBOL(ext4_find_entry);
+
+ static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,
+ struct ext4_dir_entry_2 **res_dir, int *err)
+@@ -1506,8 +1508,8 @@ static int make_indexed_dir(handle_t *ha
+ * may not sleep between calling this and putting something into
+ * the entry, as someone else might have used it while you slept.
+ */
+-static int ext4_add_entry (handle_t *handle, struct dentry *dentry,
+- struct inode *inode)
++int ext4_add_entry (handle_t *handle, struct dentry *dentry,
++ struct inode *inode)
+ {
+ struct inode *dir = dentry->d_parent->d_inode;
+ unsigned long offset;
+@@ -1553,6 +1555,7 @@ static int ext4_add_entry (handle_t *han
+ de->rec_len = ext4_rec_len_to_disk(blocksize);
+ return add_dirent_to_buf(handle, dentry, inode, de, bh);
+ }
++EXPORT_SYMBOL(ext4_add_entry);
+
+ /*
+ * Returns 0 for success, or a negative error value
+@@ -1693,10 +1696,10 @@ cleanup:
+ * ext4_delete_entry deletes a directory entry by merging it with the
+ * previous entry
+ */
+-static int ext4_delete_entry (handle_t *handle,
+- struct inode * dir,
+- struct ext4_dir_entry_2 * de_del,
+- struct buffer_head * bh)
++int ext4_delete_entry (handle_t *handle,
++ struct inode * dir,
++ struct ext4_dir_entry_2 * de_del,
++ struct buffer_head * bh)
+ {
+ struct ext4_dir_entry_2 * de, * pde;
+ int i;
+@@ -1727,7 +1730,7 @@ static int ext4_delete_entry (handle_t *
+ }
+ return -ENOENT;
+ }
+-
++EXPORT_SYMBOL(ext4_delete_entry);
+ /*
+ * DIR_NLINK feature is set if 1) nlinks > EXT4_LINK_MAX or 2) nlinks == 2,
+ * since this indicates that nlinks count was previously 1.
+@@ -1790,6 +1793,26 @@ static struct inode * ext4_new_inode_wan
+ return ext4_new_inode(handle, dir, mode, inum);
+ }
+
++struct inode * ext4_create_inode(handle_t *handle, struct inode * dir, int mode)
++{
++ struct inode *inode;
++
++ inode = ext4_new_inode(handle, dir, mode, 0);
++ if (!IS_ERR(inode)) {
++ if (S_ISCHR(mode) || S_ISBLK(mode) || S_ISFIFO(mode)) {
++#ifdef CONFIG_LDISKFS_FS_XATTR
++ inode->i_op = &ext4_special_inode_operations;
++#endif
++ } else {
++ inode->i_op = &ext4_file_inode_operations;
++ inode->i_fop = &ext4_file_operations;
++ ext4_set_aops(inode);
++ }
++ }
++ return inode;
++}
++EXPORT_SYMBOL(ext4_create_inode);
++
+ /*
+ * By the time this is called, we already have created
+ * the directory cache entry for the new file, but it
+@@ -1864,38 +1887,25 @@ retry:
+ return err;
+ }
+
+-static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+-{
+- handle_t *handle;
+- struct inode * inode;
++/* Initialize @inode as a subdirectory of @dir, and add the
++ * "." and ".." entries into the first directory block. */
++int ext4_add_dot_dotdot(handle_t *handle, struct inode * dir,
++ struct inode *inode)
++ {
+ struct buffer_head * dir_block;
+ struct ext4_dir_entry_2 * de;
+- int err, retries = 0;
+-
+- if (EXT4_DIR_LINK_MAX(dir))
+- return -EMLINK;
+-
+-retry:
+- handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
+- EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
+- 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));
+- if (IS_ERR(handle))
+- return PTR_ERR(handle);
+-
+- if (IS_DIRSYNC(dir))
+- handle->h_sync = 1;
+-
+- inode = ext4_new_inode_wantedi (handle, dir, S_IFDIR | mode, dentry);
+- err = PTR_ERR(inode);
+- if (IS_ERR(inode))
+- goto out_stop;
++ int err = 0;
+
+ inode->i_op = &ext4_dir_inode_operations;
+ inode->i_fop = &ext4_dir_operations;
+ inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
+ dir_block = ext4_bread (handle, inode, 0, 1, &err);
+- if (!dir_block)
+- goto out_clear_inode;
++ if (!dir_block) {
++ clear_nlink(inode);
++ ext4_mark_inode_dirty(handle, inode);
++ iput (inode);
++ goto get_out;
++ }
+ BUFFER_TRACE(dir_block, "get_write_access");
+ ext4_journal_get_write_access(handle, dir_block);
+ de = (struct ext4_dir_entry_2 *) dir_block->b_data;
+@@ -1907,7 +1917,7 @@ retry:
+ de = ext4_next_entry(de);
+ de->inode = cpu_to_le32(dir->i_ino);
+ de->rec_len = ext4_rec_len_to_disk(inode->i_sb->s_blocksize -
+- EXT4_DIR_REC_LEN(1));
++ EXT4_DIR_REC_LEN(1));
+ de->name_len = 2;
+ strcpy (de->name, "..");
+ ext4_set_de_type(dir->i_sb, de, S_IFDIR);
+@@ -1916,9 +1926,41 @@ retry:
+ ext4_journal_dirty_metadata(handle, dir_block);
+ brelse (dir_block);
+ ext4_mark_inode_dirty(handle, inode);
++get_out:
++ return err;
++}
++EXPORT_SYMBOL(ext4_add_dot_dotdot);
++
++static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
++{
++ handle_t *handle;
++ struct inode * inode;
++ int err, retries = 0;
++
++ if (EXT4_DIR_LINK_MAX(dir))
++ return -EMLINK;
++
++retry:
++ handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
++ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
++ 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));
++ if (IS_ERR(handle))
++ return PTR_ERR(handle);
++
++ if (IS_DIRSYNC(dir))
++ handle->h_sync = 1;
++
++ inode = ext4_new_inode_wantedi (handle, dir, S_IFDIR | mode, dentry);
++ err = PTR_ERR(inode);
++ if (IS_ERR(inode))
++ goto out_stop;
++
++ err = ext4_add_dot_dotdot(handle, dir, inode);
++ if (err)
++ goto out_stop;
++
+ err = ext4_add_entry (handle, dentry, inode);
+ if (err) {
+-out_clear_inode:
+ clear_nlink(inode);
+ ext4_mark_inode_dirty(handle, inode);
+ iput (inode);
+
--- /dev/null
+diff -rupN linux-2.6.27.21-0.1_1//fs/ext4/ext4_i.h linux-2.6.27.21-0.1_2//fs/ext4/ext4_i.h
+--- linux-2.6.27.21-0.1_1//fs/ext4/ext4_i.h 2009-08-24 13:00:59.000000000 +0530
++++ linux-2.6.27.21-0.1_2//fs/ext4/ext4_i.h 2009-08-24 13:01:25.000000000 +0530
+@@ -16,6 +16,7 @@
+ #ifndef _EXT4_I
+ #define _EXT4_I
+
++#include <linux/dynlocks.h>
+ #include <linux/rwsem.h>
+ #include <linux/rbtree.h>
+ #include <linux/seqlock.h>
+@@ -56,7 +57,9 @@ struct ext4_inode_info {
+ __u32 i_flags;
+ ext4_fsblk_t i_file_acl;
+ __u32 i_dtime;
+-
++ /* following fields for parallel directory operations -bzzz */
++ struct dynlock i_htree_lock;
++ struct semaphore i_append_sem;
+ /*
+ * i_block_group is the number of the block group which contains
+ * this file's inode. Constant across the lifetime of the inode,
+diff -rupN linux-2.6.27.21-0.1_1//fs/ext4/namei.c linux-2.6.27.21-0.1_2//fs/ext4/namei.c
+--- linux-2.6.27.21-0.1_1//fs/ext4/namei.c 2009-08-24 13:00:59.000000000 +0530
++++ linux-2.6.27.21-0.1_2//fs/ext4/namei.c 2009-08-24 13:03:45.000000000 +0530
+@@ -55,6 +55,11 @@ static struct buffer_head *ext4_append(h
+ ext4_lblk_t *block, int *err)
+ {
+ struct buffer_head *bh;
++ struct ext4_inode_info *ei = EXT4_I(inode);
++
++ /* with parallel dir operations all appends
++ * have to be serialized -bzzz */
++ down(&ei->i_append_sem);
+
+ *block = inode->i_size >> inode->i_sb->s_blocksize_bits;
+
+@@ -67,7 +72,9 @@ static struct buffer_head *ext4_append(h
+ brelse(bh);
+ bh = NULL;
+ }
++ ei->i_disksize = inode->i_size;
+ }
++ up(&ei->i_append_sem);
+ return bh;
+ }
+
+diff -rupN linux-2.6.27.21-0.1_1//fs/ext4/super.c linux-2.6.27.21-0.1_2//fs/ext4/super.c
+--- linux-2.6.27.21-0.1_1//fs/ext4/super.c 2009-08-24 13:00:59.000000000 +0530
++++ linux-2.6.27.21-0.1_2//fs/ext4/super.c 2009-08-24 13:01:25.000000000 +0530
+@@ -635,6 +635,8 @@ static struct inode *ext4_alloc_inode(st
+ #endif
+ ei->vfs_inode.i_version = 1;
+ ei->vfs_inode.i_data.writeback_index = 0;
++ dynlock_init(&ei->i_htree_lock);
++ sema_init(&ei->i_append_sem, 1);
+ memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache));
+ INIT_LIST_HEAD(&ei->i_prealloc_list);
+ spin_lock_init(&ei->i_prealloc_lock);
ext4-force_over_8tb-rhel5.patch
ext4_ext_search_right-fix.patch
ext4-pa_lock-typo.patch
+ext4-pdir-fix.patch
+ext4-osd-iop-common.patch
+ext4-osd-iam-exports.patch
+ext4-dynlocks-common.patch
+ext4-dynlocks-2.6-rhel5.patch
+ext4-hash-indexed-dir-dotdot-update.patch
ext3-get-raid-stripe-from-sb.patch
ext3-big-endian-check-2.6-rhel5.patch
alloc-policy-2.6-rhlel5.diff
-ext3-force_over_8tb-rhel5.patch
+ext3-force_over_8tb-rhel5.patch
+ext3-pdir-fix.patch
+ext3-osd-iop-common.patch
+ext3-osd-iam-exports.patch
+ext3-dynlocks-common.patch
+ext3-dynlocks-2.6-rhel5.patch
+ext3-hash-indexed-dir-dotdot-update.patch
ext3-big-endian-check-2.6-sles10.patch
alloc-policy-2.6-rhlel5.diff
ext3-force_over_8tb-sles10.patch
+ext3-pdir-fix.patch
+ext3-osd-iop-common.patch
+ext3-osd-iam-exports.patch
+ext3-dynlocks-common.patch
+ext3-dynlocks-2.6-rhel5.patch
+ext3-hash-indexed-dir-dotdot-update.patch
ext4-claim_inode-free_inode-race.patch
ext4_ext_search_right-fix.patch
ext4-pa_lock-typo.patch
+ext4-pdir-fix.patch
+ext4-osd-iop-common-sles11.patch
+ext4-osd-iam-exports.patch
+ext4-dynlocks-common-sles11.patch
+ext4-dynlocks-2.6-rhel5.patch
+ext4-hash-indexed-dir-dotdot-update.patch
backfs_sources := $(filter-out %.mod.c,$(wildcard @LINUX@/fs/@BACKFS@/*.c))
-ext3_new_sources := iopen.c iopen.h extents.c mballoc.c group.h fiemap.h
-ext3_new_headers := ext3_extents.h
+ext3_new_sources := iopen.c iopen.h extents.c mballoc.c group.h dynlocks.c fiemap.h
+ext3_new_headers := ext3_extents.h
-ext4_new_sources := iopen.c iopen.h fiemap.h
+ext4_new_sources := iopen.c iopen.h dynlocks.c fiemap.h
ext4_new_headers :=
new_sources := $(@BACKFS@_new_sources)
linux-stage/include/linux/@BACKFS@$$i \
> linux/ldiskfs$$i ; \
done
+ sed $(strip $(ldiskfs_sed_flags)) \
+ linux-stage/include/linux/dynlocks.h \
+ > linux/dynlocks.h
+
+
@echo
touch sources