| From f313e12308f7c5ea645f18e759d104d088b18615 Mon Sep 17 00:00:00 2001 |
| From: Andi Kleen <andi@firstfloor.org> |
| Date: Fri, 9 Jan 2009 12:17:43 -0800 |
| Subject: x86: avoid theoretical vmalloc fault loop |
| |
| From: Andi Kleen <andi@firstfloor.org> |
| |
| commit f313e12308f7c5ea645f18e759d104d088b18615 upstream. |
| |
| Ajith Kumar noticed: |
| |
| I was going through the vmalloc fault handling for x86_64 and am unclear |
| about the following lines in the vmalloc_fault() function. |
| |
| pgd = pgd_offset(current->mm ?: &init_mm, address); |
| pgd_ref = pgd_offset_k(address); |
| |
| Here the intention is to get the pgd corresponding to the current process |
| and sync it up with the pgd in init_mm(obtained from pgd_offset_k). |
| However, for kernel threads current->mm is NULL and hence pgd = |
| pgd_offset(init_mm, address) = pgd_ref which means the fault handler |
| returns without setting the pgd entry in the MM structure in the context |
| of which the kernel thread has faulted. This could lead to never-ending |
| faults and busy looping of kernel threads like pdflush. So, shouldn't the |
| pgd = pgd_offset(current->mm ?: &init_mm, address); be pgd = |
| pgd_offset(current->active_mm ?: &init_mm, address); |
| |
| We can use active_mm unconditionally because it should be always set. |
| |
| Signed-off-by: Andi Kleen <ak@linux.intel.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Ingo Molnar <mingo@elte.hu> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| arch/x86/mm/fault.c | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| --- a/arch/x86/mm/fault.c |
| +++ b/arch/x86/mm/fault.c |
| @@ -534,7 +534,7 @@ static int vmalloc_fault(unsigned long a |
| happen within a race in page table update. In the later |
| case just flush. */ |
| |
| - pgd = pgd_offset(current->mm ?: &init_mm, address); |
| + pgd = pgd_offset(current->active_mm, address); |
| pgd_ref = pgd_offset_k(address); |
| if (pgd_none(*pgd_ref)) |
| return -1; |