diff options
Diffstat (limited to 'mm/memory.c')
| -rw-r--r-- | mm/memory.c | 39 | 
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  static void tlb_flush_mmu_tlbonly(struct mmu_gather *tlb)  { +	if (!tlb->end) +		return; +  	tlb_flush(tlb);  	mmu_notifier_invalidate_range(tlb->mm, tlb->start, tlb->end);  #ifdef CONFIG_HAVE_RCU_TABLE_FREE @@ -247,7 +250,7 @@ static void tlb_flush_mmu_free(struct mmu_gather *tlb)  {  	struct mmu_gather_batch *batch; -	for (batch = &tlb->local; batch; batch = batch->next) { +	for (batch = &tlb->local; batch && batch->nr; batch = batch->next) {  		free_pages_and_swap_cache(batch->pages, batch->nr);  		batch->nr = 0;  	} @@ -256,9 +259,6 @@ static void tlb_flush_mmu_free(struct mmu_gather *tlb)  void tlb_flush_mmu(struct mmu_gather *tlb)  { -	if (!tlb->end) -		return; -  	tlb_flush_mmu_tlbonly(tlb);  	tlb_flush_mmu_free(tlb);  } @@ -2137,17 +2137,24 @@ reuse:  		if (!dirty_page)  			return ret; -		/* -		 * Yes, Virginia, this is actually required to prevent a race -		 * with clear_page_dirty_for_io() from clearing the page dirty -		 * bit after it clear all dirty ptes, but before a racing -		 * do_wp_page installs a dirty pte. -		 * -		 * do_shared_fault is protected similarly. -		 */  		if (!page_mkwrite) { -			wait_on_page_locked(dirty_page); -			set_page_dirty_balance(dirty_page); +			struct address_space *mapping; +			int dirtied; + +			lock_page(dirty_page); +			dirtied = set_page_dirty(dirty_page); +			VM_BUG_ON_PAGE(PageAnon(dirty_page), dirty_page); +			mapping = dirty_page->mapping; +			unlock_page(dirty_page); + +			if (dirtied && mapping) { +				/* +				 * Some device drivers do not set page.mapping +				 * but still dirty their pages +				 */ +				balance_dirty_pages_ratelimited(mapping); +			} +  			/* file_update_time outside page_lock */  			if (vma->vm_file)  				file_update_time(vma->vm_file); @@ -2593,7 +2600,7 @@ static inline int check_stack_guard_page(struct vm_area_struct *vma, unsigned lo  		if (prev && prev->vm_end == address)  			return prev->vm_flags & VM_GROWSDOWN ? 0 : -ENOMEM; -		expand_downwards(vma, address - PAGE_SIZE); +		return expand_downwards(vma, address - PAGE_SIZE);  	}  	if ((vma->vm_flags & VM_GROWSUP) && address + PAGE_SIZE == vma->vm_end) {  		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  		if (next && next->vm_start == address + PAGE_SIZE)  			return next->vm_flags & VM_GROWSUP ? 0 : -ENOMEM; -		expand_upwards(vma, address + PAGE_SIZE); +		return expand_upwards(vma, address + PAGE_SIZE);  	}  	return 0;  } | 
