diff options
Diffstat (limited to 'mm/memory.c')
| -rw-r--r-- | mm/memory.c | 46 | 
1 files changed, 41 insertions, 5 deletions
diff --git a/mm/memory.c b/mm/memory.c index 45442d9a4f52..0bccc622e482 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1664,6 +1664,9 @@ out_unlock:   * vmf_insert_pfn_prot should only be used if using multiple VMAs is   * impractical.   * + * See vmf_insert_mixed_prot() for a discussion of the implication of using + * a value of @pgprot different from that of @vma->vm_page_prot. + *   * Context: Process context.  May allocate using %GFP_KERNEL.   * Return: vm_fault_t value.   */ @@ -1737,9 +1740,9 @@ static bool vm_mixed_ok(struct vm_area_struct *vma, pfn_t pfn)  }  static vm_fault_t __vm_insert_mixed(struct vm_area_struct *vma, -		unsigned long addr, pfn_t pfn, bool mkwrite) +		unsigned long addr, pfn_t pfn, pgprot_t pgprot, +		bool mkwrite)  { -	pgprot_t pgprot = vma->vm_page_prot;  	int err;  	BUG_ON(!vm_mixed_ok(vma, pfn)); @@ -1782,10 +1785,43 @@ static vm_fault_t __vm_insert_mixed(struct vm_area_struct *vma,  	return VM_FAULT_NOPAGE;  } +/** + * vmf_insert_mixed_prot - insert single pfn into user vma with specified pgprot + * @vma: user vma to map to + * @addr: target user address of this page + * @pfn: source kernel pfn + * @pgprot: pgprot flags for the inserted page + * + * This is exactly like vmf_insert_mixed(), except that it allows drivers to + * to override pgprot on a per-page basis. + * + * Typically this function should be used by drivers to set caching- and + * encryption bits different than those of @vma->vm_page_prot, because + * the caching- or encryption mode may not be known at mmap() time. + * This is ok as long as @vma->vm_page_prot is not used by the core vm + * to set caching and encryption bits for those vmas (except for COW pages). + * This is ensured by core vm only modifying these page table entries using + * functions that don't touch caching- or encryption bits, using pte_modify() + * if needed. (See for example mprotect()). + * Also when new page-table entries are created, this is only done using the + * fault() callback, and never using the value of vma->vm_page_prot, + * except for page-table entries that point to anonymous pages as the result + * of COW. + * + * Context: Process context.  May allocate using %GFP_KERNEL. + * Return: vm_fault_t value. + */ +vm_fault_t vmf_insert_mixed_prot(struct vm_area_struct *vma, unsigned long addr, +				 pfn_t pfn, pgprot_t pgprot) +{ +	return __vm_insert_mixed(vma, addr, pfn, pgprot, false); +} +EXPORT_SYMBOL(vmf_insert_mixed_prot); +  vm_fault_t vmf_insert_mixed(struct vm_area_struct *vma, unsigned long addr,  		pfn_t pfn)  { -	return __vm_insert_mixed(vma, addr, pfn, false); +	return __vm_insert_mixed(vma, addr, pfn, vma->vm_page_prot, false);  }  EXPORT_SYMBOL(vmf_insert_mixed); @@ -1797,7 +1833,7 @@ EXPORT_SYMBOL(vmf_insert_mixed);  vm_fault_t vmf_insert_mixed_mkwrite(struct vm_area_struct *vma,  		unsigned long addr, pfn_t pfn)  { -	return __vm_insert_mixed(vma, addr, pfn, true); +	return __vm_insert_mixed(vma, addr, pfn, vma->vm_page_prot, true);  }  EXPORT_SYMBOL(vmf_insert_mixed_mkwrite); @@ -2203,7 +2239,7 @@ static inline int pte_unmap_same(struct mm_struct *mm, pmd_t *pmd,  				pte_t *page_table, pte_t orig_pte)  {  	int same = 1; -#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPTION)  	if (sizeof(pte_t) > sizeof(unsigned long)) {  		spinlock_t *ptl = pte_lockptr(mm, pmd);  		spin_lock(ptl);  |