mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-26 10:49:33 +00:00
![Joe Lawrence](/assets/img/avatar_default.png)
The test_klp_callbacks_busy module conditionally blocks a future
livepatch transition by busy waiting inside its workqueue function,
busymod_work_func(). After scheduling this work, a test livepatch is
loaded, introducing the transition under test.
Both events are marked in the kernel log for later verification, but
there is no synchronization to ensure that busymod_work_func() logs its
function entry message before subsequent selftest commands log their own
messages. This can lead to a rare test failure due to unexpected
ordering like:
--- expected
+++ result
@@ -1,7 +1,7 @@
% modprobe test_klp_callbacks_busy block_transition=Y
test_klp_callbacks_busy: test_klp_callbacks_busy_init
-test_klp_callbacks_busy: busymod_work_func enter
% modprobe test_klp_callbacks_demo
+test_klp_callbacks_busy: busymod_work_func enter
livepatch: enabling patch 'test_klp_callbacks_demo'
livepatch: 'test_klp_callbacks_demo': initializing patching transition
test_klp_callbacks_demo: pre_patch_callback: vmlinux
Force the module init function to wait until busymod_work_func() has
started (and logged its message), before exiting to the next selftest
steps.
Fixes: 547840bd5a
("selftests/livepatch: simplify test-klp-callbacks busy target tests")
Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20220602203233.979681-1-joe.lawrence@redhat.com
70 lines
1.7 KiB
C
70 lines
1.7 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
// Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com>
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/workqueue.h>
|
|
#include <linux/delay.h>
|
|
|
|
/* load/run-time control from sysfs writer */
|
|
static bool block_transition;
|
|
module_param(block_transition, bool, 0644);
|
|
MODULE_PARM_DESC(block_transition, "block_transition (default=false)");
|
|
|
|
static void busymod_work_func(struct work_struct *work);
|
|
static DECLARE_WORK(work, busymod_work_func);
|
|
static DECLARE_COMPLETION(busymod_work_started);
|
|
|
|
static void busymod_work_func(struct work_struct *work)
|
|
{
|
|
pr_info("%s enter\n", __func__);
|
|
complete(&busymod_work_started);
|
|
|
|
while (READ_ONCE(block_transition)) {
|
|
/*
|
|
* Busy-wait until the sysfs writer has acknowledged a
|
|
* blocked transition and clears the flag.
|
|
*/
|
|
msleep(20);
|
|
}
|
|
|
|
pr_info("%s exit\n", __func__);
|
|
}
|
|
|
|
static int test_klp_callbacks_busy_init(void)
|
|
{
|
|
pr_info("%s\n", __func__);
|
|
schedule_work(&work);
|
|
|
|
/*
|
|
* To synchronize kernel messages, hold the init function from
|
|
* exiting until the work function's entry message has printed.
|
|
*/
|
|
wait_for_completion(&busymod_work_started);
|
|
|
|
if (!block_transition) {
|
|
/*
|
|
* Serialize output: print all messages from the work
|
|
* function before returning from init().
|
|
*/
|
|
flush_work(&work);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void test_klp_callbacks_busy_exit(void)
|
|
{
|
|
WRITE_ONCE(block_transition, false);
|
|
flush_work(&work);
|
|
pr_info("%s\n", __func__);
|
|
}
|
|
|
|
module_init(test_klp_callbacks_busy_init);
|
|
module_exit(test_klp_callbacks_busy_exit);
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>");
|
|
MODULE_DESCRIPTION("Livepatch test: busy target module");
|