--- /dev/null
+ include/linux/dynlocks.h | 33 ++++++++++
+ lib/Makefile | 4 -
+ lib/dynlocks.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 187 insertions(+), 2 deletions(-)
+
+Index: linux-2.6.10/lib/dynlocks.c
+===================================================================
+--- linux-2.6.10.orig/lib/dynlocks.c 2005-03-31 16:59:29.399768040 +0800
++++ linux-2.6.10/lib/dynlocks.c 2005-03-31 18:02:41.470646856 +0800
+@@ -0,0 +1,187 @@
++/*
++ * 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>
++
++static kmem_cache_t * dynlock_cachep = NULL;
++
++void __init dynlock_cache_init(void)
++{
++ printk(KERN_INFO "init dynlocks cache\n");
++ dynlock_cachep = kmem_cache_create("dynlock_cache",
++ sizeof(struct dynlock_member),
++ 0,
++ SLAB_HWCACHE_ALIGN,
++ NULL, NULL);
++ if (dynlock_cachep == NULL)
++ panic("Can't create dynlock cache");
++}
++
++/*
++ * 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;
++}
++
++/*
++ * 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
++ *
++ */
++void *dynlock_lock(struct dynlock *dl, unsigned long value, int rw, int gfp)
++{
++ struct dynlock_member *nhl = NULL;
++ struct dynlock_member *hl;
++ struct list_head *cur;
++ int num = 0;
++
++ 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(cur, &dl->dl_list) {
++ BUG_ON(cur->next == NULL);
++ BUG_ON(cur->prev == NULL);
++ hl = list_entry(cur, struct dynlock_member, dl_list);
++ BUG_ON(hl->dl_magic != DYNLOCK_MAGIC);
++ if (hl->dl_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->dl_refcount++;
++ goto found;
++ }
++ num++;
++ }
++ /* lock not found */
++ if (nhl) {
++ /* we already have allocated lock. use it */
++ hl = nhl;
++ nhl = NULL;
++ list_add(&hl->dl_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->dl_refcount = 1;
++ nhl->dl_value = value;
++ nhl->dl_readers = 0;
++ nhl->dl_writers = 0;
++ nhl->dl_magic = DYNLOCK_MAGIC;
++ init_waitqueue_head(&nhl->dl_wait);
++
++ /* while lock is being allocated, someone else may allocate it
++ * and put onto to list. check this situation
++ */
++ goto repeat;
++
++found:
++ if (rw) {
++ /* 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->dl_writers && hl->dl_pid != current->pid) ||
++ hl->dl_readers) {
++ spin_unlock(&dl->dl_list_lock);
++ wait_event(hl->dl_wait,
++ hl->dl_writers == 0 && hl->dl_readers == 0);
++ spin_lock(&dl->dl_list_lock);
++ }
++ hl->dl_writers++;
++ } else {
++ /* shared lock: user do not want to share lock with writer */
++ while (hl->dl_writers) {
++ spin_unlock(&dl->dl_list_lock);
++ wait_event(hl->dl_wait, hl->dl_writers == 0);
++ spin_lock(&dl->dl_list_lock);
++ }
++ hl->dl_readers++;
++ }
++ hl->dl_pid = current->pid;
++ spin_unlock(&dl->dl_list_lock);
++
++ return hl;
++}
++
++
++/*
++ * dynlock_unlock
++ *
++ * user have to specify lockspace (dl) and pointer to lock structure
++ * returned by dynlock_lock()
++ *
++ */
++void dynlock_unlock(struct dynlock *dl, void *lock)
++{
++ struct dynlock_member *hl = lock;
++ int wakeup = 0;
++
++ BUG_ON(dl == NULL);
++ BUG_ON(hl == NULL);
++ BUG_ON(dl->dl_magic != DYNLOCK_LIST_MAGIC);
++ BUG_ON(hl->dl_magic != DYNLOCK_MAGIC);
++ BUG_ON(current->pid != hl->dl_pid);
++
++ spin_lock(&dl->dl_list_lock);
++ if (hl->dl_writers) {
++ BUG_ON(hl->dl_readers > 0 || hl->dl_readers < 0);
++ hl->dl_writers--;
++ if (hl->dl_writers == 0)
++ wakeup = 1;
++ } else if (hl->dl_readers) {
++ hl->dl_readers--;
++ if (hl->dl_readers == 0)
++ wakeup = 1;
++ } else {
++ BUG_ON(1);
++ }
++ if (wakeup) {
++ hl->dl_pid = 0;
++ wake_up(&hl->dl_wait);
++ }
++ if (--(hl->dl_refcount) == 0) {
++ hl->dl_magic = DYNLOCK_MAGIC2;
++ list_del(&hl->dl_list);
++ kmem_cache_free(dynlock_cachep, hl);
++ }
++ spin_unlock(&dl->dl_list_lock);
++}
++
++EXPORT_SYMBOL(dynlock_init);
++EXPORT_SYMBOL(dynlock_lock);
++EXPORT_SYMBOL(dynlock_unlock);
++
+Index: linux-2.6.10/lib/Makefile
+===================================================================
+--- linux-2.6.10.orig/lib/Makefile 2004-12-25 05:33:50.000000000 +0800
++++ linux-2.6.10/lib/Makefile 2005-03-31 18:03:16.727287032 +0800
+@@ -5,7 +5,7 @@
+ lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
+ bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
+ kobject.o kref.o idr.o div64.o parser.o int_sqrt.o \
+- bitmap.o extable.o kobject_uevent.o
++ bitmap.o extable.o kobject_uevent.o dynlocks.o
+
+ ifeq ($(CONFIG_DEBUG_KOBJECT),y)
+ CFLAGS_kobject.o += -DDEBUG
+Index: linux-2.6.10/fs/dcache.c
+===================================================================
+--- linux-2.6.10.orig/fs/dcache.c 2005-03-31 17:02:41.000000000 +0800
++++ linux-2.6.10/fs/dcache.c 2005-03-31 18:02:41.474646248 +0800
+@@ -1655,6 +1655,7 @@
+
+ extern void bdev_cache_init(void);
+ extern void chrdev_init(void);
++extern void dynlock_cache_init(void);
+
+ void __init vfs_caches_init_early(void)
+ {
+@@ -1684,6 +1685,7 @@
+ mnt_init(mempages);
+ bdev_cache_init();
+ chrdev_init();
++ dynlock_cache_init();
+ }
+
+ EXPORT_SYMBOL(d_alloc);
+Index: linux-2.6.10/include/linux/dynlocks.h
+===================================================================
+--- linux-2.6.10.orig/include/linux/dynlocks.h 2005-03-31 16:59:29.399768040 +0800
++++ linux-2.6.10/include/linux/dynlocks.h 2005-03-31 18:02:41.469647008 +0800
+@@ -0,0 +1,43 @@
++#ifndef _LINUX_DYNLOCKS_H
++#define _LINUX_DYNLOCKS_H
++
++#include <linux/list.h>
++#include <linux/wait.h>
++
++#define DYNLOCK_MAGIC 0xd19a10c
++#define DYNLOCK_MAGIC2 0xd1956ee
++
++struct dynlock;
++
++struct dynlock_member {
++ unsigned dl_magic;
++ struct list_head dl_list;
++ unsigned long dl_value; /* lock value */
++ int dl_refcount; /* number of users */
++ int dl_readers;
++ int dl_writers;
++ int dl_pid; /* holder of the lock */
++ wait_queue_head_t dl_wait;
++};
++
++/*
++ * lock's namespace:
++ * - list of locks
++ * - lock to protect this list
++ */
++
++#define DYNLOCK_LIST_MAGIC 0x11ee91e6
++
++struct dynlock {
++ unsigned dl_magic;
++ struct list_head dl_list;
++ spinlock_t dl_list_lock;
++};
++
++void dynlock_init(struct dynlock *dl);
++void *dynlock_lock(struct dynlock *dl, unsigned long value, int rw, int gfp);
++void dynlock_unlock(struct dynlock *dl, void *lock);
++
++
++#endif
++