diff options
author | Jack Steiner <steiner@sgi.com> | 2009-12-15 19:48:18 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-16 10:20:17 -0500 |
commit | 2ce4d4c937ce4c14704f02ae60e2e07e3906c68a (patch) | |
tree | bf6b6f32910e8550bd30dd338172a46e35d6d81e /drivers/misc | |
parent | 74ccd09526a0254c362adcc6c862354d724aa803 (diff) |
gru: fix GRU interrupt race at deallocate
Fix a race where an interrupt could be received for a GRU context that has
been deallocated.
Signed-off-by: Jack Steiner <steiner@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/sgi-gru/grufault.c | 24 | ||||
-rw-r--r-- | drivers/misc/sgi-gru/gruprocfs.c | 1 | ||||
-rw-r--r-- | drivers/misc/sgi-gru/grutables.h | 1 |
3 files changed, 19 insertions, 7 deletions
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c index 929d6073e600..6ff6dfb7516d 100644 --- a/drivers/misc/sgi-gru/grufault.c +++ b/drivers/misc/sgi-gru/grufault.c | |||
@@ -360,7 +360,8 @@ static void gru_preload_tlb(struct gru_state *gru, | |||
360 | * < 0 = error code | 360 | * < 0 = error code |
361 | * | 361 | * |
362 | */ | 362 | */ |
363 | static int gru_try_dropin(struct gru_thread_state *gts, | 363 | static int gru_try_dropin(struct gru_state *gru, |
364 | struct gru_thread_state *gts, | ||
364 | struct gru_tlb_fault_handle *tfh, | 365 | struct gru_tlb_fault_handle *tfh, |
365 | struct gru_instruction_bits *cbk) | 366 | struct gru_instruction_bits *cbk) |
366 | { | 367 | { |
@@ -432,7 +433,7 @@ static int gru_try_dropin(struct gru_thread_state *gts, | |||
432 | } | 433 | } |
433 | 434 | ||
434 | if (unlikely(cbe) && pageshift == PAGE_SHIFT) { | 435 | if (unlikely(cbe) && pageshift == PAGE_SHIFT) { |
435 | gru_preload_tlb(gts->ts_gru, gts, atomic, vaddr, asid, write, tlb_preload_count, tfh, cbe); | 436 | gru_preload_tlb(gru, gts, atomic, vaddr, asid, write, tlb_preload_count, tfh, cbe); |
436 | gru_flush_cache_cbe(cbe); | 437 | gru_flush_cache_cbe(cbe); |
437 | } | 438 | } |
438 | 439 | ||
@@ -442,7 +443,7 @@ static int gru_try_dropin(struct gru_thread_state *gts, | |||
442 | gru_dbg(grudev, | 443 | gru_dbg(grudev, |
443 | "%s: gid %d, gts 0x%p, tfh 0x%p, vaddr 0x%lx, asid 0x%x, indexway 0x%x," | 444 | "%s: gid %d, gts 0x%p, tfh 0x%p, vaddr 0x%lx, asid 0x%x, indexway 0x%x," |
444 | " rw %d, ps %d, gpa 0x%lx\n", | 445 | " rw %d, ps %d, gpa 0x%lx\n", |
445 | atomic ? "atomic" : "non-atomic", gts->ts_gru->gs_gid, gts, tfh, vaddr, asid, | 446 | atomic ? "atomic" : "non-atomic", gru->gs_gid, gts, tfh, vaddr, asid, |
446 | indexway, write, pageshift, gpa); | 447 | indexway, write, pageshift, gpa); |
447 | STAT(tlb_dropin); | 448 | STAT(tlb_dropin); |
448 | return 0; | 449 | return 0; |
@@ -528,6 +529,7 @@ static irqreturn_t gru_intr(int chiplet, int blade) | |||
528 | struct gru_tlb_fault_map imap, dmap; | 529 | struct gru_tlb_fault_map imap, dmap; |
529 | struct gru_thread_state *gts; | 530 | struct gru_thread_state *gts; |
530 | struct gru_tlb_fault_handle *tfh = NULL; | 531 | struct gru_tlb_fault_handle *tfh = NULL; |
532 | struct completion *cmp; | ||
531 | int cbrnum, ctxnum; | 533 | int cbrnum, ctxnum; |
532 | 534 | ||
533 | STAT(intr); | 535 | STAT(intr); |
@@ -547,9 +549,11 @@ static irqreturn_t gru_intr(int chiplet, int blade) | |||
547 | 549 | ||
548 | for_each_cbr_in_tfm(cbrnum, dmap.fault_bits) { | 550 | for_each_cbr_in_tfm(cbrnum, dmap.fault_bits) { |
549 | STAT(intr_cbr); | 551 | STAT(intr_cbr); |
550 | complete(gru->gs_blade->bs_async_wq); | 552 | cmp = gru->gs_blade->bs_async_wq; |
553 | if (cmp) | ||
554 | complete(cmp); | ||
551 | gru_dbg(grudev, "gid %d, cbr_done %d, done %d\n", | 555 | gru_dbg(grudev, "gid %d, cbr_done %d, done %d\n", |
552 | gru->gs_gid, cbrnum, gru->gs_blade->bs_async_wq->done); | 556 | gru->gs_gid, cbrnum, cmp ? cmp->done : -1); |
553 | } | 557 | } |
554 | 558 | ||
555 | for_each_cbr_in_tfm(cbrnum, imap.fault_bits) { | 559 | for_each_cbr_in_tfm(cbrnum, imap.fault_bits) { |
@@ -566,6 +570,12 @@ static irqreturn_t gru_intr(int chiplet, int blade) | |||
566 | ctxnum = tfh->ctxnum; | 570 | ctxnum = tfh->ctxnum; |
567 | gts = gru->gs_gts[ctxnum]; | 571 | gts = gru->gs_gts[ctxnum]; |
568 | 572 | ||
573 | /* Spurious interrupts can cause this. Ignore. */ | ||
574 | if (!gts) { | ||
575 | STAT(intr_spurious); | ||
576 | continue; | ||
577 | } | ||
578 | |||
569 | /* | 579 | /* |
570 | * This is running in interrupt context. Trylock the mmap_sem. | 580 | * This is running in interrupt context. Trylock the mmap_sem. |
571 | * If it fails, retry the fault in user context. | 581 | * If it fails, retry the fault in user context. |
@@ -573,7 +583,7 @@ static irqreturn_t gru_intr(int chiplet, int blade) | |||
573 | if (!gts->ts_force_cch_reload && | 583 | if (!gts->ts_force_cch_reload && |
574 | down_read_trylock(>s->ts_mm->mmap_sem)) { | 584 | down_read_trylock(>s->ts_mm->mmap_sem)) { |
575 | gts->ustats.fmm_tlbdropin++; | 585 | gts->ustats.fmm_tlbdropin++; |
576 | gru_try_dropin(gts, tfh, NULL); | 586 | gru_try_dropin(gru, gts, tfh, NULL); |
577 | up_read(>s->ts_mm->mmap_sem); | 587 | up_read(>s->ts_mm->mmap_sem); |
578 | } else { | 588 | } else { |
579 | tfh_user_polling_mode(tfh); | 589 | tfh_user_polling_mode(tfh); |
@@ -619,7 +629,7 @@ static int gru_user_dropin(struct gru_thread_state *gts, | |||
619 | wait_event(gms->ms_wait_queue, | 629 | wait_event(gms->ms_wait_queue, |
620 | atomic_read(&gms->ms_range_active) == 0); | 630 | atomic_read(&gms->ms_range_active) == 0); |
621 | prefetchw(tfh); /* Helps on hdw, required for emulator */ | 631 | prefetchw(tfh); /* Helps on hdw, required for emulator */ |
622 | ret = gru_try_dropin(gts, tfh, cb); | 632 | ret = gru_try_dropin(gts->ts_gru, gts, tfh, cb); |
623 | if (ret <= 0) | 633 | if (ret <= 0) |
624 | return ret; | 634 | return ret; |
625 | STAT(call_os_wait_queue); | 635 | STAT(call_os_wait_queue); |
diff --git a/drivers/misc/sgi-gru/gruprocfs.c b/drivers/misc/sgi-gru/gruprocfs.c index 54a5a1c35ad1..7768b87d995b 100644 --- a/drivers/misc/sgi-gru/gruprocfs.c +++ b/drivers/misc/sgi-gru/gruprocfs.c | |||
@@ -66,6 +66,7 @@ static int statistics_show(struct seq_file *s, void *p) | |||
66 | printstat(s, intr); | 66 | printstat(s, intr); |
67 | printstat(s, intr_cbr); | 67 | printstat(s, intr_cbr); |
68 | printstat(s, intr_tfh); | 68 | printstat(s, intr_tfh); |
69 | printstat(s, intr_spurious); | ||
69 | printstat(s, intr_mm_lock_failed); | 70 | printstat(s, intr_mm_lock_failed); |
70 | printstat(s, call_os); | 71 | printstat(s, call_os); |
71 | printstat(s, call_os_wait_queue); | 72 | printstat(s, call_os_wait_queue); |
diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h index adaf691d59f5..54c3bb171eef 100644 --- a/drivers/misc/sgi-gru/grutables.h +++ b/drivers/misc/sgi-gru/grutables.h | |||
@@ -192,6 +192,7 @@ struct gru_stats_s { | |||
192 | atomic_long_t intr; | 192 | atomic_long_t intr; |
193 | atomic_long_t intr_cbr; | 193 | atomic_long_t intr_cbr; |
194 | atomic_long_t intr_tfh; | 194 | atomic_long_t intr_tfh; |
195 | atomic_long_t intr_spurious; | ||
195 | atomic_long_t intr_mm_lock_failed; | 196 | atomic_long_t intr_mm_lock_failed; |
196 | atomic_long_t call_os; | 197 | atomic_long_t call_os; |
197 | atomic_long_t call_os_wait_queue; | 198 | atomic_long_t call_os_wait_queue; |