x86, mem-hotplug: separate x86_64 vmalloc_sync_all() into separate functions
PATCH 1/2 x86, mem-hotplug: separate x86_64 vmalloc_sync_all() into separate functions
Ingo & Peter,
These two patches are critical fixes for memory-hotplug on servers with large hotpluggable memory areas.
The bug is that when memory hotplug-adding happens for a large enough area that a new PGD entry is needed for the direct mapping, the PGDs of other processes would not get updated. This leads to some CPUs oopsing when they have to access the unmapped areas, e.g. onlining CPUs on the new added node.
Pls. apply if possible. Thanks!
---
From 04d9fc860db40f15ad629f8b341ff84b83a00a8d Mon Sep 17 00:00:00 2001
From: Haicheng Li <[email protected]>
Date: Wed, 19 May 2010 17:42:14 +0800
Subject: [PATCH] x86, mem-hotplug: separate x86_64 vmalloc_sync_all() into separate functions
No behavior change here.
Move some of vmalloc_sync_all() code into a new function sync_global_pgds() that will be useful for memory hotplug.
--- arch/x86/include/asm/pgtable_64.h | 2 ++ arch/x86/mm/fault.c | 24 +----------------------- arch/x86/mm/init_64.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 23 deletions(-)
arch/x86/include/asm/pgtable_64.h +2 -0
@@ -102,6 +102,8 @@ static inline void native_pgd_clear(pgd_t *pgd)native_set_pgd (pgd,native_make_pgd (0 )); } +extern void sync_global_pgds (unsigned long start,unsigned long end); +/* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to.
arch/x86/mm/fault.c +1 -23
@@ -326,29 +326,7 @@ out:void vmalloc_sync_all (void ) { -unsigned long address; - -for (address =VMALLOC_START &PGDIR_MASK ; address <=VMALLOC_END ; - address +=PGDIR_SIZE ) { - -const pgd_t *pgd_ref =pgd_offset_k (address); -unsigned long flags; -struct page *page; - -if (pgd_none (*pgd_ref)) -continue ; - -spin_lock_irqsave (&pgd_lock, flags); -list_for_each_entry (page, &pgd_list, lru) { -pgd_t *pgd; - pgd = (pgd_t *)page_address (page) +pgd_index (address); -if (pgd_none (*pgd)) -set_pgd (pgd, *pgd_ref); -else -BUG_ON (pgd_page_vaddr (*pgd) !=pgd_page_vaddr (*pgd_ref)); - } -spin_unlock_irqrestore (&pgd_lock, flags); - } +sync_global_pgds (VMALLOC_START &PGDIR_MASK ,VMALLOC_END ); }/*
arch/x86/mm/init_64.c +30 -0
@@ -98,6 +98,36 @@ static int __init nonx32_setup(char *str)__setup ("noexec32=" , nonx32_setup);/* +* When memory was added/removed make sure all the processes MM have +* suitable PGD entries in the local PGD level page. +*/ +void sync_global_pgds (unsigned long start,unsigned long end) +{ +unsigned long address; + +for (address = start; address <= end; address +=PGDIR_SIZE ) { +const pgd_t *pgd_ref =pgd_offset_k (address); +unsigned long flags; +struct page *page; + +if (pgd_none (*pgd_ref)) +continue ; + +spin_lock_irqsave (&pgd_lock, flags); +list_for_each_entry (page, &pgd_list, lru) { +pgd_t *pgd; + pgd = (pgd_t *)page_address (page) +pgd_index (address); +if (pgd_none (*pgd)) +set_pgd (pgd, *pgd_ref); +else +BUG_ON (pgd_page_vaddr (*pgd) + !=pgd_page_vaddr (*pgd_ref)); + } +spin_unlock_irqrestore (&pgd_lock, flags); + } +} + +/* * NOTE: This function is marked __ref because it calls __init function * (alloc_bootmem_pages). It's safe to do it ONLY when after_bootmem == 0. */
Signature · 7 lines
1.5.6.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/