mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-31 00:17:44 +00:00
44 lines
815 B
C
44 lines
815 B
C
|
/*
|
||
|
* User address space access functions.
|
||
|
*
|
||
|
* For licencing details see kernel-base/COPYING
|
||
|
*/
|
||
|
|
||
|
#include <linux/highmem.h>
|
||
|
#include <linux/module.h>
|
||
|
|
||
|
/*
|
||
|
* best effort, GUP based copy_from_user() that is NMI-safe
|
||
|
*/
|
||
|
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;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(copy_from_user_nmi);
|