162306a36Sopenharmony_ci#include <linux/kernel.h> 262306a36Sopenharmony_ci#include <linux/mm.h> 362306a36Sopenharmony_ci#include <linux/slab.h> 462306a36Sopenharmony_ci#include <linux/uaccess.h> 562306a36Sopenharmony_ci#include <linux/ktime.h> 662306a36Sopenharmony_ci#include <linux/debugfs.h> 762306a36Sopenharmony_ci#include <linux/highmem.h> 862306a36Sopenharmony_ci#include "gup_test.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistatic void put_back_pages(unsigned int cmd, struct page **pages, 1162306a36Sopenharmony_ci unsigned long nr_pages, unsigned int gup_test_flags) 1262306a36Sopenharmony_ci{ 1362306a36Sopenharmony_ci unsigned long i; 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci switch (cmd) { 1662306a36Sopenharmony_ci case GUP_FAST_BENCHMARK: 1762306a36Sopenharmony_ci case GUP_BASIC_TEST: 1862306a36Sopenharmony_ci for (i = 0; i < nr_pages; i++) 1962306a36Sopenharmony_ci put_page(pages[i]); 2062306a36Sopenharmony_ci break; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci case PIN_FAST_BENCHMARK: 2362306a36Sopenharmony_ci case PIN_BASIC_TEST: 2462306a36Sopenharmony_ci case PIN_LONGTERM_BENCHMARK: 2562306a36Sopenharmony_ci unpin_user_pages(pages, nr_pages); 2662306a36Sopenharmony_ci break; 2762306a36Sopenharmony_ci case DUMP_USER_PAGES_TEST: 2862306a36Sopenharmony_ci if (gup_test_flags & GUP_TEST_FLAG_DUMP_PAGES_USE_PIN) { 2962306a36Sopenharmony_ci unpin_user_pages(pages, nr_pages); 3062306a36Sopenharmony_ci } else { 3162306a36Sopenharmony_ci for (i = 0; i < nr_pages; i++) 3262306a36Sopenharmony_ci put_page(pages[i]); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci } 3562306a36Sopenharmony_ci break; 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic void verify_dma_pinned(unsigned int cmd, struct page **pages, 4062306a36Sopenharmony_ci unsigned long nr_pages) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci unsigned long i; 4362306a36Sopenharmony_ci struct folio *folio; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci switch (cmd) { 4662306a36Sopenharmony_ci case PIN_FAST_BENCHMARK: 4762306a36Sopenharmony_ci case PIN_BASIC_TEST: 4862306a36Sopenharmony_ci case PIN_LONGTERM_BENCHMARK: 4962306a36Sopenharmony_ci for (i = 0; i < nr_pages; i++) { 5062306a36Sopenharmony_ci folio = page_folio(pages[i]); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (WARN(!folio_maybe_dma_pinned(folio), 5362306a36Sopenharmony_ci "pages[%lu] is NOT dma-pinned\n", i)) { 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci dump_page(&folio->page, "gup_test failure"); 5662306a36Sopenharmony_ci break; 5762306a36Sopenharmony_ci } else if (cmd == PIN_LONGTERM_BENCHMARK && 5862306a36Sopenharmony_ci WARN(!folio_is_longterm_pinnable(folio), 5962306a36Sopenharmony_ci "pages[%lu] is NOT pinnable but pinned\n", 6062306a36Sopenharmony_ci i)) { 6162306a36Sopenharmony_ci dump_page(&folio->page, "gup_test failure"); 6262306a36Sopenharmony_ci break; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci break; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void dump_pages_test(struct gup_test *gup, struct page **pages, 7062306a36Sopenharmony_ci unsigned long nr_pages) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci unsigned int index_to_dump; 7362306a36Sopenharmony_ci unsigned int i; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* 7662306a36Sopenharmony_ci * Zero out any user-supplied page index that is out of range. Remember: 7762306a36Sopenharmony_ci * .which_pages[] contains a 1-based set of page indices. 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_ci for (i = 0; i < GUP_TEST_MAX_PAGES_TO_DUMP; i++) { 8062306a36Sopenharmony_ci if (gup->which_pages[i] > nr_pages) { 8162306a36Sopenharmony_ci pr_warn("ZEROING due to out of range: .which_pages[%u]: %u\n", 8262306a36Sopenharmony_ci i, gup->which_pages[i]); 8362306a36Sopenharmony_ci gup->which_pages[i] = 0; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci for (i = 0; i < GUP_TEST_MAX_PAGES_TO_DUMP; i++) { 8862306a36Sopenharmony_ci index_to_dump = gup->which_pages[i]; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (index_to_dump) { 9162306a36Sopenharmony_ci index_to_dump--; // Decode from 1-based, to 0-based 9262306a36Sopenharmony_ci pr_info("---- page #%u, starting from user virt addr: 0x%llx\n", 9362306a36Sopenharmony_ci index_to_dump, gup->addr); 9462306a36Sopenharmony_ci dump_page(pages[index_to_dump], 9562306a36Sopenharmony_ci "gup_test: dump_pages() test"); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic int __gup_test_ioctl(unsigned int cmd, 10162306a36Sopenharmony_ci struct gup_test *gup) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci ktime_t start_time, end_time; 10462306a36Sopenharmony_ci unsigned long i, nr_pages, addr, next; 10562306a36Sopenharmony_ci long nr; 10662306a36Sopenharmony_ci struct page **pages; 10762306a36Sopenharmony_ci int ret = 0; 10862306a36Sopenharmony_ci bool needs_mmap_lock = 10962306a36Sopenharmony_ci cmd != GUP_FAST_BENCHMARK && cmd != PIN_FAST_BENCHMARK; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (gup->size > ULONG_MAX) 11262306a36Sopenharmony_ci return -EINVAL; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci nr_pages = gup->size / PAGE_SIZE; 11562306a36Sopenharmony_ci pages = kvcalloc(nr_pages, sizeof(void *), GFP_KERNEL); 11662306a36Sopenharmony_ci if (!pages) 11762306a36Sopenharmony_ci return -ENOMEM; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if (needs_mmap_lock && mmap_read_lock_killable(current->mm)) { 12062306a36Sopenharmony_ci ret = -EINTR; 12162306a36Sopenharmony_ci goto free_pages; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci i = 0; 12562306a36Sopenharmony_ci nr = gup->nr_pages_per_call; 12662306a36Sopenharmony_ci start_time = ktime_get(); 12762306a36Sopenharmony_ci for (addr = gup->addr; addr < gup->addr + gup->size; addr = next) { 12862306a36Sopenharmony_ci if (nr != gup->nr_pages_per_call) 12962306a36Sopenharmony_ci break; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci next = addr + nr * PAGE_SIZE; 13262306a36Sopenharmony_ci if (next > gup->addr + gup->size) { 13362306a36Sopenharmony_ci next = gup->addr + gup->size; 13462306a36Sopenharmony_ci nr = (next - addr) / PAGE_SIZE; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci switch (cmd) { 13862306a36Sopenharmony_ci case GUP_FAST_BENCHMARK: 13962306a36Sopenharmony_ci nr = get_user_pages_fast(addr, nr, gup->gup_flags, 14062306a36Sopenharmony_ci pages + i); 14162306a36Sopenharmony_ci break; 14262306a36Sopenharmony_ci case GUP_BASIC_TEST: 14362306a36Sopenharmony_ci nr = get_user_pages(addr, nr, gup->gup_flags, pages + i); 14462306a36Sopenharmony_ci break; 14562306a36Sopenharmony_ci case PIN_FAST_BENCHMARK: 14662306a36Sopenharmony_ci nr = pin_user_pages_fast(addr, nr, gup->gup_flags, 14762306a36Sopenharmony_ci pages + i); 14862306a36Sopenharmony_ci break; 14962306a36Sopenharmony_ci case PIN_BASIC_TEST: 15062306a36Sopenharmony_ci nr = pin_user_pages(addr, nr, gup->gup_flags, pages + i); 15162306a36Sopenharmony_ci break; 15262306a36Sopenharmony_ci case PIN_LONGTERM_BENCHMARK: 15362306a36Sopenharmony_ci nr = pin_user_pages(addr, nr, 15462306a36Sopenharmony_ci gup->gup_flags | FOLL_LONGTERM, 15562306a36Sopenharmony_ci pages + i); 15662306a36Sopenharmony_ci break; 15762306a36Sopenharmony_ci case DUMP_USER_PAGES_TEST: 15862306a36Sopenharmony_ci if (gup->test_flags & GUP_TEST_FLAG_DUMP_PAGES_USE_PIN) 15962306a36Sopenharmony_ci nr = pin_user_pages(addr, nr, gup->gup_flags, 16062306a36Sopenharmony_ci pages + i); 16162306a36Sopenharmony_ci else 16262306a36Sopenharmony_ci nr = get_user_pages(addr, nr, gup->gup_flags, 16362306a36Sopenharmony_ci pages + i); 16462306a36Sopenharmony_ci break; 16562306a36Sopenharmony_ci default: 16662306a36Sopenharmony_ci ret = -EINVAL; 16762306a36Sopenharmony_ci goto unlock; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (nr <= 0) 17162306a36Sopenharmony_ci break; 17262306a36Sopenharmony_ci i += nr; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci end_time = ktime_get(); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci /* Shifting the meaning of nr_pages: now it is actual number pinned: */ 17762306a36Sopenharmony_ci nr_pages = i; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci gup->get_delta_usec = ktime_us_delta(end_time, start_time); 18062306a36Sopenharmony_ci gup->size = addr - gup->addr; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* 18362306a36Sopenharmony_ci * Take an un-benchmark-timed moment to verify DMA pinned 18462306a36Sopenharmony_ci * state: print a warning if any non-dma-pinned pages are found: 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ci verify_dma_pinned(cmd, pages, nr_pages); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (cmd == DUMP_USER_PAGES_TEST) 18962306a36Sopenharmony_ci dump_pages_test(gup, pages, nr_pages); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci start_time = ktime_get(); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci put_back_pages(cmd, pages, nr_pages, gup->test_flags); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci end_time = ktime_get(); 19662306a36Sopenharmony_ci gup->put_delta_usec = ktime_us_delta(end_time, start_time); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ciunlock: 19962306a36Sopenharmony_ci if (needs_mmap_lock) 20062306a36Sopenharmony_ci mmap_read_unlock(current->mm); 20162306a36Sopenharmony_cifree_pages: 20262306a36Sopenharmony_ci kvfree(pages); 20362306a36Sopenharmony_ci return ret; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic DEFINE_MUTEX(pin_longterm_test_mutex); 20762306a36Sopenharmony_cistatic struct page **pin_longterm_test_pages; 20862306a36Sopenharmony_cistatic unsigned long pin_longterm_test_nr_pages; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic inline void pin_longterm_test_stop(void) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci if (pin_longterm_test_pages) { 21362306a36Sopenharmony_ci if (pin_longterm_test_nr_pages) 21462306a36Sopenharmony_ci unpin_user_pages(pin_longterm_test_pages, 21562306a36Sopenharmony_ci pin_longterm_test_nr_pages); 21662306a36Sopenharmony_ci kvfree(pin_longterm_test_pages); 21762306a36Sopenharmony_ci pin_longterm_test_pages = NULL; 21862306a36Sopenharmony_ci pin_longterm_test_nr_pages = 0; 21962306a36Sopenharmony_ci } 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic inline int pin_longterm_test_start(unsigned long arg) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci long nr_pages, cur_pages, addr, remaining_pages; 22562306a36Sopenharmony_ci int gup_flags = FOLL_LONGTERM; 22662306a36Sopenharmony_ci struct pin_longterm_test args; 22762306a36Sopenharmony_ci struct page **pages; 22862306a36Sopenharmony_ci int ret = 0; 22962306a36Sopenharmony_ci bool fast; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (pin_longterm_test_pages) 23262306a36Sopenharmony_ci return -EINVAL; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (copy_from_user(&args, (void __user *)arg, sizeof(args))) 23562306a36Sopenharmony_ci return -EFAULT; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (args.flags & 23862306a36Sopenharmony_ci ~(PIN_LONGTERM_TEST_FLAG_USE_WRITE|PIN_LONGTERM_TEST_FLAG_USE_FAST)) 23962306a36Sopenharmony_ci return -EINVAL; 24062306a36Sopenharmony_ci if (!IS_ALIGNED(args.addr | args.size, PAGE_SIZE)) 24162306a36Sopenharmony_ci return -EINVAL; 24262306a36Sopenharmony_ci if (args.size > LONG_MAX) 24362306a36Sopenharmony_ci return -EINVAL; 24462306a36Sopenharmony_ci nr_pages = args.size / PAGE_SIZE; 24562306a36Sopenharmony_ci if (!nr_pages) 24662306a36Sopenharmony_ci return -EINVAL; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci pages = kvcalloc(nr_pages, sizeof(void *), GFP_KERNEL); 24962306a36Sopenharmony_ci if (!pages) 25062306a36Sopenharmony_ci return -ENOMEM; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci if (args.flags & PIN_LONGTERM_TEST_FLAG_USE_WRITE) 25362306a36Sopenharmony_ci gup_flags |= FOLL_WRITE; 25462306a36Sopenharmony_ci fast = !!(args.flags & PIN_LONGTERM_TEST_FLAG_USE_FAST); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (!fast && mmap_read_lock_killable(current->mm)) { 25762306a36Sopenharmony_ci kvfree(pages); 25862306a36Sopenharmony_ci return -EINTR; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci pin_longterm_test_pages = pages; 26262306a36Sopenharmony_ci pin_longterm_test_nr_pages = 0; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci while (nr_pages - pin_longterm_test_nr_pages) { 26562306a36Sopenharmony_ci remaining_pages = nr_pages - pin_longterm_test_nr_pages; 26662306a36Sopenharmony_ci addr = args.addr + pin_longterm_test_nr_pages * PAGE_SIZE; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (fast) 26962306a36Sopenharmony_ci cur_pages = pin_user_pages_fast(addr, remaining_pages, 27062306a36Sopenharmony_ci gup_flags, pages); 27162306a36Sopenharmony_ci else 27262306a36Sopenharmony_ci cur_pages = pin_user_pages(addr, remaining_pages, 27362306a36Sopenharmony_ci gup_flags, pages); 27462306a36Sopenharmony_ci if (cur_pages < 0) { 27562306a36Sopenharmony_ci pin_longterm_test_stop(); 27662306a36Sopenharmony_ci ret = cur_pages; 27762306a36Sopenharmony_ci break; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci pin_longterm_test_nr_pages += cur_pages; 28062306a36Sopenharmony_ci pages += cur_pages; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (!fast) 28462306a36Sopenharmony_ci mmap_read_unlock(current->mm); 28562306a36Sopenharmony_ci return ret; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic inline int pin_longterm_test_read(unsigned long arg) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci __u64 user_addr; 29162306a36Sopenharmony_ci unsigned long i; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (!pin_longterm_test_pages) 29462306a36Sopenharmony_ci return -EINVAL; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (copy_from_user(&user_addr, (void __user *)arg, sizeof(user_addr))) 29762306a36Sopenharmony_ci return -EFAULT; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci for (i = 0; i < pin_longterm_test_nr_pages; i++) { 30062306a36Sopenharmony_ci void *addr = kmap_local_page(pin_longterm_test_pages[i]); 30162306a36Sopenharmony_ci unsigned long ret; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci ret = copy_to_user((void __user *)(unsigned long)user_addr, addr, 30462306a36Sopenharmony_ci PAGE_SIZE); 30562306a36Sopenharmony_ci kunmap_local(addr); 30662306a36Sopenharmony_ci if (ret) 30762306a36Sopenharmony_ci return -EFAULT; 30862306a36Sopenharmony_ci user_addr += PAGE_SIZE; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci return 0; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic long pin_longterm_test_ioctl(struct file *filep, unsigned int cmd, 31462306a36Sopenharmony_ci unsigned long arg) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci int ret = -EINVAL; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (mutex_lock_killable(&pin_longterm_test_mutex)) 31962306a36Sopenharmony_ci return -EINTR; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci switch (cmd) { 32262306a36Sopenharmony_ci case PIN_LONGTERM_TEST_START: 32362306a36Sopenharmony_ci ret = pin_longterm_test_start(arg); 32462306a36Sopenharmony_ci break; 32562306a36Sopenharmony_ci case PIN_LONGTERM_TEST_STOP: 32662306a36Sopenharmony_ci pin_longterm_test_stop(); 32762306a36Sopenharmony_ci ret = 0; 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci case PIN_LONGTERM_TEST_READ: 33062306a36Sopenharmony_ci ret = pin_longterm_test_read(arg); 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci mutex_unlock(&pin_longterm_test_mutex); 33562306a36Sopenharmony_ci return ret; 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic long gup_test_ioctl(struct file *filep, unsigned int cmd, 33962306a36Sopenharmony_ci unsigned long arg) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct gup_test gup; 34262306a36Sopenharmony_ci int ret; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci switch (cmd) { 34562306a36Sopenharmony_ci case GUP_FAST_BENCHMARK: 34662306a36Sopenharmony_ci case PIN_FAST_BENCHMARK: 34762306a36Sopenharmony_ci case PIN_LONGTERM_BENCHMARK: 34862306a36Sopenharmony_ci case GUP_BASIC_TEST: 34962306a36Sopenharmony_ci case PIN_BASIC_TEST: 35062306a36Sopenharmony_ci case DUMP_USER_PAGES_TEST: 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci case PIN_LONGTERM_TEST_START: 35362306a36Sopenharmony_ci case PIN_LONGTERM_TEST_STOP: 35462306a36Sopenharmony_ci case PIN_LONGTERM_TEST_READ: 35562306a36Sopenharmony_ci return pin_longterm_test_ioctl(filep, cmd, arg); 35662306a36Sopenharmony_ci default: 35762306a36Sopenharmony_ci return -EINVAL; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (copy_from_user(&gup, (void __user *)arg, sizeof(gup))) 36162306a36Sopenharmony_ci return -EFAULT; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci ret = __gup_test_ioctl(cmd, &gup); 36462306a36Sopenharmony_ci if (ret) 36562306a36Sopenharmony_ci return ret; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (copy_to_user((void __user *)arg, &gup, sizeof(gup))) 36862306a36Sopenharmony_ci return -EFAULT; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return 0; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic int gup_test_release(struct inode *inode, struct file *file) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci pin_longterm_test_stop(); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return 0; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic const struct file_operations gup_test_fops = { 38162306a36Sopenharmony_ci .open = nonseekable_open, 38262306a36Sopenharmony_ci .unlocked_ioctl = gup_test_ioctl, 38362306a36Sopenharmony_ci .compat_ioctl = compat_ptr_ioctl, 38462306a36Sopenharmony_ci .release = gup_test_release, 38562306a36Sopenharmony_ci}; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int __init gup_test_init(void) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci debugfs_create_file_unsafe("gup_test", 0600, NULL, NULL, 39062306a36Sopenharmony_ci &gup_test_fops); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci return 0; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cilate_initcall(gup_test_init); 396