aboutsummaryrefslogtreecommitdiffstats
path: root/mm/memory.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/memory.c')
-rw-r--r--mm/memory.c39
1 files changed, 23 insertions, 16 deletions
diff --git a/mm/memory.c b/mm/memory.c
index ca920d1fd314..54f3a9b00956 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -235,6 +235,9 @@ void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long
235 235
236static void tlb_flush_mmu_tlbonly(struct mmu_gather *tlb) 236static void tlb_flush_mmu_tlbonly(struct mmu_gather *tlb)
237{ 237{
238 if (!tlb->end)
239 return;
240
238 tlb_flush(tlb); 241 tlb_flush(tlb);
239 mmu_notifier_invalidate_range(tlb->mm, tlb->start, tlb->end); 242 mmu_notifier_invalidate_range(tlb->mm, tlb->start, tlb->end);
240#ifdef CONFIG_HAVE_RCU_TABLE_FREE 243#ifdef CONFIG_HAVE_RCU_TABLE_FREE
@@ -247,7 +250,7 @@ static void tlb_flush_mmu_free(struct mmu_gather *tlb)
247{ 250{
248 struct mmu_gather_batch *batch; 251 struct mmu_gather_batch *batch;
249 252
250 for (batch = &tlb->local; batch; batch = batch->next) { 253 for (batch = &tlb->local; batch && batch->nr; batch = batch->next) {
251 free_pages_and_swap_cache(batch->pages, batch->nr); 254 free_pages_and_swap_cache(batch->pages, batch->nr);
252 batch->nr = 0; 255 batch->nr = 0;
253 } 256 }
@@ -256,9 +259,6 @@ static void tlb_flush_mmu_free(struct mmu_gather *tlb)
256 259
257void tlb_flush_mmu(struct mmu_gather *tlb) 260void tlb_flush_mmu(struct mmu_gather *tlb)
258{ 261{
259 if (!tlb->end)
260 return;
261
262 tlb_flush_mmu_tlbonly(tlb); 262 tlb_flush_mmu_tlbonly(tlb);
263 tlb_flush_mmu_free(tlb); 263 tlb_flush_mmu_free(tlb);
264} 264}
@@ -2137,17 +2137,24 @@ reuse:
2137 if (!dirty_page) 2137 if (!dirty_page)
2138 return ret; 2138 return ret;
2139 2139
2140 /*
2141 * Yes, Virginia, this is actually required to prevent a race
2142 * with clear_page_dirty_for_io() from clearing the page dirty
2143 * bit after it clear all dirty ptes, but before a racing
2144 * do_wp_page installs a dirty pte.
2145 *
2146 * do_shared_fault is protected similarly.
2147 */
2148 if (!page_mkwrite) { 2140 if (!page_mkwrite) {
2149 wait_on_page_locked(dirty_page); 2141 struct address_space *mapping;
2150 set_page_dirty_balance(dirty_page); 2142 int dirtied;
2143
2144 lock_page(dirty_page);
2145 dirtied = set_page_dirty(dirty_page);
2146 VM_BUG_ON_PAGE(PageAnon(dirty_page), dirty_page);
2147 mapping = dirty_page->mapping;
2148 unlock_page(dirty_page);
2149
2150 if (dirtied && mapping) {
2151 /*
2152 * Some device drivers do not set page.mapping
2153 * but still dirty their pages
2154 */
2155 balance_dirty_pages_ratelimited(mapping);
2156 }
2157
2151 /* file_update_time outside page_lock */ 2158 /* file_update_time outside page_lock */
2152 if (vma->vm_file) 2159 if (vma->vm_file)
2153 file_update_time(vma->vm_file); 2160 file_update_time(vma->vm_file);
@@ -2593,7 +2600,7 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo
2593 if (prev && prev->vm_end == address) 2600 if (prev && prev->vm_end == address)
2594 return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM; 2601 return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM;
2595 2602
2596 expand_downwards(vma, address - PAGE_SIZE); 2603 return expand_downwards(vma, address - PAGE_SIZE);
2597 } 2604 }
2598 if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) { 2605 if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) {
2599 struct vm_area_struct *next = vma->vm_next; 2606 struct vm_area_struct *next = vma->vm_next;
@@ -2602,7 +2609,7 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo
2602 if (next && next->vm_start == address + PAGE_SIZE) 2609 if (next && next->vm_start == address + PAGE_SIZE)
2603 return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM; 2610 return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM;
2604 2611
2605 expand_upwards(vma, address + PAGE_SIZE); 2612 return expand_upwards(vma, address + PAGE_SIZE);
2606 } 2613 }
2607 return 0; 2614 return 0;
2608} 2615}