diff options
Diffstat (limited to 'arch/x86/lib/usercopy.c')
| -rw-r--r-- | arch/x86/lib/usercopy.c | 43 | 
1 files changed, 15 insertions, 28 deletions
diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c index 4f74d94c8d9..ddf9ecb53cc 100644 --- a/arch/x86/lib/usercopy.c +++ b/arch/x86/lib/usercopy.c @@ -11,39 +11,26 @@  #include <linux/sched.h>  /* - * best effort, GUP based copy_from_user() that is NMI-safe + * We rely on the nested NMI work to allow atomic faults from the NMI path; the + * nested NMI paths are careful to preserve CR2.   */  unsigned long  copy_from_user_nmi(void *to, const void __user *from, unsigned long n)  { -	unsigned long offset, addr = (unsigned long)from; -	unsigned long size, len = 0; -	struct page *page; -	void *map; -	int ret; +	unsigned long ret;  	if (__range_not_ok(from, n, TASK_SIZE)) -		return len; - -	do { -		ret = __get_user_pages_fast(addr, 1, 0, &page); -		if (!ret) -			break; - -		offset = addr & (PAGE_SIZE - 1); -		size = min(PAGE_SIZE - offset, n - len); - -		map = kmap_atomic(page); -		memcpy(to, map+offset, size); -		kunmap_atomic(map); -		put_page(page); - -		len  += size; -		to   += size; -		addr += size; - -	} while (len < n); - -	return len; +		return 0; + +	/* +	 * Even though this function is typically called from NMI/IRQ context +	 * disable pagefaults so that its behaviour is consistent even when +	 * called form other contexts. +	 */ +	pagefault_disable(); +	ret = __copy_from_user_inatomic(to, from, n); +	pagefault_enable(); + +	return ret;  }  EXPORT_SYMBOL_GPL(copy_from_user_nmi);  | 
