diff options
Diffstat (limited to 'mm/memory.c')
| -rw-r--r-- | mm/memory.c | 106 | 
1 files changed, 69 insertions, 37 deletions
| diff --git a/mm/memory.c b/mm/memory.c index 098f00d05461..52c218e2b724 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -789,6 +789,46 @@ out:  	return pfn_to_page(pfn);  } +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long addr, +				pmd_t pmd) +{ +	unsigned long pfn = pmd_pfn(pmd); + +	/* +	 * There is no pmd_special() but there may be special pmds, e.g. +	 * in a direct-access (dax) mapping, so let's just replicate the +	 * !HAVE_PTE_SPECIAL case from vm_normal_page() here. +	 */ +	if (unlikely(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP))) { +		if (vma->vm_flags & VM_MIXEDMAP) { +			if (!pfn_valid(pfn)) +				return NULL; +			goto out; +		} else { +			unsigned long off; +			off = (addr - vma->vm_start) >> PAGE_SHIFT; +			if (pfn == vma->vm_pgoff + off) +				return NULL; +			if (!is_cow_mapping(vma->vm_flags)) +				return NULL; +		} +	} + +	if (is_zero_pfn(pfn)) +		return NULL; +	if (unlikely(pfn > highest_memmap_pfn)) +		return NULL; + +	/* +	 * NOTE! We still have PageReserved() pages in the page tables. +	 * eg. VDSO mappings can cause them to exist. +	 */ +out: +	return pfn_to_page(pfn); +} +#endif +  /*   * copy one vm_area from one task to the other. Assumes the page tables   * already present in the new task to be cleared in the whole range @@ -1182,15 +1222,8 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb,  		next = pmd_addr_end(addr, end);  		if (pmd_trans_huge(*pmd) || pmd_devmap(*pmd)) {  			if (next - addr != HPAGE_PMD_SIZE) { -#ifdef CONFIG_DEBUG_VM -				if (!rwsem_is_locked(&tlb->mm->mmap_sem)) { -					pr_err("%s: mmap_sem is unlocked! addr=0x%lx end=0x%lx vma->vm_start=0x%lx vma->vm_end=0x%lx\n", -						__func__, addr, end, -						vma->vm_start, -						vma->vm_end); -					BUG(); -				} -#endif +				VM_BUG_ON_VMA(vma_is_anonymous(vma) && +				    !rwsem_is_locked(&tlb->mm->mmap_sem), vma);  				split_huge_pmd(vma, pmd, addr);  			} else if (zap_huge_pmd(tlb, vma, pmd, addr))  				goto next; @@ -2054,7 +2087,7 @@ static inline int wp_page_reuse(struct mm_struct *mm,  		VM_BUG_ON_PAGE(PageAnon(page), page);  		mapping = page->mapping;  		unlock_page(page); -		page_cache_release(page); +		put_page(page);  		if ((dirtied || page_mkwrite) && mapping) {  			/* @@ -2188,7 +2221,7 @@ static int wp_page_copy(struct mm_struct *mm, struct vm_area_struct *vma,  	}  	if (new_page) -		page_cache_release(new_page); +		put_page(new_page);  	pte_unmap_unlock(page_table, ptl);  	mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end); @@ -2203,14 +2236,14 @@ static int wp_page_copy(struct mm_struct *mm, struct vm_area_struct *vma,  				munlock_vma_page(old_page);  			unlock_page(old_page);  		} -		page_cache_release(old_page); +		put_page(old_page);  	}  	return page_copied ? VM_FAULT_WRITE : 0;  oom_free_new: -	page_cache_release(new_page); +	put_page(new_page);  oom:  	if (old_page) -		page_cache_release(old_page); +		put_page(old_page);  	return VM_FAULT_OOM;  } @@ -2258,7 +2291,7 @@ static int wp_page_shared(struct mm_struct *mm, struct vm_area_struct *vma,  {  	int page_mkwrite = 0; -	page_cache_get(old_page); +	get_page(old_page);  	if (vma->vm_ops && vma->vm_ops->page_mkwrite) {  		int tmp; @@ -2267,7 +2300,7 @@ static int wp_page_shared(struct mm_struct *mm, struct vm_area_struct *vma,  		tmp = do_page_mkwrite(vma, old_page, address);  		if (unlikely(!tmp || (tmp &  				      (VM_FAULT_ERROR | VM_FAULT_NOPAGE)))) { -			page_cache_release(old_page); +			put_page(old_page);  			return tmp;  		}  		/* @@ -2281,7 +2314,7 @@ static int wp_page_shared(struct mm_struct *mm, struct vm_area_struct *vma,  		if (!pte_same(*page_table, orig_pte)) {  			unlock_page(old_page);  			pte_unmap_unlock(page_table, ptl); -			page_cache_release(old_page); +			put_page(old_page);  			return 0;  		}  		page_mkwrite = 1; @@ -2341,7 +2374,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,  	 */  	if (PageAnon(old_page) && !PageKsm(old_page)) {  		if (!trylock_page(old_page)) { -			page_cache_get(old_page); +			get_page(old_page);  			pte_unmap_unlock(page_table, ptl);  			lock_page(old_page);  			page_table = pte_offset_map_lock(mm, pmd, address, @@ -2349,10 +2382,10 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,  			if (!pte_same(*page_table, orig_pte)) {  				unlock_page(old_page);  				pte_unmap_unlock(page_table, ptl); -				page_cache_release(old_page); +				put_page(old_page);  				return 0;  			} -			page_cache_release(old_page); +			put_page(old_page);  		}  		if (reuse_swap_page(old_page)) {  			/* @@ -2375,7 +2408,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,  	/*  	 * Ok, we need to copy. Oh, well..  	 */ -	page_cache_get(old_page); +	get_page(old_page);  	pte_unmap_unlock(page_table, ptl);  	return wp_page_copy(mm, vma, address, page_table, pmd, @@ -2400,7 +2433,6 @@ static inline void unmap_mapping_range_tree(struct rb_root *root,  		vba = vma->vm_pgoff;  		vea = vba + vma_pages(vma) - 1; -		/* Assume for now that PAGE_CACHE_SHIFT == PAGE_SHIFT */  		zba = details->first_index;  		if (zba < vba)  			zba = vba; @@ -2619,7 +2651,7 @@ static int do_swap_page(struct mm_struct *mm, struct vm_area_struct *vma,  		 * parallel locked swapcache.  		 */  		unlock_page(swapcache); -		page_cache_release(swapcache); +		put_page(swapcache);  	}  	if (flags & FAULT_FLAG_WRITE) { @@ -2641,10 +2673,10 @@ out_nomap:  out_page:  	unlock_page(page);  out_release: -	page_cache_release(page); +	put_page(page);  	if (page != swapcache) {  		unlock_page(swapcache); -		page_cache_release(swapcache); +		put_page(swapcache);  	}  	return ret;  } @@ -2752,7 +2784,7 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,  	if (userfaultfd_missing(vma)) {  		pte_unmap_unlock(page_table, ptl);  		mem_cgroup_cancel_charge(page, memcg, false); -		page_cache_release(page); +		put_page(page);  		return handle_userfault(vma, address, flags,  					VM_UFFD_MISSING);  	} @@ -2771,10 +2803,10 @@ unlock:  	return 0;  release:  	mem_cgroup_cancel_charge(page, memcg, false); -	page_cache_release(page); +	put_page(page);  	goto unlock;  oom_free_page: -	page_cache_release(page); +	put_page(page);  oom:  	return VM_FAULT_OOM;  } @@ -2807,7 +2839,7 @@ static int __do_fault(struct vm_area_struct *vma, unsigned long address,  	if (unlikely(PageHWPoison(vmf.page))) {  		if (ret & VM_FAULT_LOCKED)  			unlock_page(vmf.page); -		page_cache_release(vmf.page); +		put_page(vmf.page);  		return VM_FAULT_HWPOISON;  	} @@ -2996,7 +3028,7 @@ static int do_read_fault(struct mm_struct *mm, struct vm_area_struct *vma,  	if (unlikely(!pte_same(*pte, orig_pte))) {  		pte_unmap_unlock(pte, ptl);  		unlock_page(fault_page); -		page_cache_release(fault_page); +		put_page(fault_page);  		return ret;  	}  	do_set_pte(vma, address, fault_page, pte, false, false); @@ -3024,7 +3056,7 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,  		return VM_FAULT_OOM;  	if (mem_cgroup_try_charge(new_page, mm, GFP_KERNEL, &memcg, false)) { -		page_cache_release(new_page); +		put_page(new_page);  		return VM_FAULT_OOM;  	} @@ -3041,7 +3073,7 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,  		pte_unmap_unlock(pte, ptl);  		if (fault_page) {  			unlock_page(fault_page); -			page_cache_release(fault_page); +			put_page(fault_page);  		} else {  			/*  			 * The fault handler has no page to lock, so it holds @@ -3057,7 +3089,7 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,  	pte_unmap_unlock(pte, ptl);  	if (fault_page) {  		unlock_page(fault_page); -		page_cache_release(fault_page); +		put_page(fault_page);  	} else {  		/*  		 * The fault handler has no page to lock, so it holds @@ -3068,7 +3100,7 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,  	return ret;  uncharge_out:  	mem_cgroup_cancel_charge(new_page, memcg, false); -	page_cache_release(new_page); +	put_page(new_page);  	return ret;  } @@ -3096,7 +3128,7 @@ static int do_shared_fault(struct mm_struct *mm, struct vm_area_struct *vma,  		tmp = do_page_mkwrite(vma, fault_page, address);  		if (unlikely(!tmp ||  				(tmp & (VM_FAULT_ERROR | VM_FAULT_NOPAGE)))) { -			page_cache_release(fault_page); +			put_page(fault_page);  			return tmp;  		}  	} @@ -3105,7 +3137,7 @@ static int do_shared_fault(struct mm_struct *mm, struct vm_area_struct *vma,  	if (unlikely(!pte_same(*pte, orig_pte))) {  		pte_unmap_unlock(pte, ptl);  		unlock_page(fault_page); -		page_cache_release(fault_page); +		put_page(fault_page);  		return ret;  	}  	do_set_pte(vma, address, fault_page, pte, true, false); @@ -3736,7 +3768,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,  						    buf, maddr + offset, bytes);  			}  			kunmap(page); -			page_cache_release(page); +			put_page(page);  		}  		len -= bytes;  		buf += bytes; | 
