[PATCH] lockdep: fix delayacct locking bug

Make the delayacct lock irqsave; this avoids the possible deadlock where
an interrupt is taken while holding the delayacct lock which needs to
take the delayacct lock.

Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Acked-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Balbir Singh <balbir@in.ibm.com>
Cc: Shailabh Nagar <nagar@watson.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by Peter Zijlstra and committed by Linus Torvalds 64efade1 e5b9a335

+9 -6
+9 -6
kernel/delayacct.c
··· 66 { 67 struct timespec ts; 68 s64 ns; 69 70 do_posix_clock_monotonic_gettime(end); 71 ts = timespec_sub(*end, *start); ··· 74 if (ns < 0) 75 return; 76 77 - spin_lock(&current->delays->lock); 78 *total += ns; 79 (*count)++; 80 - spin_unlock(&current->delays->lock); 81 } 82 83 void __delayacct_blkio_start(void) ··· 105 s64 tmp; 106 struct timespec ts; 107 unsigned long t1,t2,t3; 108 109 /* Though tsk->delays accessed later, early exit avoids 110 * unnecessary returning of other data ··· 138 139 /* zero XXX_total, non-zero XXX_count implies XXX stat overflowed */ 140 141 - spin_lock(&tsk->delays->lock); 142 tmp = d->blkio_delay_total + tsk->delays->blkio_delay; 143 d->blkio_delay_total = (tmp < d->blkio_delay_total) ? 0 : tmp; 144 tmp = d->swapin_delay_total + tsk->delays->swapin_delay; 145 d->swapin_delay_total = (tmp < d->swapin_delay_total) ? 0 : tmp; 146 d->blkio_count += tsk->delays->blkio_count; 147 d->swapin_count += tsk->delays->swapin_count; 148 - spin_unlock(&tsk->delays->lock); 149 150 done: 151 return 0; ··· 154 __u64 __delayacct_blkio_ticks(struct task_struct *tsk) 155 { 156 __u64 ret; 157 158 - spin_lock(&tsk->delays->lock); 159 ret = nsec_to_clock_t(tsk->delays->blkio_delay + 160 tsk->delays->swapin_delay); 161 - spin_unlock(&tsk->delays->lock); 162 return ret; 163 } 164
··· 66 { 67 struct timespec ts; 68 s64 ns; 69 + unsigned long flags; 70 71 do_posix_clock_monotonic_gettime(end); 72 ts = timespec_sub(*end, *start); ··· 73 if (ns < 0) 74 return; 75 76 + spin_lock_irqsave(&current->delays->lock, flags); 77 *total += ns; 78 (*count)++; 79 + spin_unlock_irqrestore(&current->delays->lock, flags); 80 } 81 82 void __delayacct_blkio_start(void) ··· 104 s64 tmp; 105 struct timespec ts; 106 unsigned long t1,t2,t3; 107 + unsigned long flags; 108 109 /* Though tsk->delays accessed later, early exit avoids 110 * unnecessary returning of other data ··· 136 137 /* zero XXX_total, non-zero XXX_count implies XXX stat overflowed */ 138 139 + spin_lock_irqsave(&tsk->delays->lock, flags); 140 tmp = d->blkio_delay_total + tsk->delays->blkio_delay; 141 d->blkio_delay_total = (tmp < d->blkio_delay_total) ? 0 : tmp; 142 tmp = d->swapin_delay_total + tsk->delays->swapin_delay; 143 d->swapin_delay_total = (tmp < d->swapin_delay_total) ? 0 : tmp; 144 d->blkio_count += tsk->delays->blkio_count; 145 d->swapin_count += tsk->delays->swapin_count; 146 + spin_unlock_irqrestore(&tsk->delays->lock, flags); 147 148 done: 149 return 0; ··· 152 __u64 __delayacct_blkio_ticks(struct task_struct *tsk) 153 { 154 __u64 ret; 155 + unsigned long flags; 156 157 + spin_lock_irqsave(&tsk->delays->lock, flags); 158 ret = nsec_to_clock_t(tsk->delays->blkio_delay + 159 tsk->delays->swapin_delay); 160 + spin_unlock_irqrestore(&tsk->delays->lock, flags); 161 return ret; 162 } 163