aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/mm/fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/mm/fault.c')
-rw-r--r--arch/s390/mm/fault.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index b9aeaca26d3a..67e2d4d14ae6 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -574,6 +574,7 @@ static void pfault_interrupt(struct ext_code ext_code,
574 tsk->thread.pfault_wait = 0; 574 tsk->thread.pfault_wait = 0;
575 list_del(&tsk->thread.list); 575 list_del(&tsk->thread.list);
576 wake_up_process(tsk); 576 wake_up_process(tsk);
577 put_task_struct(tsk);
577 } else { 578 } else {
578 /* Completion interrupt was faster than initial 579 /* Completion interrupt was faster than initial
579 * interrupt. Set pfault_wait to -1 so the initial 580 * interrupt. Set pfault_wait to -1 so the initial
@@ -588,14 +589,22 @@ static void pfault_interrupt(struct ext_code ext_code,
588 put_task_struct(tsk); 589 put_task_struct(tsk);
589 } else { 590 } else {
590 /* signal bit not set -> a real page is missing. */ 591 /* signal bit not set -> a real page is missing. */
591 if (tsk->thread.pfault_wait == -1) { 592 if (tsk->thread.pfault_wait == 1) {
593 /* Already on the list with a reference: put to sleep */
594 set_task_state(tsk, TASK_UNINTERRUPTIBLE);
595 set_tsk_need_resched(tsk);
596 } else if (tsk->thread.pfault_wait == -1) {
592 /* Completion interrupt was faster than the initial 597 /* Completion interrupt was faster than the initial
593 * interrupt (pfault_wait == -1). Set pfault_wait 598 * interrupt (pfault_wait == -1). Set pfault_wait
594 * back to zero and exit. */ 599 * back to zero and exit. */
595 tsk->thread.pfault_wait = 0; 600 tsk->thread.pfault_wait = 0;
596 } else { 601 } else {
597 /* Initial interrupt arrived before completion 602 /* Initial interrupt arrived before completion
598 * interrupt. Let the task sleep. */ 603 * interrupt. Let the task sleep.
604 * An extra task reference is needed since a different
605 * cpu may set the task state to TASK_RUNNING again
606 * before the scheduler is reached. */
607 get_task_struct(tsk);
599 tsk->thread.pfault_wait = 1; 608 tsk->thread.pfault_wait = 1;
600 list_add(&tsk->thread.list, &pfault_list); 609 list_add(&tsk->thread.list, &pfault_list);
601 set_task_state(tsk, TASK_UNINTERRUPTIBLE); 610 set_task_state(tsk, TASK_UNINTERRUPTIBLE);
@@ -620,6 +629,7 @@ static int __cpuinit pfault_cpu_notify(struct notifier_block *self,
620 list_del(&thread->list); 629 list_del(&thread->list);
621 tsk = container_of(thread, struct task_struct, thread); 630 tsk = container_of(thread, struct task_struct, thread);
622 wake_up_process(tsk); 631 wake_up_process(tsk);
632 put_task_struct(tsk);
623 } 633 }
624 spin_unlock_irq(&pfault_lock); 634 spin_unlock_irq(&pfault_lock);
625 break; 635 break;