]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
mm: call invalidate_range_end in do_wp_page even for zero pages
authorHaggai Eran <haggaie@mellanox.com>
Fri, 28 Sep 2012 00:19:57 +0000 (10:19 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 9 Oct 2012 03:12:39 +0000 (14:12 +1100)
The previous patch "mm: wrap calls to set_pte_at_notify with
invalidate_range_start and invalidate_range_end" only called the
invalidate_range_end mmu notifier function in do_wp_page when the new_page
variable wasn't NULL.  This was done in order to only call
invalidate_range_end after invalidate_range_start was called.
Unfortunately, there are situations where new_page is NULL and
invalidate_range_start is called.  This caused invalidate_range_start to
be called without a matching invalidate_range_end, causing kvm to loop
indefinitely on the first page fault.

This patch adds a flag variable to do_wp_page that marks whether the
invalidate_range_start notifier was called.  invalidate_range_end is then
called if the flag is true.

Reported-by: Jiri Slaby <jslaby@suse.cz>
Signed-off-by: Haggai Eran <haggaie@mellanox.com>
Cc: Andrea Arcangeli <andrea@qumranet.com>
Cc: Sagi Grimberg <sagig@mellanox.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Xiao Guangrong <xiaoguangrong@linux.vnet.ibm.com>
Cc: Or Gerlitz <ogerlitz@mellanox.com>
Cc: Haggai Eran <haggaie@mellanox.com>
Cc: Shachar Raindel <raindel@mellanox.com>
Cc: Liran Liss <liranl@mellanox.com>
Cc: Christoph Lameter <cl@linux-foundation.org>
Cc: Avi Kivity <avi@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/memory.c

index 7d5238884dff5793ad58a254bfb6f722d68744cb..05204312c7e5170f0d6b9562d55906a289232a6c 100644 (file)
@@ -2534,6 +2534,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
        struct page *dirty_page = NULL;
        unsigned long mmun_start;       /* For mmu_notifiers */
        unsigned long mmun_end;         /* For mmu_notifiers */
+       bool mmun_called = false;       /* For mmu_notifiers */
 
        old_page = vm_normal_page(vma, address, orig_pte);
        if (!old_page) {
@@ -2711,8 +2712,9 @@ gotten:
        if (mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))
                goto oom_free_new;
 
-       mmun_start = address & PAGE_MASK;
-       mmun_end   = (address & PAGE_MASK) + PAGE_SIZE;
+       mmun_start  = address & PAGE_MASK;
+       mmun_end    = (address & PAGE_MASK) + PAGE_SIZE;
+       mmun_called = true;
        mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
 
        /*
@@ -2781,8 +2783,7 @@ gotten:
                page_cache_release(new_page);
 unlock:
        pte_unmap_unlock(page_table, ptl);
-       if (new_page)
-               /* Only call the end notifier if the begin was called. */
+       if (mmun_called)
                mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
        if (old_page) {
                /*