Whamcloud - gitweb
- slab-use-after-free debug tool added to vanilla-2.4.24 series to debug 3772
[fs/lustre-release.git] / lustre / kernel_patches / patches / dynamic-locks-2.4.24.patch
1  include/linux/dynlocks.h |   33 ++++++++++
2  lib/Makefile             |    4 -
3  lib/dynlocks.c           |  152 +++++++++++++++++++++++++++++++++++++++++++++++
4  3 files changed, 187 insertions(+), 2 deletions(-)
5
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
10 @@ -0,0 +1,46 @@
11 +#ifndef _LINUX_DYNLOCKS_H
12 +#define _LINUX_DYNLOCKS_H
13 +
14 +#include <linux/list.h>
15 +#include <linux/wait.h>
16 +
17 +#define DYNLOCK_MAGIC          0xd19a10c
18 +#define DYNLOCK_MAGIC2         0xd1956ee
19 +
20 +struct dynlock;
21 +
22 +struct dynlock_member {
23 +       unsigned                dl_magic;
24 +       struct list_head        dl_list;
25 +       unsigned long           dl_value;       /* lock value */
26 +       int                     dl_refcount;    /* number of users */
27 +       int                     dl_readers;
28 +       int                     dl_writers;
29 +       int                     dl_pid;         /* holder of the lock */
30 +       wait_queue_head_t       dl_wait;
31 +       struct dynlock          *dl_head;
32 +};
33 +
34 +/*
35 + * lock's namespace:
36 + *   - list of locks
37 + *   - lock to protect this list
38 + */
39 +
40 +#define DYNLOCK_LIST_MAGIC     0x11ee91e6
41 +
42 +struct dynlock {
43 +       unsigned dl_magic;
44 +       struct list_head dl_list;
45 +       spinlock_t dl_list_lock;
46 +       struct dynlock * dl_back;
47 +       int dl_locks;
48 +};
49 +
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);
53 +
54 +
55 +#endif
56 +
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
61 @@ -0,0 +1,247 @@
62 +/*
63 + * Dynamic Locks
64 + *
65 + * struct dynlock is lockspace
66 + * one may request lock (exclusive or shared) for some value
67 + * in that lockspace
68 + *
69 + */
70 +
71 +#include <linux/dynlocks.h>
72 +#include <linux/module.h>
73 +#include <linux/slab.h>
74 +#include <linux/sched.h>
75 +
76 +static kmem_cache_t * dynlock_cachep = NULL;
77 +
78 +void __init dynlock_cache_init(void)
79 +{
80 +       printk(KERN_INFO "init dynlocks cache\n");
81 +       dynlock_cachep = kmem_cache_create("dynlock_cache",
82 +                                        sizeof(struct dynlock_member),
83 +                                        0,
84 +                                        SLAB_HWCACHE_ALIGN,
85 +                                        NULL, NULL);
86 +       if (dynlock_cachep == NULL)
87 +               panic("Can't create dynlock cache");
88 +}
89 +
90 +static void dynlock_check_consistency(struct dynlock *dl)
91 +{
92 +       struct dynlock_member *hl; 
93 +       struct list_head *cur;
94 +       int num = 0;
95 +       
96 +       spin_lock(&dl->dl_list_lock);
97 +       BUG_ON(dl == NULL);
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);
111 +                       BUG();
112 +               }
113 +               num++;
114 +       }
115 +       BUG_ON(num != dl->dl_locks);
116 +       spin_unlock(&dl->dl_list_lock);
117 +}
118 +
119 +/*
120 + * dynlock_init
121 + *
122 + * initialize lockspace
123 + *
124 + */
125 +void dynlock_init(struct dynlock *dl)
126 +{
127 +       spin_lock_init(&dl->dl_list_lock);
128 +       INIT_LIST_HEAD(&dl->dl_list);
129 +       dl->dl_magic = DYNLOCK_LIST_MAGIC;
130 +       dl->dl_back = dl;
131 +       dl->dl_locks = 0;
132 +}
133 +
134 +/*
135 + * dynlock_lock
136 + *
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
142 + *
143 + */
144 +void *dynlock_lock(struct dynlock *dl, unsigned long value, int rw, int gfp)
145 +{
146 +       struct dynlock_member *nhl = NULL; 
147 +       struct dynlock_member *hl; 
148 +       struct list_head *cur;
149 +       int num = 0;
150 +
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);
155 +               BUG();
156 +       }
157 +       BUG_ON(dl->dl_back != dl);
158 +repeat:
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);
174 +                       BUG();
175 +               }
176 +               if (hl->dl_value == value) {
177 +                       /* lock is found */
178 +                       if (nhl) {
179 +                               /* someone else just allocated
180 +                                * lock we didn't find and just created
181 +                                * so, we drop our lock
182 +                                */
183 +                               kmem_cache_free(dynlock_cachep, nhl);
184 +                               nhl = NULL;
185 +                       }
186 +                       hl->dl_refcount++;
187 +                       goto found;
188 +               }
189 +               num++;
190 +       }
191 +       /* lock not found */
192 +       if (nhl) {
193 +               /* we already have allocated lock. use it */
194 +               hl = nhl;
195 +               nhl = NULL;
196 +               dl->dl_locks++;
197 +               list_add(&hl->dl_list, &dl->dl_list);
198 +               goto found;
199 +       }
200 +       spin_unlock(&dl->dl_list_lock);
201 +       
202 +       /* lock not found and we haven't allocated lock yet. allocate it */
203 +       nhl = kmem_cache_alloc(dynlock_cachep, gfp);
204 +       if (nhl == NULL)
205 +               return NULL;
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;
211 +       nhl->dl_head = dl;
212 +       init_waitqueue_head(&nhl->dl_wait);
213 +
214 +       /* while lock is being allocated, someone else may allocate it
215 +        * and put onto to list. check this situation
216 +        */
217 +       goto repeat;
218 +
219 +found:
220 +       if (rw) {
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) ||
225 +                               hl->dl_readers) {
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);
230 +               }
231 +               hl->dl_writers++;
232 +       } else {
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);
238 +               }
239 +               hl->dl_readers++;
240 +       }
241 +       hl->dl_pid = current->pid;
242 +       spin_unlock(&dl->dl_list_lock);
243 +
244 +       BUG_ON(hl->dl_magic != DYNLOCK_MAGIC);
245 +       dynlock_check_consistency(dl);
246 +       return hl;
247 +}
248 +
249 +
250 +/*
251 + * dynlock_unlock
252 + *
253 + * user have to specify lockspace (dl) and pointer to lock structure
254 + * returned by dynlock_lock()
255 + *
256 + */
257 +void dynlock_unlock(struct dynlock *dl, void *lock)
258 +{
259 +       struct dynlock_member *hl = lock;
260 +       int wakeup = 0;
261 +       
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);
273 +               BUG();
274 +       }
275 +       BUG_ON(current->pid != hl->dl_pid);
276 +
277 +       spin_lock(&dl->dl_list_lock);
278 +       if (hl->dl_writers) {
279 +               BUG_ON(hl->dl_readers > 0 || hl->dl_readers < 0);
280 +               hl->dl_writers--;
281 +               if (hl->dl_writers == 0)
282 +                       wakeup = 1;
283 +       } else if (hl->dl_readers) {
284 +               hl->dl_readers--;
285 +               if (hl->dl_readers == 0)
286 +                       wakeup = 1;
287 +       } else {
288 +               BUG_ON(1);
289 +       }
290 +       if (wakeup) {
291 +               hl->dl_pid = 0;
292 +               wake_up(&hl->dl_wait);
293 +       }
294 +       if (--(hl->dl_refcount) == 0) {
295 +               hl->dl_magic = DYNLOCK_MAGIC2;
296 +               list_del(&hl->dl_list);
297 +               dl->dl_locks--;
298 +       }
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);
303 +}
304 +
305 +EXPORT_SYMBOL(dynlock_init);
306 +EXPORT_SYMBOL(dynlock_lock);
307 +EXPORT_SYMBOL(dynlock_unlock);
308 +
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
313 @@ -9,10 +9,10 @@
314  L_TARGET := lib.a
315  
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
319  
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
323  
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);
335  
336  void __init vfs_caches_init(unsigned long mempages)
337  {
338 @@ -1310,4 +1311,5 @@
339         bdev_cache_init();
340         cdev_cache_init();
341         iobuf_cache_init();
342 +       dynlock_cache_init();
343  }