118 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 10struct kunit_vm_mmap_resource {11 unsigned long addr;12 size_t size;13};14 15/* vm_mmap() arguments */16struct 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. */26static int kunit_attach_mm(void)27{28 struct mm_struct *mm;29 30 if (current->mm)31 return 0;32 33 /* arch_pick_mmap_layout() is only sane with MMU systems. */34 if (!IS_ENABLED(CONFIG_MMU))35 return -EINVAL;36 37 mm = mm_alloc();38 if (!mm)39 return -ENOMEM;40 41 /* Define the task size. */42 mm->task_size = TASK_SIZE;43 44 /* Make sure we can allocate new VMAs. */45 arch_pick_mmap_layout(mm, ¤t->signal->rlim[RLIMIT_STACK]);46 47 /* Attach the mm. It will be cleaned up when the process dies. */48 kthread_use_mm(mm);49 50 return 0;51}52 53static int kunit_vm_mmap_init(struct kunit_resource *res, void *context)54{55 struct kunit_vm_mmap_params *p = context;56 struct kunit_vm_mmap_resource vres;57 int ret;58 59 ret = kunit_attach_mm();60 if (ret)61 return ret;62 63 vres.size = p->len;64 vres.addr = vm_mmap(p->file, p->addr, p->len, p->prot, p->flag, p->offset);65 if (!vres.addr)66 return -ENOMEM;67 res->data = kmemdup(&vres, sizeof(vres), GFP_KERNEL);68 if (!res->data) {69 vm_munmap(vres.addr, vres.size);70 return -ENOMEM;71 }72 73 return 0;74}75 76static void kunit_vm_mmap_free(struct kunit_resource *res)77{78 struct kunit_vm_mmap_resource *vres = res->data;79 80 /*81 * Since this is executed from the test monitoring process,82 * the test's mm has already been torn down. We don't need83 * to run vm_munmap(vres->addr, vres->size), only clean up84 * the vres.85 */86 87 kfree(vres);88 res->data = NULL;89}90 91unsigned long kunit_vm_mmap(struct kunit *test, struct file *file,92 unsigned long addr, unsigned long len,93 unsigned long prot, unsigned long flag,94 unsigned long offset)95{96 struct kunit_vm_mmap_params params = {97 .file = file,98 .addr = addr,99 .len = len,100 .prot = prot,101 .flag = flag,102 .offset = offset,103 };104 struct kunit_vm_mmap_resource *vres;105 106 vres = kunit_alloc_resource(test,107 kunit_vm_mmap_init,108 kunit_vm_mmap_free,109 GFP_KERNEL,110 ¶ms);111 if (vres)112 return vres->addr;113 return 0;114}115EXPORT_SYMBOL_GPL(kunit_vm_mmap);116 117MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);118