Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


bfa05660f355e5fe316b9755f7649b340e91d5d0
[palacios.git] / linux_module / lockcheck.c
1 #include <linux/kernel.h>
2 #include <linux/kthread.h>
3 #include <linux/spinlock.h>
4
5 #include "palacios.h"
6
7 #include "lockcheck.h"
8
9 // How far up the stack to track the caller
10 // 0 => palacios_...
11 // 1 => v3_lock...
12 // 2 => caller of v3_lock..
13 // ... 
14 #define STEP_BACK_DEPTH_FIRST 1
15 #define STEP_BACK_DEPTH_LAST  4
16 #define STEP_BACK_DEPTH       (STEP_BACK_DEPTH_LAST-STEP_BACK_DEPTH_FIRST+1)
17
18 // show when multiple locks are held simultaneously
19 // This is the minimum number
20 #define WARN_MULTIPLE_THRESHOLD 3
21
22 typedef struct {
23   int  inuse;         // nonzero if this is in use
24   void *lock;         // the lock
25   void *allocator[STEP_BACK_DEPTH];
26                       // who allocated this
27   int   lockcount;    // how many times it's been locked/unlocked (lock=+1, unlock=-1)
28   int   irqcount;     // how many times interrupts have been turned off (+1/-1)
29   void *lastlocker[STEP_BACK_DEPTH];
30                       // who last locked
31   void *lastunlocker[STEP_BACK_DEPTH]; 
32                       // who last unlocked
33   void *lastirqlocker[STEP_BACK_DEPTH];
34                       // who last locked
35   unsigned long lastlockflags; // their flags
36   void *lastirqunlocker[STEP_BACK_DEPTH]
37                     ; // who last unlocked
38   unsigned long lastunlockflags; // their flags
39 } lockcheck_state_t;
40
41
42 // This lock is currently used only to control
43 // allocation of entries in the global state
44 static spinlock_t lock; 
45 static lockcheck_state_t state[NUM_LOCKS];
46
47 static void printlock(char *prefix, lockcheck_state_t *l);
48
49
50 typedef struct {
51   u32 top;               // next open slot 0..
52   void *lock[LOCK_STACK_DEPTH]; // the stack
53   char irq[LOCK_STACK_DEPTH];   // locked with irqsave?
54 } lock_stack_t;
55
56 static DEFINE_PER_CPU(lock_stack_t, lock_stack);
57
58 static lockcheck_state_t *get_lock_entry(void)
59 {
60   int i;
61   unsigned long f;
62   lockcheck_state_t *l;
63
64   spin_lock_irqsave(&lock,f);
65
66   for (i=0;i<NUM_LOCKS;i++) { 
67     l=&(state[i]);
68     if (!(l->inuse)) { 
69       l->inuse=1;
70       break;
71     }
72   }
73
74   spin_unlock_irqrestore(&lock,f);
75   
76   if (i<NUM_LOCKS) { 
77     return l;
78   } else {
79     return 0;
80   }
81 }
82
83
84 static lockcheck_state_t *find_lock_entry(void *lock)
85 {
86   int i;
87   lockcheck_state_t *l;
88
89   for (i=0;i<NUM_LOCKS;i++) { 
90     l=&(state[i]);
91     if (l->inuse && l->lock == lock) { 
92       return l;
93     }
94   }
95   return 0;
96 }
97
98
99 static void free_lock_entry(lockcheck_state_t *l)
100 {
101   l->inuse=0;
102 }
103
104
105 static void lock_stack_print(void)
106 {
107   u32 i;
108   char buf[64];
109   lock_stack_t *mystack = &(get_cpu_var(lock_stack));
110   u32 cpu = get_cpu();  put_cpu();
111   
112   if ((mystack->top)>0) { 
113     for (i=mystack->top; i>0;i--) {
114       snprintf(buf,64,"LOCK STACK (cpu=%u, index=%u, irq=%d)",cpu, i-1, (int)(mystack->irq[i-1]));
115       printlock(buf,find_lock_entry(mystack->lock[i-1]));
116     }
117   }
118   put_cpu_var(lock_stack);
119 }
120
121
122 static void lock_stack_lock(void *lock, char irq)
123 {
124   lock_stack_t *mystack = &(get_cpu_var(lock_stack));
125   u32 cpu = get_cpu();  put_cpu();
126
127   if (mystack->top>=(LOCK_STACK_DEPTH-1)) {
128     put_cpu_var(lock_stack);
129     DEBUG("LOCKCHECK: Locking lock 0x%p on cpu %u exceeds stack limit of %d\n",lock,cpu,LOCK_STACK_DEPTH);
130     lock_stack_print();
131   } else {
132     mystack->lock[mystack->top] = lock;
133     mystack->irq[mystack->top] = irq;
134     mystack->top++;
135     put_cpu_var(lock_stack);
136   }
137 }
138
139 static void lock_stack_unlock(void *lock, char irq)
140 {
141   lock_stack_t *mystack = &(get_cpu_var(lock_stack));
142   u32 cpu = get_cpu(); put_cpu();
143
144   if (mystack->top==0) {
145     put_cpu_var(lock_stack);
146     DEBUG("LOCKCHECK: Unlocking lock 0x%p on cpu %u when lock stack is empty\n",lock,cpu);
147   } else {
148     if (mystack->lock[mystack->top-1] != lock) { 
149       void *otherlock=mystack->lock[mystack->top-1];
150       put_cpu_var(lock_stack);
151       DEBUG("LOCKCHECK: Unlocking lock 0x%p on cpu %u when top of stack is lock 0x%p\n",lock,cpu, otherlock);
152       lock_stack_print();
153     } else {
154       if (irq!=mystack->irq[mystack->top-1]) {
155         char otherirq = mystack->irq[mystack->top-1];
156         put_cpu_var(lock_stack);
157         DEBUG("LOCKCHECK: Unlocking lock 0x%p on cpu %u with irq=%d, but was locked with irq=%d\n",lock,cpu,irq,otherirq);
158         lock_stack_print();
159       } else {
160         mystack->top--;
161         put_cpu_var(lock_stack);
162       }
163     }
164   }
165
166 }
167
168 void palacios_lockcheck_init()
169 {
170   memset(state,0,sizeof(lockcheck_state_t)*NUM_LOCKS);
171   spin_lock_init(&lock);
172   DEBUG("LOCKCHECK: LOCK CHECKING INITED\n");
173 }
174
175 //
176 // This needs to be defined explictly since the intrinsic does not take a var
177 //
178 #define backtrace(t) \
179   t[0]=__builtin_return_address(STEP_BACK_DEPTH_FIRST); \
180   t[1]=__builtin_return_address(STEP_BACK_DEPTH_FIRST+1); \
181   t[2]=__builtin_return_address(STEP_BACK_DEPTH_FIRST+2); \
182   t[3]=__builtin_return_address(STEP_BACK_DEPTH_FIRST+3); 
183
184 //
185 // For printing a backtrace
186 //
187 //
188 #define backtrace_format "%pS << %pS << %pS << %pS"
189 #define backtrace_expand(t) ((t)[0]),((t)[1]),((t)[2]),((t)[3])
190
191
192 static void clear_trace(void **trace)
193 {
194   int i;
195
196   for (i=0;i<STEP_BACK_DEPTH;i++) { 
197     trace[i]=0;
198   }
199 }
200
201
202 static void printlock(char *prefix, lockcheck_state_t *l)
203 {
204   if (!l || !(l->lock) ) { 
205     DEBUG("LOCKCHECK: %s: lock 0x%p BOGUS\n",prefix,l);
206     return;
207   }
208   if (l->lock) { 
209     DEBUG("LOCKCHECK: %s: lock 0x%p, allocator=" 
210           backtrace_format
211           ", lockcount=%d, lastlocker="
212           backtrace_format
213           ", lastunlocker="
214           backtrace_format
215           ", irqcount=%d, lastirqlocker="
216           backtrace_format
217           ", lastlockflags=%lu, lastirqunlocker="
218           backtrace_format
219           ", lastunlockflags=%lu\n",
220           prefix,l->lock,
221           backtrace_expand(l->allocator),
222           l->lockcount,
223           backtrace_expand(l->lastlocker),
224           backtrace_expand(l->lastunlocker),
225           l->irqcount,
226           backtrace_expand(l->lastirqlocker),
227           l->lastlockflags,
228           backtrace_expand(l->lastirqunlocker),
229           l->lastunlockflags);
230   }
231 }
232
233
234
235 static void find_multiple_locks_held(void)
236 {
237   int i;
238   int have=0;
239   lockcheck_state_t *l;
240   char buf[64];
241
242   for (i=0;i<NUM_LOCKS;i++) { 
243     l=&(state[i]);
244     if (l->inuse && l->lockcount>0) { 
245       have++;
246       if (have>=WARN_MULTIPLE_THRESHOLD) { 
247         break;
248       }
249     }
250   }
251   
252   if (have>=WARN_MULTIPLE_THRESHOLD) { 
253     have=0;
254     for (i=0;i<NUM_LOCKS;i++) { 
255       l=&(state[i]);
256       if (l->inuse && l->lockcount>0) {
257         snprintf(buf,64,"MULTIPLE LOCKS HELD (%d)",have);
258         printlock(buf,l);
259         have++;
260       }
261     }
262   }
263     
264 }
265
266 static void find_multiple_irqs_held(void)
267 {
268   int i;
269   int have=0;
270   lockcheck_state_t *l;
271   char buf[64];
272
273   for (i=0;i<NUM_LOCKS;i++) { 
274     l=&(state[i]);
275     if (l->inuse && l->irqcount>0) {
276       have++;
277       if (have>=WARN_MULTIPLE_THRESHOLD) { 
278         break;
279       }
280     }
281   }
282   
283   if (have>=WARN_MULTIPLE_THRESHOLD) { 
284     have=0;
285     for (i=0;i<NUM_LOCKS;i++) { 
286       l=&(state[i]);
287       if (l->inuse && l->irqcount>0) { 
288         snprintf(buf,64,"MULTIPLE IRQS HELD (%d)",have);
289         printlock(buf,l);
290         have++;
291       }
292     }
293   }
294
295 }
296
297
298 void palacios_lockcheck_deinit()
299 {
300   int i;
301   lockcheck_state_t *l;
302   
303   for (i=0;i<NUM_LOCKS;i++) { 
304     l=&(state[i]);
305     if (l->lock) { 
306       printlock("ALLOCATED LOCK AT DEINIT",l);
307       if ((l->lockcount)) { 
308         printlock("BAD LOCK COUNT AT DEINIT",l);
309       }
310       if ((l->irqcount)) { 
311         printlock("BAD IRQ COUNT AT DEINIT",l);
312       }
313     }
314   } 
315   INFO("LOCKCHECK: DEINITED\n");
316 }
317
318
319 void palacios_lockcheck_alloc(void *lock)
320 {
321   lockcheck_state_t *l=get_lock_entry();
322
323   if (!l) { 
324     DEBUG("LOCKCHECK: UNABLE TO ALLOCATE TRACKING DATA FOR LOCK 0x%p\n",lock);
325   }
326   l->lock=lock;
327   backtrace(l->allocator);
328   l->lockcount=l->irqcount=0;
329   clear_trace(l->lastlocker);
330   clear_trace(l->lastunlocker);
331   clear_trace(l->lastirqlocker);
332   clear_trace(l->lastirqunlocker);
333   //INFO("LOCKCHECK: LOCK ALLOCATE 0x%p\n",lock);
334   printlock("NEW LOCK", l);
335  //dump_stack();
336 }
337   
338 void palacios_lockcheck_free(void *lock)
339 {
340   lockcheck_state_t *l=find_lock_entry(lock);
341   
342   if (!l){
343     DEBUG("LOCKCHECK: FREEING UNTRACKED LOCK 0x%p\n",lock);
344     return;
345   }
346
347   if ((l->lockcount)) { 
348     printlock("BAD LOCK COUNT AT FREE",l);
349   }
350
351   if ((l->irqcount)) { 
352     printlock("BAD IRQ COUNT AT FREE",l);
353   }
354   free_lock_entry(l);
355 }
356
357 void palacios_lockcheck_lock(void *lock)
358 {
359   lockcheck_state_t *l=find_lock_entry(lock);
360   
361   if (!l) { 
362     DEBUG("LOCKCHECK: LOCKING UNTRACKED LOCK 0x%p\n",lock);
363     return;
364   }
365   
366   if (l->lockcount!=0) { 
367     printlock("BAD LOCKCOUNT AT LOCK",l);
368   }
369   if (l->irqcount!=0) { 
370     printlock("BAD IRQCOUNT AT LOCK",l);
371   }
372   
373   l->lockcount++;
374   backtrace(l->lastlocker);
375
376   find_multiple_locks_held();
377
378   lock_stack_lock(lock,0);
379
380 }
381 void palacios_lockcheck_unlock(void *lock)
382 {
383   lockcheck_state_t *l=find_lock_entry(lock);
384   
385   if (!l) { 
386     DEBUG("LOCKCHECK: UNLOCKING UNTRACKED LOCK 0x%p\n",lock);
387     return;
388   }
389   
390   if (l->lockcount!=1) { 
391     printlock("LOCKCHECK: BAD LOCKCOUNT AT UNLOCK",l);
392   }
393   if (l->irqcount!=0) { 
394     printlock("LOCKCHECK: BAD IRQCOUNT AT UNLOCK",l);
395   }
396
397   lock_stack_unlock(lock,0);
398   
399   l->lockcount--;
400   backtrace(l->lastunlocker);
401
402 }
403
404 void palacios_lockcheck_lock_irqsave(void *lock,unsigned long flags)
405 {
406   lockcheck_state_t *l=find_lock_entry(lock);
407   
408   if (!l) { 
409     DEBUG("LOCKCHECK: IRQ LOCKING UNTRACKED LOCK 0x%p\n",lock);
410     return;
411   }
412   
413   if (l->lockcount!=0) { 
414     printlock("BAD LOCKCOUNT AT IRQ LOCK",l);
415   }
416   if (l->irqcount!=0) { 
417     printlock("BAD IRQCOUNT AT IRQ LOCK",l);
418   }
419   
420   l->irqcount++;
421   l->lastlockflags=flags;
422   backtrace(l->lastirqlocker);
423
424
425   find_multiple_irqs_held();
426
427   lock_stack_lock(lock,1);
428
429
430 }
431
432 void palacios_lockcheck_unlock_irqrestore(void *lock,unsigned long flags)
433 {
434   lockcheck_state_t *l=find_lock_entry(lock);
435   
436   if (!l) { 
437     DEBUG("LOCKCHECK: IRQ UNLOCKING UNTRACKED LOCK 0x%p\n",lock);
438     return;
439   }
440   
441   if (l->lockcount!=0) { 
442     printlock("LOCKCHECK: BAD LOCKCOUNT AT IRQ UNLOCK",l);
443   }
444   if (l->irqcount!=1) { 
445     printlock("LOCKCHECK: BAD IRQCOUNT AT IRQ UNLOCK",l);
446   }
447   
448   l->irqcount--;
449   l->lastunlockflags = flags;
450
451   lock_stack_unlock(lock,1);
452
453   backtrace(l->lastirqunlocker);
454   
455 }