user_alloc.c 2.4 KB

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