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.


Lock checking enhancement to find frequently used (hot) locks
[palacios.git] / linux_module / lockcheck.c
1 #include <linux/kernel.h>
2 #include <linux/kthread.h>
3 #include <linux/spinlock.h>
4 #include <linux/sort.h>
5
6 #include "palacios.h"
7
8 #include "lockcheck.h"
9
10
11 // Number of outputs possible before output stops
12 // set to zero to remove the limit
13 #define OUTPUT_LIMIT      0
14 //
15 // Number of outputs to skip before
16 // printing and counting
17 #define OUTPUT_SKIP       0
18
19 //
20 // Whether or not to print these events
21 //
22 #define PRINT_LOCK_ALLOC  0
23 #define PRINT_LOCK_FREE   0
24 #define PRINT_LOCK_LOCK   0
25 #define PRINT_LOCK_UNLOCK 0
26
27 // How far up the stack to track the caller
28 // 0 => palacios_...
29 // 1 => v3_lock...
30 // 2 => caller of v3_lock..
31 // ... 
32 #define STEP_BACK_DEPTH_FIRST 1
33 #define STEP_BACK_DEPTH_LAST  4
34 #define STEP_BACK_DEPTH       (STEP_BACK_DEPTH_LAST-STEP_BACK_DEPTH_FIRST+1)
35
36 // show when multiple locks are held simultaneously
37 // This is the minimum number
38 #define WARN_MULTIPLE_THRESHOLD 3
39
40 // Detect when last lock a processor holds is released
41 // but interrupts remain off, similarly for first acquire
42 #define CHECK_IRQ_LAST_RELEASE   0
43 #define CHECK_IRQ_FIRST_ACQUIRE  1
44
45 // Show hottest locks every this many locks or lock_irqsaves
46 // 0 indicates this should not be shown
47 #define HOT_LOCK_INTERVAL        1000
48
49 //
50 // Whether lockcheck should lock its own data structures during an
51 // event (alloc, dealloc, lock, unlock, etc) and the subsequent
52 // checking.  If this is off, it will only lock on a lock allocation,
53 // in order to assure each lock has a distinct slot.  If this is off,
54 // lockcheck may miss problems (or see additional problems) due to
55 // internal race conditions.  However, if it is on, lockcheck is
56 // essentially adding a global lock acuire to each lock operation in
57 // palacios, which will perturb palacios.
58 //
59 #define LOCK_SELF 1
60
61
62 typedef struct {
63   int  inuse;         // nonzero if this is in use
64   void *lock;         // the lock
65   void *holder;       // current thread holding it
66   u32   holdingcpu;   // on which cpu it acquired it
67   void *allocator[STEP_BACK_DEPTH];
68                       // who allocated this
69   int   lockcount;    // how many times it's been locked/unlocked (lock=+1, unlock=-1)
70   int   irqcount;     // how many times interrupts have been turned off (+1/-1)
71   void *lastlocker[STEP_BACK_DEPTH];
72                       // who last locked
73   void *lastunlocker[STEP_BACK_DEPTH]; 
74                       // who last unlocked
75   void *lastirqlocker[STEP_BACK_DEPTH];
76                       // who last locked
77   unsigned long lastlockflags; // their flags
78   void *lastirqunlocker[STEP_BACK_DEPTH]
79                     ; // who last unlocked
80   unsigned long lastunlockflags; // their flags
81   int   hotlockcount; // how many times it's been locked
82 } lockcheck_state_t;
83
84
85 // This lock is currently used only to control
86 // allocation of entries in the global state
87 static spinlock_t mylock; 
88 static lockcheck_state_t state[NUM_LOCKS];
89 static lockcheck_state_t *sorted_state[NUM_LOCKS];
90
91 static int numout=0;
92
93 static int globallockcount=0;
94
95 #define DEBUG_OUTPUT(fmt, args...)                                      \
96 do {                                                                    \
97   numout++;                                                             \
98   if (numout>=OUTPUT_SKIP) {                                            \
99     if (OUTPUT_LIMIT==0 ||(numout-OUTPUT_SKIP)<OUTPUT_LIMIT) {          \
100       DEBUG(fmt, ##args);                                               \
101     } else {                                                            \
102       if ((numout-OUTPUT_SKIP)==OUTPUT_LIMIT) {                         \
103         DEBUG("LOCKCHECK: Output limit hit - no further printouts\n");  \
104       }                                                                 \
105     }                                                                   \
106   }                                                                     \
107 } while (0)
108
109 #define DEBUG_DUMPSTACK()                                               \
110 do {                                                                    \
111   if (numout>=OUTPUT_SKIP) {                                            \
112     if (OUTPUT_LIMIT==0 || (numout-OUTPUT_SKIP)<OUTPUT_LIMIT) {         \
113       dump_stack();                                                     \
114     }                                                                   \
115   }                                                                     \
116 } while (0)
117
118 #if LOCK_SELF
119 #define LOCK_DECL unsigned long f
120 #define LOCK() spin_lock_irqsave(&mylock,f)
121 #define UNLOCK() spin_unlock_irqrestore(&mylock,f)
122 #define LOCK_ALLOC_DECL 
123 #define LOCK_ALLOC()  
124 #define UNLOCK_ALLOC() 
125 #else
126 #define LOCK_DECL 
127 #define LOCK()  
128 #define UNLOCK() 
129 #define LOCK_ALLOC_DECL unsigned long f
130 #define LOCK_ALLOC() spin_lock_irqsave(&mylock,f)
131 #define UNLOCK_ALLOC() spin_unlock_irqrestore(&mylock,f)
132 #endif
133
134 static void printlock(char *prefix, lockcheck_state_t *l);
135
136
137 typedef struct {
138   u32 top;               // next open slot 0..
139   void *lock[LOCK_STACK_DEPTH]; // the stack
140   char irq[LOCK_STACK_DEPTH];   // locked with irqsave?
141   char irqoff[LOCK_STACK_DEPTH]; // if so, what was the flag?
142 } lock_stack_t;
143
144 static DEFINE_PER_CPU(lock_stack_t, lock_stack);
145
146 static lockcheck_state_t *get_lock_entry(void)
147 {
148   int i;
149   lockcheck_state_t *l;
150   LOCK_ALLOC_DECL;
151
152   LOCK_ALLOC();
153   for (i=0;i<NUM_LOCKS;i++) { 
154     l=&(state[i]);
155     if (!(l->inuse)) { 
156       l->inuse=1;
157       break;
158     }
159   }
160   UNLOCK_ALLOC();
161   
162   if (i<NUM_LOCKS) { 
163     return l;
164   } else {
165     return 0;
166   }
167 }
168
169
170 static lockcheck_state_t *find_lock_entry(void *lock)
171 {
172   int i;
173   lockcheck_state_t *l;
174
175   for (i=0;i<NUM_LOCKS;i++) { 
176     l=&(state[i]);
177     if (l->inuse && l->lock == lock) { 
178       return l;
179     }
180   }
181   return 0;
182 }
183
184
185 static void free_lock_entry(lockcheck_state_t *l)
186 {
187   l->inuse=0;
188 }
189
190
191 static void lock_stack_print(void)
192 {
193   u32 i;
194   char buf[64];
195   lock_stack_t *mystack = &(get_cpu_var(lock_stack));
196   u32 cpu = get_cpu();  put_cpu();
197   
198   if ((mystack->top)>0) { 
199     for (i=mystack->top; i>0;i--) {
200       snprintf(buf,64,"LOCK STACK (cpu=%u, index=%u, irq=%d, irqoff=%d)",cpu, i-1, (int)(mystack->irq[i-1]), (int)(mystack->irqoff[i-1]));
201       printlock(buf,find_lock_entry(mystack->lock[i-1]));
202     }
203   }
204   put_cpu_var(lock_stack);
205 }
206
207
208 static void lock_stack_lock(void *lock, char irq, unsigned long flags)
209 {
210   lock_stack_t *mystack = &(get_cpu_var(lock_stack));
211   u32 cpu = get_cpu();  put_cpu();
212
213   if (mystack->top>=(LOCK_STACK_DEPTH-1)) {
214     put_cpu_var(lock_stack);
215     DEBUG_OUTPUT("LOCKCHECK: Locking lock 0x%p on cpu %u exceeds stack limit of %d\n",lock,cpu,LOCK_STACK_DEPTH);
216     lock_stack_print();
217   } else {
218     int oldtop = mystack->top;
219     mystack->lock[mystack->top] = lock;
220     mystack->irq[mystack->top] = irq;
221     mystack->irqoff[mystack->top] = irqs_disabled_flags(flags);
222     mystack->top++;
223     put_cpu_var(lock_stack);
224     if (CHECK_IRQ_FIRST_ACQUIRE && oldtop==0 && irqs_disabled_flags(flags) ) { 
225        DEBUG_OUTPUT("LOCKCHECK: First lock on lock stack of processor %d but irqs were already disabled - stack trace follows\n", cpu);
226        DEBUG_DUMPSTACK();
227     }
228        
229   }
230   
231   
232 }
233
234 static void lock_stack_unlock(void *lock, char irq, unsigned long flags)
235 {
236   lock_stack_t *mystack = &(get_cpu_var(lock_stack));
237   u32 cpu = get_cpu(); put_cpu();
238
239   if (mystack->top==0) {
240     put_cpu_var(lock_stack);
241     DEBUG_OUTPUT("LOCKCHECK: Unlocking lock 0x%p on cpu %u when lock stack is empty\n",lock,cpu);
242   } else {
243     if (mystack->lock[mystack->top-1] != lock) { 
244       void *otherlock=mystack->lock[mystack->top-1];
245       put_cpu_var(lock_stack);
246       DEBUG_OUTPUT("LOCKCHECK: Unlocking lock 0x%p on cpu %u when top of stack is lock 0x%p\n",lock,cpu, otherlock);
247       lock_stack_print();
248     } else {
249       if (irq!=mystack->irq[mystack->top-1]) {
250         char otherirq = mystack->irq[mystack->top-1];
251         put_cpu_var(lock_stack);
252         DEBUG_OUTPUT("LOCKCHECK: Unlocking lock 0x%p on cpu %u with irq=%d, but was locked with irq=%d\n",lock,cpu,irq,otherirq);
253         lock_stack_print();
254         mystack = &(get_cpu_var(lock_stack));
255         mystack->top--;
256         put_cpu_var(lock_stack);
257       } else {
258         if (irq) { 
259           if (irqs_disabled_flags(flags)!=mystack->irqoff[mystack->top-1]) {
260              char otherirqoff = mystack->irqoff[mystack->top-1];
261              put_cpu_var(lock_stack);
262              DEBUG_OUTPUT("LOCKCHECK: Unlocking lock 0x%p on cpu %u sets irqoff=%d but the matching lock returned irqoff=%d\n", lock, cpu, irqs_disabled_flags(flags), otherirqoff);
263              lock_stack_print();
264              mystack = &(get_cpu_var(lock_stack));
265              mystack->top--;
266              put_cpu_var(lock_stack);
267           } else {
268             // irq, and irq states match - good
269             mystack->top--;
270             put_cpu_var(lock_stack);
271           }
272         } else {
273           // !irq - we are good
274           mystack->top--;
275           put_cpu_var(lock_stack);
276         }
277       }
278     }
279   }
280
281   mystack = &(get_cpu_var(lock_stack));
282   if (mystack->top == 0) {
283     put_cpu_var(lock_stack);
284     if (CHECK_IRQ_LAST_RELEASE && irqs_disabled()) { 
285        DEBUG_OUTPUT("LOCKCHECK: Lock stack on cpu %u is now empty, but irqs are still disabled! Stack trace follows\n", cpu);
286        DEBUG_DUMPSTACK();
287     }
288   } else {
289     put_cpu_var(lock_stack);
290   }
291
292 }
293
294
295 // pointers are to the pointers in the sorted_state array
296 int compare(const void *a, const void *b)
297 {
298   lockcheck_state_t *l = *((lockcheck_state_t **)a);
299   lockcheck_state_t *r = *((lockcheck_state_t **)b);
300
301   return -(l->hotlockcount - r->hotlockcount);
302 }
303
304 static void hot_lock_show(void)
305 {
306   int n, i;
307   char buf[64];
308
309   n=0;
310   for (i=0;i<NUM_LOCKS;i++) { 
311     if (state[i].inuse) { 
312       sorted_state[n]=&(state[i]);
313       n++;
314     }
315   }
316
317   sort(sorted_state,n,sizeof(lockcheck_state_t *),compare,NULL);
318   
319   for (i=0;i<n;i++) {
320     snprintf(buf,64,"HOT LOCK (%d of %d) %d acquires", i,n,sorted_state[i]->hotlockcount);
321     printlock(buf,sorted_state[i]);
322   }
323 }
324
325
326 static void hot_lock_lock(void *lock)
327
328   lockcheck_state_t *l = find_lock_entry(lock);
329    
330   if (!l) { return; }
331
332   l->hotlockcount++;
333   globallockcount++;
334
335   if (HOT_LOCK_INTERVAL && !(globallockcount % HOT_LOCK_INTERVAL )) {
336     DEBUG_OUTPUT("LOCKCHECK: Hot locks after %d acquires Follow\n",globallockcount);
337     hot_lock_show();
338   }
339 }
340
341
342 #define hot_lock_unlock(X) // nothing for now
343
344
345
346 void palacios_lockcheck_init()
347 {
348   memset(state,0,sizeof(lockcheck_state_t)*NUM_LOCKS);
349   spin_lock_init(&mylock);
350   DEBUG_OUTPUT("LOCKCHECK: LOCK CHECKING INITED (internal locking: %d, output limit: %d, output skip: %d)\n",LOCK_SELF,OUTPUT_LIMIT,OUTPUT_SKIP);
351 }
352
353 //
354 // This needs to be defined explictly since the intrinsic does not take a var
355 //
356 #define backtrace(t) \
357   t[0]=__builtin_return_address(STEP_BACK_DEPTH_FIRST); \
358   t[1]=__builtin_return_address(STEP_BACK_DEPTH_FIRST+1); \
359   t[2]=__builtin_return_address(STEP_BACK_DEPTH_FIRST+2); \
360   t[3]=__builtin_return_address(STEP_BACK_DEPTH_FIRST+3); 
361
362 //
363 // For printing a backtrace
364 //
365 //
366 #define backtrace_format "%pS << %pS << %pS << %pS"
367 #define backtrace_expand(t) ((t)[0]),((t)[1]),((t)[2]),((t)[3])
368
369
370 static void clear_trace(void **trace)
371 {
372   int i;
373
374   for (i=0;i<STEP_BACK_DEPTH;i++) { 
375     trace[i]=0;
376   }
377 }
378
379
380 static void printlock(char *prefix, lockcheck_state_t *l)
381 {
382   if (!l || !(l->lock) ) { 
383     DEBUG_OUTPUT("LOCKCHECK: %s: lock 0x%p BOGUS\n",prefix,l);
384     return;
385   }
386   if (l->lock) { 
387     DEBUG_OUTPUT("LOCKCHECK: %s: lock 0x%p, holder %s on %u, allocator=" 
388           backtrace_format
389           ", lockcount=%d, lastlocker="
390           backtrace_format
391           ", lastunlocker="
392           backtrace_format
393           ", irqcount=%d, lastirqlocker="
394           backtrace_format
395           ", lastlockflags=%lu, lastirqunlocker="
396           backtrace_format
397           ", lastunlockflags=%lu\n",
398           prefix,l->lock,
399           l->holder ? ((struct task_struct *)(l->holder))->comm : "none",
400           l->holdingcpu,
401           backtrace_expand(l->allocator),
402           l->lockcount,
403           backtrace_expand(l->lastlocker),
404           backtrace_expand(l->lastunlocker),
405           l->irqcount,
406           backtrace_expand(l->lastirqlocker),
407           l->lastlockflags,
408           backtrace_expand(l->lastirqunlocker),
409           l->lastunlockflags);
410   }
411 }
412
413
414
415 static void find_multiple_locks_held(void)
416 {
417   int i;
418   int have=0;
419   lockcheck_state_t *l;
420   char buf[64];
421
422   for (i=0;i<NUM_LOCKS;i++) { 
423     l=&(state[i]);
424     if (l->inuse && l->lockcount>0) { 
425       have++;
426       if (have>=WARN_MULTIPLE_THRESHOLD) { 
427         break;
428       }
429     }
430   }
431   
432   if (have>=WARN_MULTIPLE_THRESHOLD) { 
433     have=0;
434     for (i=0;i<NUM_LOCKS;i++) { 
435       l=&(state[i]);
436       if (l->inuse && l->lockcount>0) {
437         snprintf(buf,64,"MULTIPLE LOCKS HELD (%d)",have);
438         printlock(buf,l);
439         have++;
440       }
441     }
442   }
443     
444 }
445
446 static void find_multiple_irqs_held(void)
447 {
448   int i;
449   int have=0;
450   lockcheck_state_t *l;
451   char buf[64];
452
453   for (i=0;i<NUM_LOCKS;i++) { 
454     l=&(state[i]);
455     if (l->inuse && l->irqcount>0) {
456       have++;
457       if (have>=WARN_MULTIPLE_THRESHOLD) { 
458         break;
459       }
460     }
461   }
462   
463   if (have>=WARN_MULTIPLE_THRESHOLD) { 
464     have=0;
465     for (i=0;i<NUM_LOCKS;i++) { 
466       l=&(state[i]);
467       if (l->inuse && l->irqcount>0) { 
468         snprintf(buf,64,"MULTIPLE IRQS HELD (%d)",have);
469         printlock(buf,l);
470         have++;
471       }
472     }
473   }
474
475 }
476
477
478 void palacios_lockcheck_deinit()
479 {
480   int i;
481   lockcheck_state_t *l;
482   LOCK_DECL;
483   
484   LOCK();
485
486   for (i=0;i<NUM_LOCKS;i++) { 
487     l=&(state[i]);
488     if (l->lock) { 
489       printlock("ALLOCATED LOCK AT DEINIT",l);
490       if ((l->lockcount)) { 
491         printlock("BAD LOCK COUNT AT DEINIT",l);
492       }
493       if ((l->irqcount)) { 
494         printlock("BAD IRQ COUNT AT DEINIT",l);
495       }
496     }
497   } 
498   UNLOCK();
499   INFO("LOCKCHECK: DEINITED\n");
500 }
501
502
503 void palacios_lockcheck_alloc(void *lock)
504 {
505   lockcheck_state_t *l;
506   LOCK_DECL;
507
508   LOCK();
509
510   l=get_lock_entry();
511   
512   if (!l) { 
513     DEBUG_OUTPUT("LOCKCHECK: UNABLE TO ALLOCATE TRACKING DATA FOR LOCK 0x%p\n",lock);
514   }
515   l->lock=lock;
516   backtrace(l->allocator);
517   l->lockcount=l->irqcount=0;
518   clear_trace(l->lastlocker);
519   clear_trace(l->lastunlocker);
520   clear_trace(l->lastirqlocker);
521   clear_trace(l->lastirqunlocker);
522   //INFO("LOCKCHECK: LOCK ALLOCATE 0x%p\n",lock);
523 #if PRINT_LOCK_ALLOC
524   printlock("NEW LOCK", l);
525 #endif
526   
527   UNLOCK();
528 }
529   
530 void palacios_lockcheck_free(void *lock)
531 {
532   lockcheck_state_t *l;
533   LOCK_DECL;
534
535   LOCK();
536   l=find_lock_entry(lock);
537   
538   if (!l){
539     UNLOCK();
540     DEBUG_OUTPUT("LOCKCHECK: FREEING UNTRACKED LOCK 0x%p - stack trace follows\n",lock);
541     DEBUG_DUMPSTACK();
542     return;
543   }
544
545   if ((l->lockcount)) { 
546     printlock("BAD LOCK COUNT AT FREE",l);
547   }
548
549   if ((l->irqcount)) { 
550     printlock("BAD IRQ COUNT AT FREE",l);
551   }
552
553 #if PRINT_LOCK_FREE
554   printlock("FREE LOCK",l);
555 #endif
556
557   free_lock_entry(l);
558
559   UNLOCK();
560
561 }
562
563 void palacios_lockcheck_lock(void *lock)
564 {
565   LOCK_DECL;
566   lockcheck_state_t *l;
567
568
569   LOCK();
570
571   l=find_lock_entry(lock); 
572  
573   if (!l) { 
574     UNLOCK();
575     DEBUG_OUTPUT("LOCKCHECK: LOCKING UNTRACKED LOCK 0x%p - stack follows\n",lock);
576     DEBUG_DUMPSTACK();
577     return;
578   }
579   
580   if (l->lockcount!=0) { 
581     printlock("BAD LOCKCOUNT AT LOCK - stack follows",l);
582     DEBUG_DUMPSTACK();
583   }
584   if (l->irqcount!=0) { 
585     printlock("BAD IRQCOUNT AT LOCK - stack follows",l);
586     DEBUG_DUMPSTACK();
587   }
588   
589   l->lockcount++;
590   l->holder=current;
591   l->holdingcpu=get_cpu(); put_cpu();
592   backtrace(l->lastlocker);
593
594   find_multiple_locks_held();
595
596   lock_stack_lock(lock,0,0);
597
598   hot_lock_lock(lock);
599
600 #if PRINT_LOCK_LOCK
601   printlock("LOCK",l);
602 #endif
603
604   UNLOCK();
605
606 }
607 void palacios_lockcheck_unlock(void *lock)
608 {
609   LOCK_DECL;
610   lockcheck_state_t *l;
611
612   LOCK();
613
614   l=find_lock_entry(lock);
615   
616   if (!l) { 
617     UNLOCK();
618     DEBUG_OUTPUT("LOCKCHECK: UNLOCKING UNTRACKED LOCK 0x%p - stack follows\n",lock);
619     DEBUG_DUMPSTACK();
620     return;
621   }
622   
623   if (l->lockcount!=1) { 
624     printlock("LOCKCHECK: BAD LOCKCOUNT AT UNLOCK - stack follows",l);
625     DEBUG_DUMPSTACK();
626   }
627   if (l->irqcount!=0) { 
628     printlock("LOCKCHECK: BAD IRQCOUNT AT UNLOCK - stack follows",l);
629     DEBUG_DUMPSTACK();
630   }
631
632   lock_stack_unlock(lock,0,0);
633
634   hot_lock_unlock(lock);
635   
636   l->holder=0;
637   l->holdingcpu=0;
638   l->lockcount--;
639   backtrace(l->lastunlocker);
640
641 #if PRINT_LOCK_UNLOCK
642   printlock("UNLOCK",l);
643 #endif
644
645   UNLOCK();
646
647 }
648
649 void palacios_lockcheck_lock_irqsave(void *lock,unsigned long flags)
650 {
651   LOCK_DECL;
652   lockcheck_state_t *l;
653   
654   LOCK();
655
656   l=find_lock_entry(lock);
657
658   if (!l) { 
659     UNLOCK();
660     DEBUG_OUTPUT("LOCKCHECK: IRQ LOCKING UNTRACKED LOCK 0x%p - stack follows\n",lock);
661     DEBUG_DUMPSTACK();
662     return;
663   }
664   
665   if (l->lockcount!=0) { 
666     printlock("BAD LOCKCOUNT AT IRQ LOCK - stack follows",l);
667     DEBUG_DUMPSTACK();
668   }
669   if (l->irqcount!=0) { 
670     printlock("BAD IRQCOUNT AT IRQ LOCK - stack follows",l);
671     DEBUG_DUMPSTACK();
672   }
673   
674   l->irqcount++;
675   l->holder=current;
676   l->holdingcpu=get_cpu(); put_cpu();
677   l->lastlockflags=flags;
678   backtrace(l->lastirqlocker);
679
680   find_multiple_irqs_held();
681
682   lock_stack_lock(lock,1,flags);
683
684   hot_lock_lock(lock);
685
686 #if PRINT_LOCK_LOCK
687   printlock("LOCK_IRQSAVE",l);
688 #endif
689
690   UNLOCK();
691
692
693 }
694
695
696 //
697 // This is separated into two components to avoid a race between
698 // the underlying spin_unlock_irqrestore and the next lockcheck_lock_irqsave
699 // If simply record the state after the unlock, we might see that the 
700 // irqcount has already increased.  Therefore, we will acquire the 
701 // lockchecker lock in _pre and release it in _post.  Note that when
702 // we release the lock in _post, we restore the flags provided by the 
703 // code under test - NOT our original flags
704 //
705 // unlock_pre() - stores flags, takes mylock discard flags
706 // At this point, a lockcheck_lock cannot enter, since it's stuck on mylock
707 // spinunlock - restores lock, restores original flags
708 // unlock_post() - restores mylock WITH orig flags
709 //
710 void palacios_lockcheck_unlock_irqrestore_pre(void *lock,unsigned long flags)
711 {
712   LOCK_DECL;
713   
714   LOCK();  // flags are discarded
715   // at this point, the actual spin unlock can run 
716   // if another thread hits lockcheck_irqsave at this point, it
717   // will block on mylock
718 }
719
720 void palacios_lockcheck_unlock_irqrestore_post(void *lock,unsigned long flags)
721 {
722   LOCK_DECL;
723   lockcheck_state_t *l;
724
725 #if LOCK_SELF
726   // when we unlock, want to restore the flags *the user wants*
727   f = flags;
728 #endif
729
730   // Note that we DO NOT take mylock here, since we already took it in
731   // _pre
732
733   l=find_lock_entry(lock);
734
735   if (!l) { 
736     UNLOCK();  // release any waiting threads on lockcheck_lock_irqsave
737     DEBUG_OUTPUT("LOCKCHECK: IRQ UNLOCKING UNTRACKED LOCK 0x%p - stack follows\n",lock);
738     DEBUG_DUMPSTACK();
739     return;
740   }
741   
742   if (l->lockcount!=0) { 
743     printlock("LOCKCHECK: BAD LOCKCOUNT AT IRQ UNLOCK - stack follows",l);
744     DEBUG_DUMPSTACK();
745   }
746   if (l->irqcount!=1) { 
747     printlock("LOCKCHECK: BAD IRQCOUNT AT IRQ UNLOCK - stack follows",l);
748     DEBUG_DUMPSTACK();
749   }
750   
751   l->holder=0;
752   l->holdingcpu=0;
753   l->irqcount--;
754   l->lastunlockflags = flags;
755
756   lock_stack_unlock(lock,1,flags);
757
758   hot_lock_unlock(lock);
759
760   backtrace(l->lastirqunlocker);
761
762 #if PRINT_LOCK_UNLOCK
763   printlock("UNLOCK_IRQRESTORE",l);
764 #endif
765   UNLOCK(); // release any waiting threads on lockcheck_lock_irqsave
766
767 }