diff options
Diffstat (limited to 'kernel/livepatch/transition.c')
-rw-r--r-- | kernel/livepatch/transition.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/kernel/livepatch/transition.c b/kernel/livepatch/transition.c index edcfcb8ebb2d..be5bfa533ee8 100644 --- a/kernel/livepatch/transition.c +++ b/kernel/livepatch/transition.c | |||
@@ -33,6 +33,8 @@ struct klp_patch *klp_transition_patch; | |||
33 | 33 | ||
34 | static int klp_target_state = KLP_UNDEFINED; | 34 | static int klp_target_state = KLP_UNDEFINED; |
35 | 35 | ||
36 | static bool klp_forced = false; | ||
37 | |||
36 | /* | 38 | /* |
37 | * This work can be performed periodically to finish patching or unpatching any | 39 | * This work can be performed periodically to finish patching or unpatching any |
38 | * "straggler" tasks which failed to transition in the first attempt. | 40 | * "straggler" tasks which failed to transition in the first attempt. |
@@ -146,9 +148,12 @@ done: | |||
146 | /* | 148 | /* |
147 | * See complementary comment in __klp_enable_patch() for why we | 149 | * See complementary comment in __klp_enable_patch() for why we |
148 | * keep the module reference for immediate patches. | 150 | * keep the module reference for immediate patches. |
151 | * | ||
152 | * klp_forced or immediate_func set implies unbounded increase of | ||
153 | * module's ref count if the module is disabled/enabled in a loop. | ||
149 | */ | 154 | */ |
150 | if (!klp_transition_patch->immediate && !immediate_func && | 155 | if (!klp_forced && !klp_transition_patch->immediate && |
151 | klp_target_state == KLP_UNPATCHED) { | 156 | !immediate_func && klp_target_state == KLP_UNPATCHED) { |
152 | module_put(klp_transition_patch->mod); | 157 | module_put(klp_transition_patch->mod); |
153 | } | 158 | } |
154 | 159 | ||
@@ -649,3 +654,30 @@ void klp_send_signals(void) | |||
649 | } | 654 | } |
650 | read_unlock(&tasklist_lock); | 655 | read_unlock(&tasklist_lock); |
651 | } | 656 | } |
657 | |||
658 | /* | ||
659 | * Drop TIF_PATCH_PENDING of all tasks on admin's request. This forces an | ||
660 | * existing transition to finish. | ||
661 | * | ||
662 | * NOTE: klp_update_patch_state(task) requires the task to be inactive or | ||
663 | * 'current'. This is not the case here and the consistency model could be | ||
664 | * broken. Administrator, who is the only one to execute the | ||
665 | * klp_force_transitions(), has to be aware of this. | ||
666 | */ | ||
667 | void klp_force_transition(void) | ||
668 | { | ||
669 | struct task_struct *g, *task; | ||
670 | unsigned int cpu; | ||
671 | |||
672 | pr_warn("forcing remaining tasks to the patched state\n"); | ||
673 | |||
674 | read_lock(&tasklist_lock); | ||
675 | for_each_process_thread(g, task) | ||
676 | klp_update_patch_state(task); | ||
677 | read_unlock(&tasklist_lock); | ||
678 | |||
679 | for_each_possible_cpu(cpu) | ||
680 | klp_update_patch_state(idle_task(cpu)); | ||
681 | |||
682 | klp_forced = true; | ||
683 | } | ||