diff options
Diffstat (limited to 'mm/memory.c')
| -rw-r--r-- | mm/memory.c | 72 | 
1 files changed, 48 insertions, 24 deletions
diff --git a/mm/memory.c b/mm/memory.c index e11ca9dd823f..47fe250307c7 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -69,6 +69,7 @@  #include <linux/userfaultfd_k.h>  #include <linux/dax.h>  #include <linux/oom.h> +#include <linux/numa.h>  #include <asm/io.h>  #include <asm/mmu_context.h> @@ -1451,7 +1452,7 @@ static int insert_page(struct vm_area_struct *vma, unsigned long addr,  	spinlock_t *ptl;  	retval = -EINVAL; -	if (PageAnon(page)) +	if (PageAnon(page) || PageSlab(page) || page_has_type(page))  		goto out;  	retval = -ENOMEM;  	flush_dcache_page(page); @@ -1503,6 +1504,8 @@ out:   * under mm->mmap_sem write-lock, so it can change vma->vm_flags.   * Caller must set VM_MIXEDMAP on vma if it wants to call this   * function from other places, for example from page-fault handler. + * + * Return: %0 on success, negative error code otherwise.   */  int vm_insert_page(struct vm_area_struct *vma, unsigned long addr,  			struct page *page) @@ -1830,7 +1833,9 @@ static inline int remap_p4d_range(struct mm_struct *mm, pgd_t *pgd,   * @size: size of map area   * @prot: page protection flags for this mapping   * - *  Note: this is only safe if the mm semaphore is held when called. + * Note: this is only safe if the mm semaphore is held when called. + * + * Return: %0 on success, negative error code otherwise.   */  int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,  		    unsigned long pfn, unsigned long size, pgprot_t prot) @@ -1903,6 +1908,8 @@ EXPORT_SYMBOL(remap_pfn_range);   *   * NOTE! Some drivers might want to tweak vma->vm_page_prot first to get   * whatever write-combining details or similar. + * + * Return: %0 on success, negative error code otherwise.   */  int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len)  { @@ -2381,12 +2388,13 @@ oom:   *   * This function handles all that is needed to finish a write page fault in a   * shared mapping due to PTE being read-only once the mapped page is prepared. - * It handles locking of PTE and modifying it. The function returns - * VM_FAULT_WRITE on success, 0 when PTE got changed before we acquired PTE - * lock. + * It handles locking of PTE and modifying it.   *   * The function expects the page to be locked or other protection against   * concurrent faults / writeback (such as DAX radix tree locks). + * + * Return: %VM_FAULT_WRITE on success, %0 when PTE got changed before + * we acquired PTE lock.   */  vm_fault_t finish_mkwrite_fault(struct vm_fault *vmf)  { @@ -2504,8 +2512,11 @@ static vm_fault_t do_wp_page(struct vm_fault *vmf)  	 * Take out anonymous pages first, anonymous shared vmas are  	 * not dirty accountable.  	 */ -	if (PageAnon(vmf->page) && !PageKsm(vmf->page)) { +	if (PageAnon(vmf->page)) {  		int total_map_swapcount; +		if (PageKsm(vmf->page) && (PageSwapCache(vmf->page) || +					   page_count(vmf->page) != 1)) +			goto copy;  		if (!trylock_page(vmf->page)) {  			get_page(vmf->page);  			pte_unmap_unlock(vmf->pte, vmf->ptl); @@ -2520,6 +2531,15 @@ static vm_fault_t do_wp_page(struct vm_fault *vmf)  			}  			put_page(vmf->page);  		} +		if (PageKsm(vmf->page)) { +			bool reused = reuse_ksm_page(vmf->page, vmf->vma, +						     vmf->address); +			unlock_page(vmf->page); +			if (!reused) +				goto copy; +			wp_page_reuse(vmf); +			return VM_FAULT_WRITE; +		}  		if (reuse_swap_page(vmf->page, &total_map_swapcount)) {  			if (total_map_swapcount == 1) {  				/* @@ -2540,7 +2560,7 @@ static vm_fault_t do_wp_page(struct vm_fault *vmf)  					(VM_WRITE|VM_SHARED))) {  		return wp_page_shared(vmf);  	} - +copy:  	/*  	 * Ok, we need to copy. Oh, well..  	 */ @@ -3201,6 +3221,8 @@ static vm_fault_t do_set_pmd(struct vm_fault *vmf, struct page *page)   *   * Target users are page handler itself and implementations of   * vm_ops->map_pages. + * + * Return: %0 on success, %VM_FAULT_ code in case of error.   */  vm_fault_t alloc_set_pte(struct vm_fault *vmf, struct mem_cgroup *memcg,  		struct page *page) @@ -3261,11 +3283,12 @@ vm_fault_t alloc_set_pte(struct vm_fault *vmf, struct mem_cgroup *memcg,   * This function handles all that is needed to finish a page fault once the   * page to fault in is prepared. It handles locking of PTEs, inserts PTE for   * given page, adds reverse page mapping, handles memcg charges and LRU - * addition. The function returns 0 on success, VM_FAULT_ code in case of - * error. + * addition.   *   * The function expects the page to be locked and on success it consumes a   * reference of a page being mapped (for the PTE which maps it). + * + * Return: %0 on success, %VM_FAULT_ code in case of error.   */  vm_fault_t finish_fault(struct vm_fault *vmf)  { @@ -3321,12 +3344,8 @@ DEFINE_DEBUGFS_ATTRIBUTE(fault_around_bytes_fops,  static int __init fault_around_debugfs(void)  { -	void *ret; - -	ret = debugfs_create_file_unsafe("fault_around_bytes", 0644, NULL, NULL, -			&fault_around_bytes_fops); -	if (!ret) -		pr_warn("Failed to create fault_around_bytes in debugfs"); +	debugfs_create_file_unsafe("fault_around_bytes", 0644, NULL, NULL, +				   &fault_around_bytes_fops);  	return 0;  }  late_initcall(fault_around_debugfs); @@ -3517,10 +3536,13 @@ static vm_fault_t do_shared_fault(struct vm_fault *vmf)   * but allow concurrent faults).   * The mmap_sem may have been released depending on flags and our   * return value.  See filemap_fault() and __lock_page_or_retry(). + * If mmap_sem is released, vma may become invalid (for example + * by other thread calling munmap()).   */  static vm_fault_t do_fault(struct vm_fault *vmf)  {  	struct vm_area_struct *vma = vmf->vma; +	struct mm_struct *vm_mm = vma->vm_mm;  	vm_fault_t ret;  	/* @@ -3561,7 +3583,7 @@ static vm_fault_t do_fault(struct vm_fault *vmf)  	/* preallocated pagetable is unused: free it */  	if (vmf->prealloc_pte) { -		pte_free(vma->vm_mm, vmf->prealloc_pte); +		pte_free(vm_mm, vmf->prealloc_pte);  		vmf->prealloc_pte = NULL;  	}  	return ret; @@ -3586,11 +3608,11 @@ static vm_fault_t do_numa_page(struct vm_fault *vmf)  {  	struct vm_area_struct *vma = vmf->vma;  	struct page *page = NULL; -	int page_nid = -1; +	int page_nid = NUMA_NO_NODE;  	int last_cpupid;  	int target_nid;  	bool migrated = false; -	pte_t pte; +	pte_t pte, old_pte;  	bool was_writable = pte_savedwrite(vmf->orig_pte);  	int flags = 0; @@ -3610,12 +3632,12 @@ static vm_fault_t do_numa_page(struct vm_fault *vmf)  	 * Make it present again, Depending on how arch implementes non  	 * accessible ptes, some can allow access by kernel mode.  	 */ -	pte = ptep_modify_prot_start(vma->vm_mm, vmf->address, vmf->pte); -	pte = pte_modify(pte, vma->vm_page_prot); +	old_pte = ptep_modify_prot_start(vma, vmf->address, vmf->pte); +	pte = pte_modify(old_pte, vma->vm_page_prot);  	pte = pte_mkyoung(pte);  	if (was_writable)  		pte = pte_mkwrite(pte); -	ptep_modify_prot_commit(vma->vm_mm, vmf->address, vmf->pte, pte); +	ptep_modify_prot_commit(vma, vmf->address, vmf->pte, old_pte, pte);  	update_mmu_cache(vma, vmf->address, vmf->pte);  	page = vm_normal_page(vma, vmf->address, pte); @@ -3653,7 +3675,7 @@ static vm_fault_t do_numa_page(struct vm_fault *vmf)  	target_nid = numa_migrate_prep(page, vma, vmf->address, page_nid,  			&flags);  	pte_unmap_unlock(vmf->pte, vmf->ptl); -	if (target_nid == -1) { +	if (target_nid == NUMA_NO_NODE) {  		put_page(page);  		goto out;  	} @@ -3667,7 +3689,7 @@ static vm_fault_t do_numa_page(struct vm_fault *vmf)  		flags |= TNF_MIGRATE_FAIL;  out: -	if (page_nid != -1) +	if (page_nid != NUMA_NO_NODE)  		task_numa_fault(last_cpupid, page_nid, 1, flags);  	return 0;  } @@ -4150,7 +4172,7 @@ EXPORT_SYMBOL(follow_pte_pmd);   *   * Only IO mappings and raw PFN mappings are allowed.   * - * Returns zero and the pfn at @pfn on success, -ve otherwise. + * Return: zero and the pfn at @pfn on success, -ve otherwise.   */  int follow_pfn(struct vm_area_struct *vma, unsigned long address,  	unsigned long *pfn) @@ -4300,6 +4322,8 @@ int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,   * @gup_flags:	flags modifying lookup behaviour   *   * The caller must hold a reference on @mm. + * + * Return: number of bytes copied from source to destination.   */  int access_remote_vm(struct mm_struct *mm, unsigned long addr,  		void *buf, int len, unsigned int gup_flags)  |