-Index: linux-stage/fs/ext4/dynlocks.c
-===================================================================
---- /dev/null
-+++ linux-stage/fs/ext4/dynlocks.c
-@@ -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 struct kmem_cache * 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 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);
-Index: linux-stage/include/linux/dynlocks.h
-===================================================================
---- /dev/null
-+++ linux-stage/include/linux/dynlocks.h
-@@ -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
-+
-Index: linux-stage/fs/ext4/Makefile
-===================================================================
---- linux-stage.orig/fs/ext4/Makefile
-+++ linux-stage/fs/ext4/Makefile
-@@ -7,7 +7,7 @@ obj-$(CONFIG_EXT4_FS) += ext4.o
- ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
- ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \
- ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o \
-- mmp.o
-+ mmp.o dynlocks.o
-
- ext4-$(CONFIG_EXT4_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
- ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
-Index: linux-stage/fs/ext4/super.c
-===================================================================
---- linux-stage.orig/fs/ext4/super.c
-+++ linux-stage/fs/ext4/super.c
-@@ -4620,20 +4620,23 @@ static int __init init_ext4_fs(void)
- return err;
- ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj);
- if (!ext4_kset)
-- goto out4;
-+ goto out5;
- ext4_proc_root = proc_mkdir("fs/ext4", NULL);
-
- err = ext4_init_feat_adverts();
-
- err = init_ext4_mballoc();
- if (err)
-- goto out3;
-+ goto out4;
-
- err = init_ext4_xattr();
- if (err)
-- goto out2;
-+ goto out3;
- err = init_inodecache();
- if (err)
-+ goto out2;
-+ err = dynlock_cache_init();
-+ if (err)
- goto out1;
- err = register_filesystem(&ext4_fs_type);
- if (err)
-@@ -4643,16 +4646,18 @@ static int __init init_ext4_fs(void)
- mutex_init(&ext4_li_mtx);
- return 0;
- out:
-- destroy_inodecache();
-+ dynlock_cache_exit();
- out1:
-- exit_ext4_xattr();
-+ destroy_inodecache();
- out2:
-- exit_ext4_mballoc();
-+ exit_ext4_xattr();
- out3:
-+ exit_ext4_mballoc();
-+out4:
- ext4_exit_feat_adverts();
- remove_proc_entry("fs/ext4", NULL);
- kset_unregister(ext4_kset);
--out4:
-+out5:
- exit_ext4_system_zone();
- return err;
- }
-@@ -4661,6 +4666,7 @@ static void __exit exit_ext4_fs(void)
- {
- ext4_destroy_lazyinit_thread();
- unregister_filesystem(&ext4_fs_type);
-+ dynlock_cache_exit();
- destroy_inodecache();
- exit_ext4_xattr();
- exit_ext4_mballoc();