1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/kernel.h> 3 #include <linux/mm.h> 4 #include <linux/slab.h> 5 #include <linux/uaccess.h> 6 #include <linux/ktime.h> 7 #include <linux/debugfs.h> 8 #include <linux/highmem.h> 9 #include "gup_test.h" 10 11 static void put_back_pages(unsigned int cmd, struct page **pages, 12 unsigned long nr_pages, unsigned int gup_test_flags) 13 { 14 unsigned long i; 15 16 switch (cmd) { 17 case GUP_FAST_BENCHMARK: 18 case GUP_BASIC_TEST: 19 for (i = 0; i < nr_pages; i++) 20 put_page(pages[i]); 21 break; 22 23 case PIN_FAST_BENCHMARK: 24 case PIN_BASIC_TEST: 25 case PIN_LONGTERM_BENCHMARK: 26 unpin_user_pages(pages, nr_pages); 27 break; 28 case DUMP_USER_PAGES_TEST: 29 if (gup_test_flags & GUP_TEST_FLAG_DUMP_PAGES_USE_PIN) { 30 unpin_user_pages(pages, nr_pages); 31 } else { 32 for (i = 0; i < nr_pages; i++) 33 put_page(pages[i]); 34 35 } 36 break; 37 } 38 } 39 40 static void verify_dma_pinned(unsigned int cmd, struct page **pages, 41 unsigned long nr_pages) 42 { 43 unsigned long i; 44 struct folio *folio; 45 46 switch (cmd) { 47 case PIN_FAST_BENCHMARK: 48 case PIN_BASIC_TEST: 49 case PIN_LONGTERM_BENCHMARK: 50 for (i = 0; i < nr_pages; i++) { 51 folio = page_folio(pages[i]); 52 53 if (WARN(!folio_maybe_dma_pinned(folio), 54 "pages[%lu] is NOT dma-pinned\n", i)) { 55 56 dump_page(&folio->page, "gup_test failure"); 57 break; 58 } else if (cmd == PIN_LONGTERM_BENCHMARK && 59 WARN(!folio_is_longterm_pinnable(folio), 60 "pages[%lu] is NOT pinnable but pinned\n", 61 i)) { 62 dump_page(&folio->page, "gup_test failure"); 63 break; 64 } 65 } 66 break; 67 } 68 } 69 70 static void dump_pages_test(struct gup_test *gup, struct page **pages, 71 unsigned long nr_pages) 72 { 73 unsigned int index_to_dump; 74 unsigned int i; 75 76 /* 77 * Zero out any user-supplied page index that is out of range. Remember: 78 * .which_pages[] contains a 1-based set of page indices. 79 */ 80 for (i = 0; i < GUP_TEST_MAX_PAGES_TO_DUMP; i++) { 81 if (gup->which_pages[i] > nr_pages) { 82 pr_warn("ZEROING due to out of range: .which_pages[%u]: %u\n", 83 i, gup->which_pages[i]); 84 gup->which_pages[i] = 0; 85 } 86 } 87 88 for (i = 0; i < GUP_TEST_MAX_PAGES_TO_DUMP; i++) { 89 index_to_dump = gup->which_pages[i]; 90 91 if (index_to_dump) { 92 index_to_dump--; // Decode from 1-based, to 0-based 93 pr_info("---- page #%u, starting from user virt addr: 0x%llx\n", 94 index_to_dump, gup->addr); 95 dump_page(pages[index_to_dump], 96 "gup_test: dump_pages() test"); 97 } 98 } 99 } 100 101 static int __gup_test_ioctl(unsigned int cmd, 102 struct gup_test *gup) 103 { 104 ktime_t start_time, end_time; 105 unsigned long i, nr_pages, addr, next; 106 long nr; 107 struct page **pages; 108 unsigned long end; 109 int ret = 0; 110 bool needs_mmap_lock = 111 cmd != GUP_FAST_BENCHMARK && cmd != PIN_FAST_BENCHMARK; 112 113 if (gup->addr > ULONG_MAX || gup->size > ULONG_MAX) 114 return -EINVAL; 115 if (check_add_overflow((unsigned long)gup->addr, 116 (unsigned long)gup->size, &end)) 117 return -EINVAL; 118 119 nr_pages = gup->size / PAGE_SIZE; 120 pages = kvcalloc(nr_pages, sizeof(void *), GFP_KERNEL); 121 if (!pages) 122 return -ENOMEM; 123 124 if (needs_mmap_lock && mmap_read_lock_killable(current->mm)) { 125 ret = -EINTR; 126 goto free_pages; 127 } 128 129 i = 0; 130 nr = gup->nr_pages_per_call; 131 start_time = ktime_get(); 132 for (addr = gup->addr; addr < end; addr = next) { 133 if (nr != gup->nr_pages_per_call) 134 break; 135 136 next = addr + nr * PAGE_SIZE; 137 if (next > end) { 138 next = end; 139 nr = (next - addr) / PAGE_SIZE; 140 } 141 142 switch (cmd) { 143 case GUP_FAST_BENCHMARK: 144 nr = get_user_pages_fast(addr, nr, gup->gup_flags, 145 pages + i); 146 break; 147 case GUP_BASIC_TEST: 148 nr = get_user_pages(addr, nr, gup->gup_flags, pages + i); 149 break; 150 case PIN_FAST_BENCHMARK: 151 nr = pin_user_pages_fast(addr, nr, gup->gup_flags, 152 pages + i); 153 break; 154 case PIN_BASIC_TEST: 155 nr = pin_user_pages(addr, nr, gup->gup_flags, pages + i); 156 break; 157 case PIN_LONGTERM_BENCHMARK: 158 nr = pin_user_pages(addr, nr, 159 gup->gup_flags | FOLL_LONGTERM, 160 pages + i); 161 break; 162 case DUMP_USER_PAGES_TEST: 163 if (gup->test_flags & GUP_TEST_FLAG_DUMP_PAGES_USE_PIN) 164 nr = pin_user_pages(addr, nr, gup->gup_flags, 165 pages + i); 166 else 167 nr = get_user_pages(addr, nr, gup->gup_flags, 168 pages + i); 169 break; 170 default: 171 ret = -EINVAL; 172 goto unlock; 173 } 174 175 if (nr <= 0) 176 break; 177 i += nr; 178 } 179 end_time = ktime_get(); 180 181 /* Shifting the meaning of nr_pages: now it is actual number pinned: */ 182 nr_pages = i; 183 184 gup->get_delta_usec = ktime_us_delta(end_time, start_time); 185 gup->size = addr - gup->addr; 186 187 /* 188 * Take an un-benchmark-timed moment to verify DMA pinned 189 * state: print a warning if any non-dma-pinned pages are found: 190 */ 191 verify_dma_pinned(cmd, pages, nr_pages); 192 193 if (cmd == DUMP_USER_PAGES_TEST) 194 dump_pages_test(gup, pages, nr_pages); 195 196 start_time = ktime_get(); 197 198 put_back_pages(cmd, pages, nr_pages, gup->test_flags); 199 200 end_time = ktime_get(); 201 gup->put_delta_usec = ktime_us_delta(end_time, start_time); 202 203 unlock: 204 if (needs_mmap_lock) 205 mmap_read_unlock(current->mm); 206 free_pages: 207 kvfree(pages); 208 return ret; 209 } 210 211 static DEFINE_MUTEX(pin_longterm_test_mutex); 212 static struct page **pin_longterm_test_pages; 213 static unsigned long pin_longterm_test_nr_pages; 214 215 static inline void pin_longterm_test_stop(void) 216 { 217 if (pin_longterm_test_pages) { 218 if (pin_longterm_test_nr_pages) 219 unpin_user_pages(pin_longterm_test_pages, 220 pin_longterm_test_nr_pages); 221 kvfree(pin_longterm_test_pages); 222 pin_longterm_test_pages = NULL; 223 pin_longterm_test_nr_pages = 0; 224 } 225 } 226 227 static inline int pin_longterm_test_start(unsigned long arg) 228 { 229 long nr_pages, cur_pages, addr, remaining_pages; 230 int gup_flags = FOLL_LONGTERM; 231 struct pin_longterm_test args; 232 struct page **pages; 233 int ret = 0; 234 bool fast; 235 236 if (pin_longterm_test_pages) 237 return -EINVAL; 238 239 if (copy_from_user(&args, (void __user *)arg, sizeof(args))) 240 return -EFAULT; 241 242 if (args.flags & 243 ~(PIN_LONGTERM_TEST_FLAG_USE_WRITE|PIN_LONGTERM_TEST_FLAG_USE_FAST)) 244 return -EINVAL; 245 if (!IS_ALIGNED(args.addr | args.size, PAGE_SIZE)) 246 return -EINVAL; 247 if (args.size > LONG_MAX) 248 return -EINVAL; 249 nr_pages = args.size / PAGE_SIZE; 250 if (!nr_pages) 251 return -EINVAL; 252 253 pages = kvcalloc(nr_pages, sizeof(void *), GFP_KERNEL); 254 if (!pages) 255 return -ENOMEM; 256 257 if (args.flags & PIN_LONGTERM_TEST_FLAG_USE_WRITE) 258 gup_flags |= FOLL_WRITE; 259 fast = !!(args.flags & PIN_LONGTERM_TEST_FLAG_USE_FAST); 260 261 if (!fast && mmap_read_lock_killable(current->mm)) { 262 kvfree(pages); 263 return -EINTR; 264 } 265 266 pin_longterm_test_pages = pages; 267 pin_longterm_test_nr_pages = 0; 268 269 while (nr_pages - pin_longterm_test_nr_pages) { 270 remaining_pages = nr_pages - pin_longterm_test_nr_pages; 271 addr = args.addr + pin_longterm_test_nr_pages * PAGE_SIZE; 272 273 if (fast) 274 cur_pages = pin_user_pages_fast(addr, remaining_pages, 275 gup_flags, pages); 276 else 277 cur_pages = pin_user_pages(addr, remaining_pages, 278 gup_flags, pages); 279 if (cur_pages < 0) { 280 pin_longterm_test_stop(); 281 ret = cur_pages; 282 break; 283 } 284 pin_longterm_test_nr_pages += cur_pages; 285 pages += cur_pages; 286 } 287 288 if (!fast) 289 mmap_read_unlock(current->mm); 290 return ret; 291 } 292 293 static inline int pin_longterm_test_read(unsigned long arg) 294 { 295 __u64 user_addr; 296 unsigned long i; 297 298 if (!pin_longterm_test_pages) 299 return -EINVAL; 300 301 if (copy_from_user(&user_addr, (void __user *)arg, sizeof(user_addr))) 302 return -EFAULT; 303 304 for (i = 0; i < pin_longterm_test_nr_pages; i++) { 305 void *addr = kmap_local_page(pin_longterm_test_pages[i]); 306 unsigned long ret; 307 308 ret = copy_to_user((void __user *)(unsigned long)user_addr, addr, 309 PAGE_SIZE); 310 kunmap_local(addr); 311 if (ret) 312 return -EFAULT; 313 user_addr += PAGE_SIZE; 314 } 315 return 0; 316 } 317 318 static long pin_longterm_test_ioctl(struct file *filep, unsigned int cmd, 319 unsigned long arg) 320 { 321 int ret = -EINVAL; 322 323 if (mutex_lock_killable(&pin_longterm_test_mutex)) 324 return -EINTR; 325 326 switch (cmd) { 327 case PIN_LONGTERM_TEST_START: 328 ret = pin_longterm_test_start(arg); 329 break; 330 case PIN_LONGTERM_TEST_STOP: 331 pin_longterm_test_stop(); 332 ret = 0; 333 break; 334 case PIN_LONGTERM_TEST_READ: 335 ret = pin_longterm_test_read(arg); 336 break; 337 } 338 339 mutex_unlock(&pin_longterm_test_mutex); 340 return ret; 341 } 342 343 static long gup_test_ioctl(struct file *filep, unsigned int cmd, 344 unsigned long arg) 345 { 346 struct gup_test gup; 347 int ret; 348 349 switch (cmd) { 350 case GUP_FAST_BENCHMARK: 351 case PIN_FAST_BENCHMARK: 352 case PIN_LONGTERM_BENCHMARK: 353 case GUP_BASIC_TEST: 354 case PIN_BASIC_TEST: 355 case DUMP_USER_PAGES_TEST: 356 break; 357 case PIN_LONGTERM_TEST_START: 358 case PIN_LONGTERM_TEST_STOP: 359 case PIN_LONGTERM_TEST_READ: 360 return pin_longterm_test_ioctl(filep, cmd, arg); 361 default: 362 return -EINVAL; 363 } 364 365 if (copy_from_user(&gup, (void __user *)arg, sizeof(gup))) 366 return -EFAULT; 367 368 ret = __gup_test_ioctl(cmd, &gup); 369 if (ret) 370 return ret; 371 372 if (copy_to_user((void __user *)arg, &gup, sizeof(gup))) 373 return -EFAULT; 374 375 return 0; 376 } 377 378 static int gup_test_release(struct inode *inode, struct file *file) 379 { 380 pin_longterm_test_stop(); 381 382 return 0; 383 } 384 385 static const struct file_operations gup_test_fops = { 386 .open = nonseekable_open, 387 .unlocked_ioctl = gup_test_ioctl, 388 .compat_ioctl = compat_ptr_ioctl, 389 .release = gup_test_release, 390 }; 391 392 static int __init gup_test_init(void) 393 { 394 debugfs_create_file_unsafe("gup_test", 0600, NULL, NULL, 395 &gup_test_fops); 396 397 return 0; 398 } 399 400 late_initcall(gup_test_init); 401