| // 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 void busymod_work_func(struct work_struct *work) | 
 | { | 
 | 	pr_info("%s enter\n", __func__); | 
 |  | 
 | 	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); | 
 |  | 
 | 	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"); |