static int __init test_size_treshold(void) { struct page *src_page, *dst_page; void *user_ptr, *kernel_ptr; unsigned long long t0, t1, t2; int size, ret; ret = -ENOMEM; src_page = alloc_page(GFP_KERNEL); if (!src_page) goto no_src; dst_page = alloc_page(GFP_KERNEL); if (!dst_page) goto no_dst; kernel_ptr = page_address(src_page); user_ptr = vmap(&dst_page, 1, VM_IOREMAP, __pgprot(__P010)); if (!user_ptr) goto no_vmap; /* warm up the src page dcache */ ret = __copy_to_user_memcpy(user_ptr, kernel_ptr, PAGE_SIZE); for (size = PAGE_SIZE; size >= 4; size /= 2) { t0 = sched_clock(); ret |= __copy_to_user_memcpy(user_ptr, kernel_ptr, size); t1 = sched_clock(); ret |= __copy_to_user_std(user_ptr, kernel_ptr, size); t2 = sched_clock(); printk("copy_to_user: %d %llu %llu\n", size, t1 - t0, t2 - t1); } for (size = PAGE_SIZE; size >= 4; size /= 2) { t0 = sched_clock(); ret |= __clear_user_memset(user_ptr, size); t1 = sched_clock(); ret |= __clear_user_std(user_ptr, size); t2 = sched_clock(); printk("clear_user: %d %llu %llu\n", size, t1 - t0, t2 - t1); } if (ret) ret = -EFAULT; vunmap(user_ptr); no_vmap: put_page(dst_page); no_dst: put_page(src_page); no_src: return ret; }
unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n) { /* * This test is stubbed out of the main function above to keep * the overhead for small copies low by avoiding a large * register dump on the stack just to reload them right away. * With frame pointer disabled, tail call optimization kicks in * as well making this test almost invisible. */ if (n < 64) return __copy_to_user_std(to, from, n); return __copy_to_user_memcpy(to, from, n); }
unsigned long arm_copy_to_user(void __user *to, const void *from, unsigned long n) { /* * This test is stubbed out of the main function above to keep * the overhead for small copies low by avoiding a large * register dump on the stack just to reload them right away. * With frame pointer disabled, tail call optimization kicks in * as well making this test almost invisible. */ if (n < COPY_TO_USER_THRESHOLD) { unsigned long ua_flags = uaccess_save_and_enable(); n = __copy_to_user_std(to, from, n); uaccess_restore(ua_flags); } else { n = __copy_to_user_memcpy(to, from, n); } return n; }