summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiroslav Benes <mbenes@suse.cz>2019-01-15 11:45:06 -0500
committerJiri Kosina <jkosina@suse.cz>2019-01-16 16:09:09 -0500
commitcba82dea30613346cf9a0532a41fc118bc3263af (patch)
treec7b4182b5f7bc83b646eae084d4a6646f3da874b
parenta2818ee4dce575b299d8a7f46b393bc2b02ef1f4 (diff)
livepatch: Send a fake signal periodically
An administrator may send a fake signal to all remaining blocking tasks of a running transition by writing to /sys/kernel/livepatch/<patch>/signal attribute. Let's do it automatically after 15 seconds. The timeout is chosen deliberately. It gives the tasks enough time to transition themselves. Theoretically, sending it once should be more than enough. However, every task must get outside of a patched function to be successfully transitioned. It could prove not to be simple and resending could be helpful in that case. A new workqueue job could be a cleaner solution to achieve it, but it could also introduce deadlocks and cause more headaches with synchronization and cancelling. [jkosina@suse.cz: removed added newline] Signed-off-by: Miroslav Benes <mbenes@suse.cz> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r--Documentation/livepatch/livepatch.txt3
-rw-r--r--kernel/livepatch/transition.c16
2 files changed, 15 insertions, 4 deletions
diff --git a/Documentation/livepatch/livepatch.txt b/Documentation/livepatch/livepatch.txt
index 71d7f286ec4d..407e0f03dc99 100644
--- a/Documentation/livepatch/livepatch.txt
+++ b/Documentation/livepatch/livepatch.txt
@@ -163,7 +163,8 @@ patched state. This may be harmful to the system though.
163Writing 1 to the attribute sends a fake signal to all remaining blocking 163Writing 1 to the attribute sends a fake signal to all remaining blocking
164tasks. No proper signal is actually delivered (there is no data in signal 164tasks. No proper signal is actually delivered (there is no data in signal
165pending structures). Tasks are interrupted or woken up, and forced to change 165pending structures). Tasks are interrupted or woken up, and forced to change
166their patched state. 166their patched state. Despite the sysfs attribute the fake signal is also sent
167every 15 seconds automatically.
167 168
168Administrator can also affect a transition through 169Administrator can also affect a transition through
169/sys/kernel/livepatch/<patch>/force attribute. Writing 1 there clears 170/sys/kernel/livepatch/<patch>/force attribute. Writing 1 there clears
diff --git a/kernel/livepatch/transition.c b/kernel/livepatch/transition.c
index 300273819674..ea7697bb753e 100644
--- a/kernel/livepatch/transition.c
+++ b/kernel/livepatch/transition.c
@@ -29,10 +29,14 @@
29#define MAX_STACK_ENTRIES 100 29#define MAX_STACK_ENTRIES 100
30#define STACK_ERR_BUF_SIZE 128 30#define STACK_ERR_BUF_SIZE 128
31 31
32#define SIGNALS_TIMEOUT 15
33
32struct klp_patch *klp_transition_patch; 34struct klp_patch *klp_transition_patch;
33 35
34static int klp_target_state = KLP_UNDEFINED; 36static int klp_target_state = KLP_UNDEFINED;
35 37
38static unsigned int klp_signals_cnt;
39
36/* 40/*
37 * This work can be performed periodically to finish patching or unpatching any 41 * This work can be performed periodically to finish patching or unpatching any
38 * "straggler" tasks which failed to transition in the first attempt. 42 * "straggler" tasks which failed to transition in the first attempt.
@@ -393,6 +397,10 @@ void klp_try_complete_transition(void)
393 put_online_cpus(); 397 put_online_cpus();
394 398
395 if (!complete) { 399 if (!complete) {
400 if (klp_signals_cnt && !(klp_signals_cnt % SIGNALS_TIMEOUT))
401 klp_send_signals();
402 klp_signals_cnt++;
403
396 /* 404 /*
397 * Some tasks weren't able to be switched over. Try again 405 * Some tasks weren't able to be switched over. Try again
398 * later and/or wait for other methods like kernel exit 406 * later and/or wait for other methods like kernel exit
@@ -454,6 +462,8 @@ void klp_start_transition(void)
454 if (task->patch_state != klp_target_state) 462 if (task->patch_state != klp_target_state)
455 set_tsk_thread_flag(task, TIF_PATCH_PENDING); 463 set_tsk_thread_flag(task, TIF_PATCH_PENDING);
456 } 464 }
465
466 klp_signals_cnt = 0;
457} 467}
458 468
459/* 469/*
@@ -578,14 +588,14 @@ void klp_copy_process(struct task_struct *child)
578 588
579/* 589/*
580 * Sends a fake signal to all non-kthread tasks with TIF_PATCH_PENDING set. 590 * Sends a fake signal to all non-kthread tasks with TIF_PATCH_PENDING set.
581 * Kthreads with TIF_PATCH_PENDING set are woken up. Only admin can request this 591 * Kthreads with TIF_PATCH_PENDING set are woken up.
582 * action currently.
583 */ 592 */
584void klp_send_signals(void) 593void klp_send_signals(void)
585{ 594{
586 struct task_struct *g, *task; 595 struct task_struct *g, *task;
587 596
588 pr_notice("signaling remaining tasks\n"); 597 if (klp_signals_cnt == SIGNALS_TIMEOUT)
598 pr_notice("signaling remaining tasks\n");
589 599
590 read_lock(&tasklist_lock); 600 read_lock(&tasklist_lock);
591 for_each_process_thread(g, task) { 601 for_each_process_thread(g, task) {