18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci// Copyright (C) 2018 Joe Lawrence <joe.lawrence@redhat.com>
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/module.h>
78c2ecf20Sopenharmony_ci#include <linux/kernel.h>
88c2ecf20Sopenharmony_ci#include <linux/sched.h>
98c2ecf20Sopenharmony_ci#include <linux/workqueue.h>
108c2ecf20Sopenharmony_ci#include <linux/delay.h>
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci/* load/run-time control from sysfs writer  */
138c2ecf20Sopenharmony_cistatic bool block_transition;
148c2ecf20Sopenharmony_cimodule_param(block_transition, bool, 0644);
158c2ecf20Sopenharmony_ciMODULE_PARM_DESC(block_transition, "block_transition (default=false)");
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic void busymod_work_func(struct work_struct *work);
188c2ecf20Sopenharmony_cistatic DECLARE_WORK(work, busymod_work_func);
198c2ecf20Sopenharmony_cistatic DECLARE_COMPLETION(busymod_work_started);
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_cistatic void busymod_work_func(struct work_struct *work)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	pr_info("%s enter\n", __func__);
248c2ecf20Sopenharmony_ci	complete(&busymod_work_started);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	while (READ_ONCE(block_transition)) {
278c2ecf20Sopenharmony_ci		/*
288c2ecf20Sopenharmony_ci		 * Busy-wait until the sysfs writer has acknowledged a
298c2ecf20Sopenharmony_ci		 * blocked transition and clears the flag.
308c2ecf20Sopenharmony_ci		 */
318c2ecf20Sopenharmony_ci		msleep(20);
328c2ecf20Sopenharmony_ci	}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	pr_info("%s exit\n", __func__);
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic int test_klp_callbacks_busy_init(void)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	pr_info("%s\n", __func__);
408c2ecf20Sopenharmony_ci	schedule_work(&work);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	/*
438c2ecf20Sopenharmony_ci	 * To synchronize kernel messages, hold the init function from
448c2ecf20Sopenharmony_ci	 * exiting until the work function's entry message has printed.
458c2ecf20Sopenharmony_ci	 */
468c2ecf20Sopenharmony_ci	wait_for_completion(&busymod_work_started);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	if (!block_transition) {
498c2ecf20Sopenharmony_ci		/*
508c2ecf20Sopenharmony_ci		 * Serialize output: print all messages from the work
518c2ecf20Sopenharmony_ci		 * function before returning from init().
528c2ecf20Sopenharmony_ci		 */
538c2ecf20Sopenharmony_ci		flush_work(&work);
548c2ecf20Sopenharmony_ci	}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	return 0;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic void test_klp_callbacks_busy_exit(void)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	WRITE_ONCE(block_transition, false);
628c2ecf20Sopenharmony_ci	flush_work(&work);
638c2ecf20Sopenharmony_ci	pr_info("%s\n", __func__);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cimodule_init(test_klp_callbacks_busy_init);
678c2ecf20Sopenharmony_cimodule_exit(test_klp_callbacks_busy_exit);
688c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
698c2ecf20Sopenharmony_ciMODULE_AUTHOR("Joe Lawrence <joe.lawrence@redhat.com>");
708c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Livepatch test: busy target module");
71