| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * KUnit userspace memory allocation resource management.
- */
- #include <kunit/resource.h>
- #include <kunit/test.h>
- #include <linux/kthread.h>
- #include <linux/mm.h>
- struct kunit_vm_mmap_resource {
- unsigned long addr;
- size_t size;
- };
- /* vm_mmap() arguments */
- struct kunit_vm_mmap_params {
- struct file *file;
- unsigned long addr;
- unsigned long len;
- unsigned long prot;
- unsigned long flag;
- unsigned long offset;
- };
- int kunit_attach_mm(void)
- {
- struct mm_struct *mm;
- if (current->mm)
- return 0;
- /* arch_pick_mmap_layout() is only sane with MMU systems. */
- if (!IS_ENABLED(CONFIG_MMU))
- return -EINVAL;
- mm = mm_alloc();
- if (!mm)
- return -ENOMEM;
- /* Define the task size. */
- mm->task_size = TASK_SIZE;
- /* Make sure we can allocate new VMAs. */
- arch_pick_mmap_layout(mm, ¤t->signal->rlim[RLIMIT_STACK]);
- /* Attach the mm. It will be cleaned up when the process dies. */
- kthread_use_mm(mm);
- return 0;
- }
- EXPORT_SYMBOL_GPL(kunit_attach_mm);
- static int kunit_vm_mmap_init(struct kunit_resource *res, void *context)
- {
- struct kunit_vm_mmap_params *p = context;
- struct kunit_vm_mmap_resource vres;
- int ret;
- ret = kunit_attach_mm();
- if (ret)
- return ret;
- vres.size = p->len;
- vres.addr = vm_mmap(p->file, p->addr, p->len, p->prot, p->flag, p->offset);
- if (!vres.addr)
- return -ENOMEM;
- res->data = kmemdup(&vres, sizeof(vres), GFP_KERNEL);
- if (!res->data) {
- vm_munmap(vres.addr, vres.size);
- return -ENOMEM;
- }
- return 0;
- }
- static void kunit_vm_mmap_free(struct kunit_resource *res)
- {
- struct kunit_vm_mmap_resource *vres = res->data;
- /*
- * Since this is executed from the test monitoring process,
- * the test's mm has already been torn down. We don't need
- * to run vm_munmap(vres->addr, vres->size), only clean up
- * the vres.
- */
- kfree(vres);
- res->data = NULL;
- }
- unsigned long kunit_vm_mmap(struct kunit *test, struct file *file,
- unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flag,
- unsigned long offset)
- {
- struct kunit_vm_mmap_params params = {
- .file = file,
- .addr = addr,
- .len = len,
- .prot = prot,
- .flag = flag,
- .offset = offset,
- };
- struct kunit_vm_mmap_resource *vres;
- vres = kunit_alloc_resource(test,
- kunit_vm_mmap_init,
- kunit_vm_mmap_free,
- GFP_KERNEL,
- ¶ms);
- if (vres)
- return vres->addr;
- return 0;
- }
- EXPORT_SYMBOL_GPL(kunit_vm_mmap);
- MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
|