Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=9a24d04a3c26c223f22493492c5c9085b8773d4a
Commit:     9a24d04a3c26c223f22493492c5c9085b8773d4a
Parent:     4fa4d23fa20de67df919030c1216295664866ad7
Author:     Ingo Molnar <[EMAIL PROTECTED]>
AuthorDate: Fri Oct 19 12:19:26 2007 +0200
Committer:  Thomas Gleixner <[EMAIL PROTECTED]>
CommitDate: Fri Oct 19 12:19:26 2007 +0200

    x86: fix global_flush_tlb() bug
    
    While we were reviewing pageattr_32/64.c for unification,
    Thomas Gleixner noticed the following serious SMP bug in
    global_flush_tlb():
    
        down_read(&init_mm.mmap_sem);
        list_replace_init(&deferred_pages, &l);
        up_read(&init_mm.mmap_sem);
    
    this is SMP-unsafe because list_replace_init() done on two CPUs in
    parallel can corrupt the list.
    
    This bug has been introduced about a year ago in the 64-bit tree:
    
           commit ea7322decb974a4a3e804f96a0201e893ff88ce3
           Author: Andi Kleen <[EMAIL PROTECTED]>
           Date:   Thu Dec 7 02:14:05 2006 +0100
    
           [PATCH] x86-64: Speed and clean up cache flushing in change_page_attr
    
                    down_read(&init_mm.mmap_sem);
            -       dpage = xchg(&deferred_pages, NULL);
            +       list_replace_init(&deferred_pages, &l);
                    up_read(&init_mm.mmap_sem);
    
    the xchg() based version was SMP-safe, but list_replace_init() is not.
    So this "cleanup" introduced a nasty bug.
    
    why this bug never become prominent is a mystery - it can probably be
    explained with the (still) relative obscurity of the x86_64 architecture.
    
    the safe fix for now is to write-lock init_mm.mmap_sem.
    
    Signed-off-by: Ingo Molnar <[EMAIL PROTECTED]>
    Signed-off-by: Thomas Gleixner <[EMAIL PROTECTED]>
---
 arch/x86/mm/pageattr_64.c |    9 +++++++--
 1 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/x86/mm/pageattr_64.c b/arch/x86/mm/pageattr_64.c
index 8a4f65b..c7b7dfe 100644
--- a/arch/x86/mm/pageattr_64.c
+++ b/arch/x86/mm/pageattr_64.c
@@ -230,9 +230,14 @@ void global_flush_tlb(void)
        struct page *pg, *next;
        struct list_head l;
 
-       down_read(&init_mm.mmap_sem);
+       /*
+        * Write-protect the semaphore, to exclude two contexts
+        * doing a list_replace_init() call in parallel and to
+        * exclude new additions to the deferred_pages list:
+        */
+       down_write(&init_mm.mmap_sem);
        list_replace_init(&deferred_pages, &l);
-       up_read(&init_mm.mmap_sem);
+       up_write(&init_mm.mmap_sem);
 
        flush_map(&l);
 
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to