1 include/linux/dynlocks.h | 33 ++++++++++
3 lib/dynlocks.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++
4 3 files changed, 187 insertions(+), 2 deletions(-)
6 Index: linux-2.6.10/lib/dynlocks.c
7 ===================================================================
8 --- linux-2.6.10.orig/lib/dynlocks.c 2005-03-31 16:59:29.399768040 +0800
9 +++ linux-2.6.10/lib/dynlocks.c 2005-03-31 18:02:41.470646856 +0800
14 + * struct dynlock is lockspace
15 + * one may request lock (exclusive or shared) for some value
20 +#include <linux/dynlocks.h>
21 +#include <linux/module.h>
22 +#include <linux/slab.h>
23 +#include <linux/sched.h>
25 +static kmem_cache_t * dynlock_cachep = NULL;
27 +void __init dynlock_cache_init(void)
29 + printk(KERN_INFO "init dynlocks cache\n");
30 + dynlock_cachep = kmem_cache_create("dynlock_cache",
31 + sizeof(struct dynlock_member),
35 + if (dynlock_cachep == NULL)
36 + panic("Can't create dynlock cache");
42 + * initialize lockspace
45 +void dynlock_init(struct dynlock *dl)
47 + spin_lock_init(&dl->dl_list_lock);
48 + INIT_LIST_HEAD(&dl->dl_list);
49 + dl->dl_magic = DYNLOCK_LIST_MAGIC;
55 + * acquires lock (exclusive or shared) in specified lockspace
56 + * each lock in lockspace is allocated separately, so user have
57 + * to specify GFP flags.
58 + * routine returns pointer to lock. this pointer is intended to
59 + * be passed to dynlock_unlock
62 +void *dynlock_lock(struct dynlock *dl, unsigned long value, int rw, int gfp)
64 + struct dynlock_member *nhl = NULL;
65 + struct dynlock_member *hl;
66 + struct list_head *cur;
70 + BUG_ON(dl->dl_magic != DYNLOCK_LIST_MAGIC);
72 + /* find requested lock in lockspace */
73 + spin_lock(&dl->dl_list_lock);
74 + BUG_ON(dl->dl_list.next == NULL);
75 + BUG_ON(dl->dl_list.prev == NULL);
76 + list_for_each(cur, &dl->dl_list) {
77 + BUG_ON(cur->next == NULL);
78 + BUG_ON(cur->prev == NULL);
79 + hl = list_entry(cur, struct dynlock_member, dl_list);
80 + BUG_ON(hl->dl_magic != DYNLOCK_MAGIC);
81 + if (hl->dl_value == value) {
84 + /* someone else just allocated
85 + * lock we didn't find and just created
86 + * so, we drop our lock
88 + kmem_cache_free(dynlock_cachep, nhl);
96 + /* lock not found */
98 + /* we already have allocated lock. use it */
101 + list_add(&hl->dl_list, &dl->dl_list);
104 + spin_unlock(&dl->dl_list_lock);
106 + /* lock not found and we haven't allocated lock yet. allocate it */
107 + nhl = kmem_cache_alloc(dynlock_cachep, gfp);
110 + nhl->dl_refcount = 1;
111 + nhl->dl_value = value;
112 + nhl->dl_readers = 0;
113 + nhl->dl_writers = 0;
114 + nhl->dl_magic = DYNLOCK_MAGIC;
115 + init_waitqueue_head(&nhl->dl_wait);
117 + /* while lock is being allocated, someone else may allocate it
118 + * and put onto to list. check this situation
124 + /* exclusive lock: user don't want to share lock at all
125 + * NOTE: one process may take the same lock several times
126 + * this functionaly is useful for rename operations */
127 + while ((hl->dl_writers && hl->dl_pid != current->pid) ||
129 + spin_unlock(&dl->dl_list_lock);
130 + wait_event(hl->dl_wait,
131 + hl->dl_writers == 0 && hl->dl_readers == 0);
132 + spin_lock(&dl->dl_list_lock);
136 + /* shared lock: user do not want to share lock with writer */
137 + while (hl->dl_writers) {
138 + spin_unlock(&dl->dl_list_lock);
139 + wait_event(hl->dl_wait, hl->dl_writers == 0);
140 + spin_lock(&dl->dl_list_lock);
144 + hl->dl_pid = current->pid;
145 + spin_unlock(&dl->dl_list_lock);
154 + * user have to specify lockspace (dl) and pointer to lock structure
155 + * returned by dynlock_lock()
158 +void dynlock_unlock(struct dynlock *dl, void *lock)
160 + struct dynlock_member *hl = lock;
163 + BUG_ON(dl == NULL);
164 + BUG_ON(hl == NULL);
165 + BUG_ON(dl->dl_magic != DYNLOCK_LIST_MAGIC);
166 + BUG_ON(hl->dl_magic != DYNLOCK_MAGIC);
167 + BUG_ON(current->pid != hl->dl_pid);
169 + spin_lock(&dl->dl_list_lock);
170 + if (hl->dl_writers) {
171 + BUG_ON(hl->dl_readers > 0 || hl->dl_readers < 0);
173 + if (hl->dl_writers == 0)
175 + } else if (hl->dl_readers) {
177 + if (hl->dl_readers == 0)
184 + wake_up(&hl->dl_wait);
186 + if (--(hl->dl_refcount) == 0) {
187 + hl->dl_magic = DYNLOCK_MAGIC2;
188 + list_del(&hl->dl_list);
189 + kmem_cache_free(dynlock_cachep, hl);
191 + spin_unlock(&dl->dl_list_lock);
194 +EXPORT_SYMBOL(dynlock_init);
195 +EXPORT_SYMBOL(dynlock_lock);
196 +EXPORT_SYMBOL(dynlock_unlock);
198 Index: linux-2.6.10/lib/Makefile
199 ===================================================================
200 --- linux-2.6.10.orig/lib/Makefile 2004-12-25 05:33:50.000000000 +0800
201 +++ linux-2.6.10/lib/Makefile 2005-03-31 18:03:16.727287032 +0800
203 lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
204 bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
205 kobject.o kref.o idr.o div64.o parser.o int_sqrt.o \
206 - bitmap.o extable.o kobject_uevent.o
207 + bitmap.o extable.o kobject_uevent.o dynlocks.o
209 ifeq ($(CONFIG_DEBUG_KOBJECT),y)
210 CFLAGS_kobject.o += -DDEBUG
211 Index: linux-2.6.10/fs/dcache.c
212 ===================================================================
213 --- linux-2.6.10.orig/fs/dcache.c 2005-03-31 17:02:41.000000000 +0800
214 +++ linux-2.6.10/fs/dcache.c 2005-03-31 18:02:41.474646248 +0800
215 @@ -1655,6 +1655,7 @@
217 extern void bdev_cache_init(void);
218 extern void chrdev_init(void);
219 +extern void dynlock_cache_init(void);
221 void __init vfs_caches_init_early(void)
223 @@ -1684,6 +1685,7 @@
227 + dynlock_cache_init();
230 EXPORT_SYMBOL(d_alloc);
231 Index: linux-2.6.10/include/linux/dynlocks.h
232 ===================================================================
233 --- linux-2.6.10.orig/include/linux/dynlocks.h 2005-03-31 16:59:29.399768040 +0800
234 +++ linux-2.6.10/include/linux/dynlocks.h 2005-03-31 18:02:41.469647008 +0800
236 +#ifndef _LINUX_DYNLOCKS_H
237 +#define _LINUX_DYNLOCKS_H
239 +#include <linux/list.h>
240 +#include <linux/wait.h>
242 +#define DYNLOCK_MAGIC 0xd19a10c
243 +#define DYNLOCK_MAGIC2 0xd1956ee
247 +struct dynlock_member {
249 + struct list_head dl_list;
250 + unsigned long dl_value; /* lock value */
251 + int dl_refcount; /* number of users */
254 + int dl_pid; /* holder of the lock */
255 + wait_queue_head_t dl_wait;
259 + * lock's namespace:
261 + * - lock to protect this list
264 +#define DYNLOCK_LIST_MAGIC 0x11ee91e6
268 + struct list_head dl_list;
269 + spinlock_t dl_list_lock;
272 +void dynlock_init(struct dynlock *dl);
273 +void *dynlock_lock(struct dynlock *dl, unsigned long value, int rw, int gfp);
274 +void dynlock_unlock(struct dynlock *dl, void *lock);