+++ /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
-+