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