Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

locking/ww_mutex/test: Fix potential workqueue corruption

In some cases running with the test-ww_mutex code, I was seeing
odd behavior where sometimes it seemed flush_workqueue was
returning before all the work threads were finished.

Often this would cause strange crashes as the mutexes would be
freed while they were being used.

Looking at the code, there is a lifetime problem as the
controlling thread that spawns the work allocates the
"struct stress" structures that are passed to the workqueue
threads. Then when the workqueue threads are finished,
they free the stress struct that was passed to them.

Unfortunately the workqueue work_struct node is in the stress
struct. Which means the work_struct is freed before the work
thread returns and while flush_workqueue is waiting.

It seems like a better idea to have the controlling thread
both allocate and free the stress structures, so that we can
be sure we don't corrupt the workqueue by freeing the structure
prematurely.

So this patch reworks the test to do so, and with this change
I no longer see the early flush_workqueue returns.

Signed-off-by: John Stultz <jstultz@google.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://lore.kernel.org/r/20230922043616.19282-3-jstultz@google.com

authored by

John Stultz and committed by
Ingo Molnar
bccdd808 4812c54d

+12 -8
+12 -8
kernel/locking/test-ww_mutex.c
··· 479 479 } while (!time_after(jiffies, stress->timeout)); 480 480 481 481 kfree(order); 482 - kfree(stress); 483 482 } 484 483 485 484 struct reorder_lock { ··· 543 544 list_for_each_entry_safe(ll, ln, &locks, link) 544 545 kfree(ll); 545 546 kfree(order); 546 - kfree(stress); 547 547 } 548 548 549 549 static void stress_one_work(struct work_struct *work) ··· 563 565 break; 564 566 } 565 567 } while (!time_after(jiffies, stress->timeout)); 566 - 567 - kfree(stress); 568 568 } 569 569 570 570 #define STRESS_INORDER BIT(0) ··· 573 577 static int stress(int nlocks, int nthreads, unsigned int flags) 574 578 { 575 579 struct ww_mutex *locks; 576 - int n; 580 + struct stress *stress_array; 581 + int n, count; 577 582 578 583 locks = kmalloc_array(nlocks, sizeof(*locks), GFP_KERNEL); 579 584 if (!locks) 580 585 return -ENOMEM; 581 586 587 + stress_array = kmalloc_array(nthreads, sizeof(*stress_array), 588 + GFP_KERNEL); 589 + if (!stress_array) { 590 + kfree(locks); 591 + return -ENOMEM; 592 + } 593 + 582 594 for (n = 0; n < nlocks; n++) 583 595 ww_mutex_init(&locks[n], &ww_class); 584 596 597 + count = 0; 585 598 for (n = 0; nthreads; n++) { 586 599 struct stress *stress; 587 600 void (*fn)(struct work_struct *work); ··· 614 609 if (!fn) 615 610 continue; 616 611 617 - stress = kmalloc(sizeof(*stress), GFP_KERNEL); 618 - if (!stress) 619 - break; 612 + stress = &stress_array[count++]; 620 613 621 614 INIT_WORK(&stress->work, fn); 622 615 stress->locks = locks; ··· 629 626 630 627 for (n = 0; n < nlocks; n++) 631 628 ww_mutex_destroy(&locks[n]); 629 + kfree(stress_array); 632 630 kfree(locks); 633 631 634 632 return 0;