* [PATCH v6 1/2] drm/i915/selftests: Prevent userspace mapping invalidation
2026-04-15 9:21 [PATCH v6 0/2] drm/i915/selftests: Use safe userspace memory for mappings Krzysztof Karas
@ 2026-04-15 9:21 ` Krzysztof Karas
2026-04-15 22:21 ` Andi Shyti
2026-04-15 9:21 ` [PATCH v6 2/2] drm/i915/selftests: Run vma tests only if current->mm is present Krzysztof Karas
1 sibling, 1 reply; 5+ messages in thread
From: Krzysztof Karas @ 2026-04-15 9:21 UTC (permalink / raw)
To: intel-gfx
Cc: Andi Shyti, Sebastian Brzezinka, Krzysztof Niemiec,
Janusz Krzysztofik, Krzysztof Karas
Migration testing in i915 assumes current task's address space
to allocate new userspace mapping and uses it without
registering real user for that address space in mm_struct.
On single NUMA node setups PCI probe executes in the same
context as userspace process calling the test (i915_selftest
from IGT), but when multiple nodes are available, the PCI code
puts probe into a kernel workqueue. This switches execution in
a kworker, which does not have its own address space in
userspace and must borrow such memory from another process, so
"current->active_mm" is unknown at the start of the test.
It was observed that mm->mm_users would occasionally be 0
or drop to 0 during the test due to short delay between
scheduling and executing work in forked process, which reaped
userspace mappings, further leading to failures upon reading
from userland memory.
Prevent this by adding a PID parameter to a trusted task, so its
mm struct may be used if needed.
Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14204
Fixes: 34b1c1c71d37 ("i915/selftest/igt_mmap: let mmap tests run in kthread")
Signed-off-by: Krzysztof Karas <krzysztof.karas@intel.com>
---
v2 (Janusz):
* Reword and shorten commit message to be more precise.
* Reorder variable declarations to follow upside down christmas
tree style.
v3 (Andi):
* Prevent PID and mm leaks.
* Remove a flag and use mm pointer to determine whether to
release references to the memory.
v4:
* Revert !current->mm check. (Janusz, Sebastian)
* Drop refernce to mm sooner. (Janusz)
* Ensure kthread_use_mm did its job. (Janusz)
v5 (Janusz):
* Remove missing PID warning.
v6:
* Move mm handling to a separate function. (Andi)
* Validate user provided PID. (Janusz)
drivers/gpu/drm/i915/i915_selftest.h | 1 +
.../gpu/drm/i915/selftests/i915_selftest.c | 57 +++++++++++++++++++
2 files changed, 58 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_selftest.h b/drivers/gpu/drm/i915/i915_selftest.h
index 72922028f4ba..e29ca298e7eb 100644
--- a/drivers/gpu/drm/i915/i915_selftest.h
+++ b/drivers/gpu/drm/i915/i915_selftest.h
@@ -35,6 +35,7 @@ struct i915_selftest {
unsigned long timeout_jiffies;
unsigned int timeout_ms;
unsigned int random_seed;
+ unsigned int userspace_pid;
char *filter;
int mock;
int live;
diff --git a/drivers/gpu/drm/i915/selftests/i915_selftest.c b/drivers/gpu/drm/i915/selftests/i915_selftest.c
index 8460f0a70d04..90bd9fad39a3 100644
--- a/drivers/gpu/drm/i915/selftests/i915_selftest.c
+++ b/drivers/gpu/drm/i915/selftests/i915_selftest.c
@@ -181,11 +181,48 @@ __wait_gsc_huc_load_completed(struct drm_i915_private *i915)
pr_warn(DRIVER_NAME "Timed out waiting for huc load via GSC!\n");
}
+static struct mm_struct *
+get_mm(int u_pid_nr)
+{
+ struct pid *u_pid = find_get_pid(u_pid_nr);
+ struct task_struct *task;
+ struct mm_struct *mm;
+
+ if (!u_pid) {
+ pr_warn("Could not find PID: %d\n", u_pid_nr);
+ return NULL;
+ }
+
+ task = get_pid_task(u_pid, PIDTYPE_PID);
+ put_pid(u_pid);
+ if (!task) {
+ pr_warn("Could not find task for PID: %d\n", u_pid_nr);
+ return NULL;
+ }
+
+ if (task->flags & PF_KTHREAD) {
+ pr_warn("Task not in userspace: %d\n", u_pid_nr);
+ put_task_struct(task);
+ return NULL;
+ }
+
+ mm = get_task_mm(task);
+ put_task_struct(task);
+ if (!mm) {
+ pr_warn("Could not find address space of task with PID: %d\n", u_pid_nr);
+ return NULL;
+ }
+
+ return mm;
+}
+
static int __run_selftests(const char *name,
struct selftest *st,
unsigned int count,
void *data)
{
+ int u_pid_nr = i915_selftest.userspace_pid;
+ struct mm_struct *mm = NULL;
int err = 0;
while (!i915_selftest.random_seed)
@@ -201,6 +238,21 @@ static int __run_selftests(const char *name,
pr_info(DRIVER_NAME ": Performing %s selftests with st_random_seed=0x%x st_timeout=%u\n",
name, i915_selftest.random_seed, i915_selftest.timeout_ms);
+ /**
+ * If we are running in a kthread on a multi NUMA system and the user passed
+ * a valid PID of a userspace task, then we may borrow its address space
+ * to prepare a safe environment for the mmap selftests.
+ */
+ if (!current->mm && u_pid_nr) {
+ mm = get_mm(u_pid_nr);
+ if (mm) {
+ kthread_use_mm(mm);
+ mmput_async(mm);
+ if (unlikely(!current->mm))
+ pr_warn("Could not set mm as current->mm\n");
+ }
+ }
+
/* Tests are listed in order in i915_*_selftests.h */
for (; count--; st++) {
if (!st->enabled)
@@ -226,6 +278,9 @@ static int __run_selftests(const char *name,
st->name, err))
err = -1;
+ if (mm)
+ kthread_unuse_mm(mm);
+
return err;
}
@@ -507,6 +562,8 @@ void igt_hexdump(const void *buf, size_t len)
module_param_named(st_random_seed, i915_selftest.random_seed, uint, 0400);
module_param_named(st_timeout, i915_selftest.timeout_ms, uint, 0400);
module_param_named(st_filter, i915_selftest.filter, charp, 0400);
+module_param_named(st_userspace_pid, i915_selftest.userspace_pid, uint, 0400);
+MODULE_PARM_DESC(st_userspace_pid, "For usage in tests that map userspace memory and require address space with controllable lifetime.");
module_param_named_unsafe(mock_selftests, i915_selftest.mock, int, 0400);
MODULE_PARM_DESC(mock_selftests, "Run selftests before loading, using mock hardware (0:disabled [default], 1:run tests then load driver, -1:run tests then leave dummy module)");
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH v6 2/2] drm/i915/selftests: Run vma tests only if current->mm is present
2026-04-15 9:21 [PATCH v6 0/2] drm/i915/selftests: Use safe userspace memory for mappings Krzysztof Karas
2026-04-15 9:21 ` [PATCH v6 1/2] drm/i915/selftests: Prevent userspace mapping invalidation Krzysztof Karas
@ 2026-04-15 9:21 ` Krzysztof Karas
2026-04-15 22:23 ` Andi Shyti
1 sibling, 1 reply; 5+ messages in thread
From: Krzysztof Karas @ 2026-04-15 9:21 UTC (permalink / raw)
To: intel-gfx
Cc: Andi Shyti, Sebastian Brzezinka, Krzysztof Niemiec,
Janusz Krzysztofik, Krzysztof Karas
This set of tests require userspace memory to map objects,
so run them only if that memory is available.
Signed-off-by: Krzysztof Karas <krzysztof.karas@intel.com>
---
v5 (Janusz):
* Add warning when current->mm is missing.
v6 (Andi):
* Shorten the warning upon no current->mm.
.../gpu/drm/i915/gem/selftests/i915_gem_mman.c | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
index 9d454d0b46f2..b97e0d99d92c 100644
--- a/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
+++ b/drivers/gpu/drm/i915/gem/selftests/i915_gem_mman.c
@@ -1847,11 +1847,12 @@ static int igt_mmap_revoke(void *arg)
int i915_gem_mman_live_selftests(struct drm_i915_private *i915)
{
int ret;
- bool unuse_mm = false;
static const struct i915_subtest tests[] = {
SUBTEST(igt_partial_tiling),
SUBTEST(igt_smoke_tiling),
SUBTEST(igt_mmap_offset_exhaustion),
+ };
+ static const struct i915_subtest vma_tests[] = {
SUBTEST(igt_mmap),
SUBTEST(igt_mmap_migrate),
SUBTEST(igt_mmap_access),
@@ -1859,15 +1860,14 @@ int i915_gem_mman_live_selftests(struct drm_i915_private *i915)
SUBTEST(igt_mmap_gpu),
};
- if (!current->mm) {
- kthread_use_mm(current->active_mm);
- unuse_mm = true;
- }
-
ret = i915_live_subtests(tests, i915);
+ if (ret)
+ return ret;
- if (unuse_mm)
- kthread_unuse_mm(current->active_mm);
+ if (current->mm)
+ ret = i915_live_subtests(vma_tests, i915);
+ else
+ pr_warn("No current->mm.\n");
return ret;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread