diff options
| -rw-r--r-- | include/linux/hugetlb.h | 13 | ||||
| -rw-r--r-- | mm/memory.c | 14 | 
2 files changed, 25 insertions, 2 deletions
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index e670b0d13fe..42cb7d70f9a 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -155,11 +155,24 @@ static inline void set_file_hugepages(struct file *file)  {  	file->f_op = &hugetlbfs_file_operations;  } + +static inline int valid_hugetlb_file_off(struct vm_area_struct *vma,  +					  unsigned long address)  +{ +	struct inode *inode = vma->vm_file->f_dentry->d_inode; +	loff_t file_off = address - vma->vm_start; +	 +	file_off += (vma->vm_pgoff << PAGE_SHIFT); +	 +	return (file_off < inode->i_size); +} +  #else /* !CONFIG_HUGETLBFS */  #define is_file_hugepages(file)		0  #define set_file_hugepages(file)	BUG()  #define hugetlb_zero_setup(size)	ERR_PTR(-ENOSYS) +#define valid_hugetlb_file_off(vma, address) 	0  #endif /* !CONFIG_HUGETLBFS */ diff --git a/mm/memory.c b/mm/memory.c index ae8161f1f45..8c88b973abc 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2045,8 +2045,18 @@ int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct * vma,  	inc_page_state(pgfault); -	if (is_vm_hugetlb_page(vma)) -		return VM_FAULT_SIGBUS;	/* mapping truncation does this. */ +	if (unlikely(is_vm_hugetlb_page(vma))) { +		if (valid_hugetlb_file_off(vma, address)) +			/* We get here only if there was a stale(zero) TLB entry  +			 * (because of  HW prefetching).  +			 * Low-level arch code (if needed) should have already +			 * purged the stale entry as part of this fault handling.   +			 * Here we just return. +			 */ +			return VM_FAULT_MINOR;  +		else +			return VM_FAULT_SIGBUS;	/* mapping truncation does this. */ +	}  	/*  	 * We need the page table lock to synchronize with kswapd  |