1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * KUnit userspace memory allocation resource management. 4 */ 5 #include <kunit/resource.h> 6 #include <kunit/test.h> 7 #include <linux/kthread.h> 8 #include <linux/mm.h> 9 10 struct kunit_vm_mmap_resource { 11 unsigned long addr; 12 size_t size; 13 }; 14 15 /* vm_mmap() arguments */ 16 struct kunit_vm_mmap_params { 17 struct file *file; 18 unsigned long addr; 19 unsigned long len; 20 unsigned long prot; 21 unsigned long flag; 22 unsigned long offset; 23 }; 24 25 /* Create and attach a new mm if it doesn't already exist. */ 26 static int kunit_attach_mm(void) 27 { 28 struct mm_struct *mm; 29 30 if (current->mm) 31 return 0; 32 33 mm = mm_alloc(); 34 if (!mm) 35 return -ENOMEM; 36 37 /* Define the task size. */ 38 mm->task_size = TASK_SIZE; 39 40 /* Make sure we can allocate new VMAs. */ 41 arch_pick_mmap_layout(mm, ¤t->signal->rlim[RLIMIT_STACK]); 42 43 /* Attach the mm. It will be cleaned up when the process dies. */ 44 kthread_use_mm(mm); 45 46 return 0; 47 } 48 49 static int kunit_vm_mmap_init(struct kunit_resource *res, void *context) 50 { 51 struct kunit_vm_mmap_params *p = context; 52 struct kunit_vm_mmap_resource vres; 53 int ret; 54 55 ret = kunit_attach_mm(); 56 if (ret) 57 return ret; 58 59 vres.size = p->len; 60 vres.addr = vm_mmap(p->file, p->addr, p->len, p->prot, p->flag, p->offset); 61 if (!vres.addr) 62 return -ENOMEM; 63 res->data = kmemdup(&vres, sizeof(vres), GFP_KERNEL); 64 if (!res->data) { 65 vm_munmap(vres.addr, vres.size); 66 return -ENOMEM; 67 } 68 69 return 0; 70 } 71 72 static void kunit_vm_mmap_free(struct kunit_resource *res) 73 { 74 struct kunit_vm_mmap_resource *vres = res->data; 75 76 /* 77 * Since this is executed from the test monitoring process, 78 * the test's mm has already been torn down. We don't need 79 * to run vm_munmap(vres->addr, vres->size), only clean up 80 * the vres. 81 */ 82 83 kfree(vres); 84 res->data = NULL; 85 } 86 87 unsigned long kunit_vm_mmap(struct kunit *test, struct file *file, 88 unsigned long addr, unsigned long len, 89 unsigned long prot, unsigned long flag, 90 unsigned long offset) 91 { 92 struct kunit_vm_mmap_params params = { 93 .file = file, 94 .addr = addr, 95 .len = len, 96 .prot = prot, 97 .flag = flag, 98 .offset = offset, 99 }; 100 struct kunit_vm_mmap_resource *vres; 101 102 vres = kunit_alloc_resource(test, 103 kunit_vm_mmap_init, 104 kunit_vm_mmap_free, 105 GFP_KERNEL, 106 ¶ms); 107 if (vres) 108 return vres->addr; 109 return 0; 110 } 111 EXPORT_SYMBOL_GPL(kunit_vm_mmap); 112 113 MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING); 114