0001 #include <linux/kernel.h>
0002 #include <linux/mm.h>
0003 #include <linux/slab.h>
0004 #include <linux/uaccess.h>
0005 #include <linux/ktime.h>
0006 #include <linux/debugfs.h>
0007 #include "gup_test.h"
0008
0009 static void put_back_pages(unsigned int cmd, struct page **pages,
0010 unsigned long nr_pages, unsigned int gup_test_flags)
0011 {
0012 unsigned long i;
0013
0014 switch (cmd) {
0015 case GUP_FAST_BENCHMARK:
0016 case GUP_BASIC_TEST:
0017 for (i = 0; i < nr_pages; i++)
0018 put_page(pages[i]);
0019 break;
0020
0021 case PIN_FAST_BENCHMARK:
0022 case PIN_BASIC_TEST:
0023 case PIN_LONGTERM_BENCHMARK:
0024 unpin_user_pages(pages, nr_pages);
0025 break;
0026 case DUMP_USER_PAGES_TEST:
0027 if (gup_test_flags & GUP_TEST_FLAG_DUMP_PAGES_USE_PIN) {
0028 unpin_user_pages(pages, nr_pages);
0029 } else {
0030 for (i = 0; i < nr_pages; i++)
0031 put_page(pages[i]);
0032
0033 }
0034 break;
0035 }
0036 }
0037
0038 static void verify_dma_pinned(unsigned int cmd, struct page **pages,
0039 unsigned long nr_pages)
0040 {
0041 unsigned long i;
0042 struct page *page;
0043
0044 switch (cmd) {
0045 case PIN_FAST_BENCHMARK:
0046 case PIN_BASIC_TEST:
0047 case PIN_LONGTERM_BENCHMARK:
0048 for (i = 0; i < nr_pages; i++) {
0049 page = pages[i];
0050 if (WARN(!page_maybe_dma_pinned(page),
0051 "pages[%lu] is NOT dma-pinned\n", i)) {
0052
0053 dump_page(page, "gup_test failure");
0054 break;
0055 } else if (cmd == PIN_LONGTERM_BENCHMARK &&
0056 WARN(!is_longterm_pinnable_page(page),
0057 "pages[%lu] is NOT pinnable but pinned\n",
0058 i)) {
0059 dump_page(page, "gup_test failure");
0060 break;
0061 }
0062 }
0063 break;
0064 }
0065 }
0066
0067 static void dump_pages_test(struct gup_test *gup, struct page **pages,
0068 unsigned long nr_pages)
0069 {
0070 unsigned int index_to_dump;
0071 unsigned int i;
0072
0073
0074
0075
0076
0077 for (i = 0; i < GUP_TEST_MAX_PAGES_TO_DUMP; i++) {
0078 if (gup->which_pages[i] > nr_pages) {
0079 pr_warn("ZEROING due to out of range: .which_pages[%u]: %u\n",
0080 i, gup->which_pages[i]);
0081 gup->which_pages[i] = 0;
0082 }
0083 }
0084
0085 for (i = 0; i < GUP_TEST_MAX_PAGES_TO_DUMP; i++) {
0086 index_to_dump = gup->which_pages[i];
0087
0088 if (index_to_dump) {
0089 index_to_dump--;
0090 pr_info("---- page #%u, starting from user virt addr: 0x%llx\n",
0091 index_to_dump, gup->addr);
0092 dump_page(pages[index_to_dump],
0093 "gup_test: dump_pages() test");
0094 }
0095 }
0096 }
0097
0098 static int __gup_test_ioctl(unsigned int cmd,
0099 struct gup_test *gup)
0100 {
0101 ktime_t start_time, end_time;
0102 unsigned long i, nr_pages, addr, next;
0103 long nr;
0104 struct page **pages;
0105 int ret = 0;
0106 bool needs_mmap_lock =
0107 cmd != GUP_FAST_BENCHMARK && cmd != PIN_FAST_BENCHMARK;
0108
0109 if (gup->size > ULONG_MAX)
0110 return -EINVAL;
0111
0112 nr_pages = gup->size / PAGE_SIZE;
0113 pages = kvcalloc(nr_pages, sizeof(void *), GFP_KERNEL);
0114 if (!pages)
0115 return -ENOMEM;
0116
0117 if (needs_mmap_lock && mmap_read_lock_killable(current->mm)) {
0118 ret = -EINTR;
0119 goto free_pages;
0120 }
0121
0122 i = 0;
0123 nr = gup->nr_pages_per_call;
0124 start_time = ktime_get();
0125 for (addr = gup->addr; addr < gup->addr + gup->size; addr = next) {
0126 if (nr != gup->nr_pages_per_call)
0127 break;
0128
0129 next = addr + nr * PAGE_SIZE;
0130 if (next > gup->addr + gup->size) {
0131 next = gup->addr + gup->size;
0132 nr = (next - addr) / PAGE_SIZE;
0133 }
0134
0135 switch (cmd) {
0136 case GUP_FAST_BENCHMARK:
0137 nr = get_user_pages_fast(addr, nr, gup->gup_flags,
0138 pages + i);
0139 break;
0140 case GUP_BASIC_TEST:
0141 nr = get_user_pages(addr, nr, gup->gup_flags, pages + i,
0142 NULL);
0143 break;
0144 case PIN_FAST_BENCHMARK:
0145 nr = pin_user_pages_fast(addr, nr, gup->gup_flags,
0146 pages + i);
0147 break;
0148 case PIN_BASIC_TEST:
0149 nr = pin_user_pages(addr, nr, gup->gup_flags, pages + i,
0150 NULL);
0151 break;
0152 case PIN_LONGTERM_BENCHMARK:
0153 nr = pin_user_pages(addr, nr,
0154 gup->gup_flags | FOLL_LONGTERM,
0155 pages + i, NULL);
0156 break;
0157 case DUMP_USER_PAGES_TEST:
0158 if (gup->test_flags & GUP_TEST_FLAG_DUMP_PAGES_USE_PIN)
0159 nr = pin_user_pages(addr, nr, gup->gup_flags,
0160 pages + i, NULL);
0161 else
0162 nr = get_user_pages(addr, nr, gup->gup_flags,
0163 pages + i, NULL);
0164 break;
0165 default:
0166 ret = -EINVAL;
0167 goto unlock;
0168 }
0169
0170 if (nr <= 0)
0171 break;
0172 i += nr;
0173 }
0174 end_time = ktime_get();
0175
0176
0177 nr_pages = i;
0178
0179 gup->get_delta_usec = ktime_us_delta(end_time, start_time);
0180 gup->size = addr - gup->addr;
0181
0182
0183
0184
0185
0186 verify_dma_pinned(cmd, pages, nr_pages);
0187
0188 if (cmd == DUMP_USER_PAGES_TEST)
0189 dump_pages_test(gup, pages, nr_pages);
0190
0191 start_time = ktime_get();
0192
0193 put_back_pages(cmd, pages, nr_pages, gup->test_flags);
0194
0195 end_time = ktime_get();
0196 gup->put_delta_usec = ktime_us_delta(end_time, start_time);
0197
0198 unlock:
0199 if (needs_mmap_lock)
0200 mmap_read_unlock(current->mm);
0201 free_pages:
0202 kvfree(pages);
0203 return ret;
0204 }
0205
0206 static long gup_test_ioctl(struct file *filep, unsigned int cmd,
0207 unsigned long arg)
0208 {
0209 struct gup_test gup;
0210 int ret;
0211
0212 switch (cmd) {
0213 case GUP_FAST_BENCHMARK:
0214 case PIN_FAST_BENCHMARK:
0215 case PIN_LONGTERM_BENCHMARK:
0216 case GUP_BASIC_TEST:
0217 case PIN_BASIC_TEST:
0218 case DUMP_USER_PAGES_TEST:
0219 break;
0220 default:
0221 return -EINVAL;
0222 }
0223
0224 if (copy_from_user(&gup, (void __user *)arg, sizeof(gup)))
0225 return -EFAULT;
0226
0227 ret = __gup_test_ioctl(cmd, &gup);
0228 if (ret)
0229 return ret;
0230
0231 if (copy_to_user((void __user *)arg, &gup, sizeof(gup)))
0232 return -EFAULT;
0233
0234 return 0;
0235 }
0236
0237 static const struct file_operations gup_test_fops = {
0238 .open = nonseekable_open,
0239 .unlocked_ioctl = gup_test_ioctl,
0240 };
0241
0242 static int __init gup_test_init(void)
0243 {
0244 debugfs_create_file_unsafe("gup_test", 0600, NULL, NULL,
0245 &gup_test_fops);
0246
0247 return 0;
0248 }
0249
0250 late_initcall(gup_test_init);