/* best effort, GUP based copy_from_user() that assumes IRQ or NMI context  */
static unsigned long copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
/* best effort, GUP based copy_from_user() that assumes IRQ or NMI context  */
static unsigned long copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
{
	unsigned long offset, addr = (unsigned long)from;
	int type = in_nmi() ? KM_NMI : KM_IRQ0;
	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, type);
		memcpy(to, map+offset, size);
		kunmap_atomic(map, type);
		put_page(page);
		len  += size;
		to   += size;
		addr += size;
	} while (len < n);
	return len;
}