RE: [PATCH] tests/amdgpu: Add lockdep false positive reproducer test
"Zhang, Jesse(Jie)" <[email protected]>
| Newsgroups | org.freedesktop.lists.igt-dev |
|---|---|
| Message-ID | <DM4PR12MB51528DD83766C9223743C7B0E3C12@DM4PR12MB5152.namprd12.prod.outlook.com> |
AMD General Hi Vitaly, I have some comments in line. Except that, this patch is good for me. > -----Original Message----- > From: [email protected] <[email protected]> > Sent: Tuesday, July 21, 2026 9:17 AM > To: [email protected] > Cc: Prosyak, Vitaly <[email protected]>; Mikhail Gavrilov > <[email protected]>; Koenig, Christian <[email protected]>; > Deucher, Alexander <[email protected]>; Zhang, Jesse(Jie) > <[email protected]> > Subject: [PATCH] tests/amdgpu: Add lockdep false positive reproducer test > > From: Vitaly Prosyak <[email protected]> > > Add notifier-reclaim-splat subtest to amd_lockdep that reproduces the lockdep false > positive circular dependency warning reported by Mikhail Gavrilov. > > The test is based on Mikhail Gavrilov's standalone reproducer code. > It creates a 64MB GPU userptr memory buffer, then repeatedly forces the kernel to > reclaim it by issuing madvise(MADV_PAGEOUT). This simulates memory pressure > and triggers the MMU notifier callback path (amdgpu_hmm_invalidate_gfx) from > within the reclaim context. > > The test exposes the lockdep false positive where amdgpu_lockdep_init() > incorrectly taught lockdep that fs_reclaim can be acquired while holding > notifier_lock, when the runtime path actually takes notifier_lock under fs_reclaim > (the opposite direction). > > Test behavior: > Before kernel fix: Lockdep splat on first reclaim attempt (iteration 1/8) > After kernel fix: All 8 iterations complete without warnings > > The test monitors dmesg for lockdep violations and reports them to the user with > detailed explanation of the kernel bug and required fix. > > Run with: > sudo ./build/tests/amdgpu/amd_lockdep --run-subtest notifier-reclaim-splat > > Requires: > - Kernel built with CONFIG_PROVE_LOCKING=y (lockdep enabled) > - Fresh boot (lockdep disables itself after first splat) > - AMD GPU with amdgpu driver > > The corresponding kernel fix is: > drm/amdgpu: Fix lockdep false positive in amdgpu_lockdep_init > > v2: Credit Mikhail Gavrilov properly: > - Fix author name: Michael -> Mikhail Gavrilov in Based-on-patch-by > - Add note about corresponding kernel fix in commit message > > Based-on-patch-by: Mikhail Gavrilov <[email protected]> > Cc: Christian König <[email protected]> > Cc: Alex Deucher <[email protected]> > Cc: Jesse Zhang <[email protected]> > Cc: Mikhail Gavrilov <[email protected]> > Signed-off-by: Vitaly Prosyak <[email protected]> > --- > tests/amdgpu/amd_lockdep.c | 123 > +++++++++++++++++++++++++++++++++++++ > 1 file changed, 123 insertions(+) > > diff --git a/tests/amdgpu/amd_lockdep.c b/tests/amdgpu/amd_lockdep.c index > 48d7ccafa..8edae507c 100644 > --- a/tests/amdgpu/amd_lockdep.c > +++ b/tests/amdgpu/amd_lockdep.c > @@ -20,6 +20,7 @@ > * concurrent-mmap-and-evict - mmap/munmap while VRAM eviction runs > * concurrent-userptr-and-reset - USERPTR invalidation during reset > * stress-all-paths - Combined stress of all paths > + * notifier-reclaim-splat - userptr + MADV_PAGEOUT (Michael Gavrilov) > */ > > #include <errno.h> > @@ -42,6 +43,10 @@ > #define STRESS_ITERATIONS 100 > #define THREAD_RUNTIME_SEC 2 > > +/* For notifier-reclaim-splat test */ > +#define USERPTR_BUF_SIZE (64ull * 1024 * 1024) /* 64 MiB */ #define > +PAGEOUT_ITERATIONS 8 > + > /* kmsg patterns that indicate lockdep violations */ static const char > *lockdep_violation_patterns[] = { > "circular locking dependency", > @@ -478,6 +483,120 @@ static void test_stress_all_paths(int fd, > amdgpu_device_handle device) > close(kmsg_fd); > } > > +/* For notifier-reclaim-splat test */ > +#define USERPTR_BUF_SIZE (64ull * 1024 * 1024) /* 64 MiB */ #define > +PAGEOUT_ITERATIONS 8 [Zhang, Jesse(Jie)] remove the duplicate define. > + > +/* > + * test_notifier_reclaim_splat - Michael Gavrilov reproducer > + * > + * Triggers the false positive lockdep splat by: > + * 1. Creating anonymous memory buffer (64MB) > + * 2. Registering it as AMDGPU userptr (installs MMU notifier) > + * 3. Forcing memory reclaim with madvise(MADV_PAGEOUT) > + * 4. Reclaim path calls MMU notifier which takes notifier_lock under > +fs_reclaim > + * 5. Lockdep sees circular dependency with the false edge from > +amdgpu_lockdep_init > + * > + * Expected behavior: > + * - BEFORE kernel fix: lockdep splat in dmesg (test FAILS) > + * - AFTER kernel fix: no lockdep splat (test PASSES) */ static void > +test_notifier_reclaim_splat(int fd) { > + void *buf; > + struct drm_amdgpu_gem_userptr userptr = {0}; > + int ret; > + int kmsg_fd; > + bool violation_found = false; > + unsigned long taints = 0; > + > + igt_info("Creating %llu MiB anonymous buffer\n", USERPTR_BUF_SIZE / > +(1024 * 1024)); > + > + buf = mmap(NULL, USERPTR_BUF_SIZE, PROT_READ | PROT_WRITE, > + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); > + igt_assert(buf != MAP_FAILED); > + > + /* Fault all pages in */ > + igt_info("Faulting in all pages\n"); > + memset(buf, 0xa5, USERPTR_BUF_SIZE); > + > + /* Open kmsg to monitor for lockdep violations */ > + kmsg_fd = kmsg_open(); > + igt_assert(kmsg_fd >= 0); > + > + /* Register as userptr - this installs MMU notifier callback */ > + igt_info("Registering as userptr BO - installs MMU notifier\n"); > + userptr.addr = (uint64_t)(uintptr_t)buf; > + userptr.size = USERPTR_BUF_SIZE; > + userptr.flags = AMDGPU_GEM_USERPTR_ANONONLY | > + AMDGPU_GEM_USERPTR_REGISTER | /* Install > mmu_interval_notifier */ > + AMDGPU_GEM_USERPTR_VALIDATE; > + > + ret = igt_ioctl(fd, DRM_IOCTL_AMDGPU_GEM_USERPTR, &userptr); > + igt_assert_eq(ret, 0); > + > + igt_info("Forcing reclaim with MADV_PAGEOUT - triggers MMU notifier > +under fs_reclaim\n"); > + > + /* Force reclaim - this triggers the lockdep splat on vulnerable kernel */ > + for (int i = 0; i < PAGEOUT_ITERATIONS; i++) { > + igt_info(" Iteration %d/%d: madvise MADV_PAGEOUT\n", i + 1, > +PAGEOUT_ITERATIONS); > + > + ret = madvise(buf, USERPTR_BUF_SIZE, MADV_PAGEOUT); > + igt_assert_eq(ret, 0); > + > + usleep(50000); /* 50ms - give kernel time to process */ > + > + /* Check for lockdep violations */ > + if (kmsg_has_lockdep_violation(kmsg_fd)) { > + violation_found = true; > + igt_warn("LOCKDEP VIOLATION DETECTED during > iteration %d\n", i + 1); > + break; > + } > + > + /* Re-fault pages for next iteration */ > + memset(buf, 0xa5, USERPTR_BUF_SIZE); > + } > + > + close(kmsg_fd); > + > + if (violation_found) { > + igt_info("\n"); > + > igt_info("================================================ > ================\n"); > + igt_info("LOCKDEP SPLAT DETECTED - This is EXPECTED > before kernel fix\n"); > + > igt_info("================================================ > ================\n"); > + igt_info("\n"); > + igt_info("The kernel has a FALSE POSITIVE lockdep bug:\n"); > + igt_info(" File: drivers/gpu/drm/amd/amdgpu/amdgpu_lockdep.c\n"); > + igt_info(" Function: amdgpu_lockdep_init() around line 176\n"); > + igt_info(" Problem: fs_reclaim_acquire called while holding > notifier_lock\n"); > + igt_info("\n"); > + igt_info("This teaches lockdep a FALSE edge: notifier_lock -> > fs_reclaim\n"); > + igt_info("Runtime reality: fs_reclaim -> notifier_lock (opposite > direction)\n"); > + igt_info("\n"); > + igt_info("FIX: Move fs_reclaim_acquire to BEFORE all mutex > acquisitions\n"); > + igt_info(" in amdgpu_lockdep_init\n"); > + igt_info("\n"); > + igt_info("See: > /home/vprosyak/Documents/IGT/LOCKDEP_ISSUE/\n"); We should remove this debug log ? > + > igt_info("================================================ > ================\n"); > + igt_info("\n"); > + } else { > + igt_info("\n"); > + > igt_info("================================================ > ================\n"); > + igt_info("NO LOCKDEP VIOLATION - Kernel fix appears to be > working!\n"); > + > igt_info("================================================ > ================\n"); > + igt_info("\n"); > + } > + > + /* Cleanup */ [Zhang, Jesse(Jie)] Free the upserptr handle to prevent leakage.. { struct drm_gem_close gem_close = { .handle = userptr.handle }; igt_ioctl(fd, DRM_IOCTL_GEM_CLOSE, &gem_close); } > + munmap(buf, USERPTR_BUF_SIZE); > + > + /* Check kernel taint flags */ > + igt_kernel_tainted(&taints); > + igt_assert_f(!(taints & (1ul << TAINT_WARN)), > + "Kernel is tainted - lockdep violation detected\n"); } > + > + > int igt_main() > { > amdgpu_device_handle device; > @@ -522,6 +641,10 @@ int igt_main() > test_stress_all_paths(fd, device); > } > > + igt_describe("Michael Gavrilov reproducer: userptr + MADV_PAGEOUT > triggers fs_reclaim cycle"); > + igt_subtest("notifier-reclaim-splat") { > + test_notifier_reclaim_splat(fd); > + } > igt_fixture() { > amdgpu_device_deinitialize(device); > drm_close_driver(fd); > -- > 2.54.0