Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] s390: pfault interrupt race

There is a race in pfault_interrupt. That function gets called two times for
each pfault notification. Once with a subcode of 0 to indicate that a real
page is not available and once with a subcode of 0x80 to indicate that the
page is present again.

Since the two external interrupts can be delivered on two different cpus the
order in which the two calls are made is unpredictable. It is possible that
the subcode 0x80 interrupt is completed before the subcode 0x00 interrupt has
done the wake_up() call.

To avoid calling wake_up() on an already removed task structure proper task
structure reference counting is needed. Increase the reference counter in the
subcode 0x00 interrupt before setting pfault_wait to zero and return the
reference after the wake_up call.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Martin Schwidefsky and committed by
Linus Torvalds
b6d09449 4c24da79

+4 -1
+4 -1
arch/s390/mm/fault.c
··· 563 563 * interrupt. pfault_wait is valid. Set pfault_wait 564 564 * back to zero and wake up the process. This can 565 565 * safely be done because the task is still sleeping 566 - * and can't procude new pfaults. */ 566 + * and can't produce new pfaults. */ 567 567 tsk->thread.pfault_wait = 0; 568 568 wake_up_process(tsk); 569 + put_task_struct(tsk); 569 570 } 570 571 } else { 571 572 /* signal bit not set -> a real page is missing. */ 573 + get_task_struct(tsk); 572 574 set_task_state(tsk, TASK_UNINTERRUPTIBLE); 573 575 if (xchg(&tsk->thread.pfault_wait, 1) != 0) { 574 576 /* Completion interrupt was faster than the initial ··· 580 578 * mode and can't produce new pfaults. */ 581 579 tsk->thread.pfault_wait = 0; 582 580 set_task_state(tsk, TASK_RUNNING); 581 + put_task_struct(tsk); 583 582 } else 584 583 set_tsk_need_resched(tsk); 585 584 }