diff options
Diffstat (limited to 'lib/kunit/user_alloc.c')
| -rw-r--r-- | lib/kunit/user_alloc.c | 117 | 
1 files changed, 117 insertions, 0 deletions
| diff --git a/lib/kunit/user_alloc.c b/lib/kunit/user_alloc.c new file mode 100644 index 000000000000..ae935df09a5e --- /dev/null +++ b/lib/kunit/user_alloc.c @@ -0,0 +1,117 @@ +// 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; +}; + +/* Create and attach a new mm if it doesn't already exist. */ +static 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; +} + +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); |