1 include/linux/dynlocks.h | 33 ++++++++++
3 lib/dynlocks.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++
4 3 files changed, 187 insertions(+), 2 deletions(-)
6 Index: linux-2.4.24/include/linux/dynlocks.h
7 ===================================================================
8 --- linux-2.4.24.orig/include/linux/dynlocks.h 2003-01-30 13:24:37.000000000 +0300
9 +++ linux-2.4.24/include/linux/dynlocks.h 2004-07-16 14:17:00.000000000 +0400
11 +#ifndef _LINUX_DYNLOCKS_H
12 +#define _LINUX_DYNLOCKS_H
14 +#include <linux/list.h>
15 +#include <linux/wait.h>
17 +#define DYNLOCK_MAGIC 0xd19a10c
18 +#define DYNLOCK_MAGIC2 0xd1956ee
22 +struct dynlock_member {
24 + struct list_head dl_list;
25 + unsigned long dl_value; /* lock value */
26 + int dl_refcount; /* number of users */
29 + int dl_pid; /* holder of the lock */
30 + wait_queue_head_t dl_wait;
31 + struct dynlock *dl_head;
37 + * - lock to protect this list
40 +#define DYNLOCK_LIST_MAGIC 0x11ee91e6
44 + struct list_head dl_list;
45 + spinlock_t dl_list_lock;
46 + struct dynlock * dl_back;
50 +void dynlock_init(struct dynlock *dl);
51 +void *dynlock_lock(struct dynlock *dl, unsigned long value, int rw, int gfp);
52 +void dynlock_unlock(struct dynlock *dl, void *lock);
57 Index: linux-2.4.24/lib/dynlocks.c
58 ===================================================================
59 --- linux-2.4.24.orig/lib/dynlocks.c 2003-01-30 13:24:37.000000000 +0300
60 +++ linux-2.4.24/lib/dynlocks.c 2004-07-16 15:31:06.000000000 +0400
65 + * struct dynlock is lockspace
66 + * one may request lock (exclusive or shared) for some value
71 +#include <linux/dynlocks.h>
72 +#include <linux/module.h>
73 +#include <linux/slab.h>
74 +#include <linux/sched.h>
76 +static kmem_cache_t * dynlock_cachep = NULL;
78 +void __init dynlock_cache_init(void)
80 + printk(KERN_INFO "init dynlocks cache\n");
81 + dynlock_cachep = kmem_cache_create("dynlock_cache",
82 + sizeof(struct dynlock_member),
86 + if (dynlock_cachep == NULL)
87 + panic("Can't create dynlock cache");
90 +static void dynlock_check_consistency(struct dynlock *dl)
92 + struct dynlock_member *hl;
93 + struct list_head *cur;
96 + spin_lock(&dl->dl_list_lock);
98 + BUG_ON(dl->dl_magic != DYNLOCK_LIST_MAGIC);
99 + BUG_ON(dl->dl_back != dl);
100 + list_for_each(cur, &dl->dl_list) {
101 + BUG_ON(cur->next == NULL);
102 + BUG_ON(cur->prev == NULL);
103 + hl = list_entry(cur, struct dynlock_member, dl_list);
104 + if (hl->dl_magic != DYNLOCK_MAGIC || hl->dl_head != dl) {
105 + printk("corrupted lock 0x%p/%d: magic 0x%x (!=0x%x)\n",
106 + hl, num, hl->dl_magic, DYNLOCK_MAGIC);
107 + printk(" value 0x%lx, %d readers, %d writers, pid %d, %d refs\n",
108 + hl->dl_value, hl->dl_readers, hl->dl_writers,
109 + hl->dl_pid, hl->dl_refcount);
110 + printk(" head 0x%p\n", hl->dl_head);
115 + BUG_ON(num != dl->dl_locks);
116 + spin_unlock(&dl->dl_list_lock);
122 + * initialize lockspace
125 +void dynlock_init(struct dynlock *dl)
127 + spin_lock_init(&dl->dl_list_lock);
128 + INIT_LIST_HEAD(&dl->dl_list);
129 + dl->dl_magic = DYNLOCK_LIST_MAGIC;
137 + * acquires lock (exclusive or shared) in specified lockspace
138 + * each lock in lockspace is allocated separately, so user have
139 + * to specify GFP flags.
140 + * routine returns pointer to lock. this pointer is intended to
141 + * be passed to dynlock_unlock
144 +void *dynlock_lock(struct dynlock *dl, unsigned long value, int rw, int gfp)
146 + struct dynlock_member *nhl = NULL;
147 + struct dynlock_member *hl;
148 + struct list_head *cur;
151 + BUG_ON(dl == NULL);
152 + if (dl->dl_magic != DYNLOCK_LIST_MAGIC) {
153 + printk("corrupted dynlock head 0x%p: magic 0x%x (!=0x%x)\n",
154 + dl, dl->dl_magic, DYNLOCK_LIST_MAGIC);
157 + BUG_ON(dl->dl_back != dl);
159 + /* find requested lock in lockspace */
160 + spin_lock(&dl->dl_list_lock);
161 + BUG_ON(dl->dl_list.next == NULL);
162 + BUG_ON(dl->dl_list.prev == NULL);
163 + list_for_each(cur, &dl->dl_list) {
164 + BUG_ON(cur->next == NULL);
165 + BUG_ON(cur->prev == NULL);
166 + hl = list_entry(cur, struct dynlock_member, dl_list);
167 + if (hl->dl_magic != DYNLOCK_MAGIC || hl->dl_head != dl) {
168 + printk("corrupted lock 0x%p/%d: magic 0x%x (!=0x%x)\n",
169 + hl, num, hl->dl_magic, DYNLOCK_MAGIC);
170 + printk(" value 0x%lx, %d readers, %d writers, pid %d, %d refs\n",
171 + hl->dl_value, hl->dl_readers, hl->dl_writers,
172 + hl->dl_pid, hl->dl_refcount);
173 + printk(" head 0x%p\n", hl->dl_head);
176 + if (hl->dl_value == value) {
177 + /* lock is found */
179 + /* someone else just allocated
180 + * lock we didn't find and just created
181 + * so, we drop our lock
183 + kmem_cache_free(dynlock_cachep, nhl);
191 + /* lock not found */
193 + /* we already have allocated lock. use it */
197 + list_add(&hl->dl_list, &dl->dl_list);
200 + spin_unlock(&dl->dl_list_lock);
202 + /* lock not found and we haven't allocated lock yet. allocate it */
203 + nhl = kmem_cache_alloc(dynlock_cachep, gfp);
206 + nhl->dl_refcount = 1;
207 + nhl->dl_value = value;
208 + nhl->dl_readers = 0;
209 + nhl->dl_writers = 0;
210 + nhl->dl_magic = DYNLOCK_MAGIC;
212 + init_waitqueue_head(&nhl->dl_wait);
214 + /* while lock is being allocated, someone else may allocate it
215 + * and put onto to list. check this situation
221 + /* exclusive lock: user don't want to share lock at all
222 + * NOTE: one process may take the same lock several times
223 + * this functionaly is useful for rename operations */
224 + while ((hl->dl_writers && hl->dl_pid != current->pid) ||
226 + spin_unlock(&dl->dl_list_lock);
227 + wait_event(hl->dl_wait,
228 + hl->dl_writers == 0 && hl->dl_readers == 0);
229 + spin_lock(&dl->dl_list_lock);
233 + /* shared lock: user do not want to share lock with writer */
234 + while (hl->dl_writers) {
235 + spin_unlock(&dl->dl_list_lock);
236 + wait_event(hl->dl_wait, hl->dl_writers == 0);
237 + spin_lock(&dl->dl_list_lock);
241 + hl->dl_pid = current->pid;
242 + spin_unlock(&dl->dl_list_lock);
244 + BUG_ON(hl->dl_magic != DYNLOCK_MAGIC);
245 + dynlock_check_consistency(dl);
253 + * user have to specify lockspace (dl) and pointer to lock structure
254 + * returned by dynlock_lock()
257 +void dynlock_unlock(struct dynlock *dl, void *lock)
259 + struct dynlock_member *hl = lock;
262 + BUG_ON(dl == NULL);
263 + BUG_ON(hl == NULL);
264 + BUG_ON(dl->dl_magic != DYNLOCK_LIST_MAGIC);
265 + BUG_ON(dl->dl_back != dl);
266 + if (hl->dl_magic != DYNLOCK_MAGIC || hl->dl_head != dl) {
267 + printk("corrupted lock 0x%p: magic 0x%x (!=0x%x)\n",
268 + hl, hl->dl_magic, DYNLOCK_MAGIC);
269 + printk(" value 0x%lx, %d readers, %d writers, pid %d, %d refs\n",
270 + hl->dl_value, hl->dl_readers, hl->dl_writers,
271 + hl->dl_pid, hl->dl_refcount);
272 + printk(" head 0x%p\n", hl->dl_head);
275 + BUG_ON(current->pid != hl->dl_pid);
277 + spin_lock(&dl->dl_list_lock);
278 + if (hl->dl_writers) {
279 + BUG_ON(hl->dl_readers > 0 || hl->dl_readers < 0);
281 + if (hl->dl_writers == 0)
283 + } else if (hl->dl_readers) {
285 + if (hl->dl_readers == 0)
292 + wake_up(&hl->dl_wait);
294 + if (--(hl->dl_refcount) == 0) {
295 + hl->dl_magic = DYNLOCK_MAGIC2;
296 + list_del(&hl->dl_list);
299 + spin_unlock(&dl->dl_list_lock);
300 + if (hl->dl_refcount == 0)
301 + kmem_cache_free(dynlock_cachep, hl);
302 + dynlock_check_consistency(dl);
305 +EXPORT_SYMBOL(dynlock_init);
306 +EXPORT_SYMBOL(dynlock_lock);
307 +EXPORT_SYMBOL(dynlock_unlock);
309 Index: linux-2.4.24/lib/Makefile
310 ===================================================================
311 --- linux-2.4.24.orig/lib/Makefile 2004-06-24 09:06:32.000000000 +0400
312 +++ linux-2.4.24/lib/Makefile 2004-07-14 18:14:28.000000000 +0400
316 export-objs := cmdline.o dec_and_lock.o rwsem-spinlock.o rwsem.o \
317 - rbtree.o crc32.o firmware_class.o
318 + rbtree.o crc32.o firmware_class.o dynlocks.o
320 obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o \
321 - bust_spinlocks.o rbtree.o dump_stack.o
322 + bust_spinlocks.o rbtree.o dump_stack.o dynlocks.o
324 obj-$(CONFIG_FW_LOADER) += firmware_class.o
325 obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
326 Index: linux-2.4.24/fs/dcache.c
327 ===================================================================
328 --- linux-2.4.24.orig/fs/dcache.c 2004-07-16 12:35:54.000000000 +0400
329 +++ linux-2.4.24/fs/dcache.c 2004-07-16 12:36:14.000000000 +0400
330 @@ -1274,6 +1274,7 @@
331 extern void bdev_cache_init(void);
332 extern void cdev_cache_init(void);
333 extern void iobuf_cache_init(void);
334 +extern void dynlock_cache_init(void);
336 void __init vfs_caches_init(unsigned long mempages)
338 @@ -1310,4 +1311,5 @@
342 + dynlock_cache_init();