diff options
Diffstat (limited to 'kernel/livepatch/transition.c')
-rw-r--r-- | kernel/livepatch/transition.c | 45 |
1 files changed, 38 insertions, 7 deletions
diff --git a/kernel/livepatch/transition.c b/kernel/livepatch/transition.c index b004a1fb6032..56add6327736 100644 --- a/kernel/livepatch/transition.c +++ b/kernel/livepatch/transition.c | |||
@@ -82,6 +82,10 @@ static void klp_complete_transition(void) | |||
82 | unsigned int cpu; | 82 | unsigned int cpu; |
83 | bool immediate_func = false; | 83 | bool immediate_func = false; |
84 | 84 | ||
85 | pr_debug("'%s': completing %s transition\n", | ||
86 | klp_transition_patch->mod->name, | ||
87 | klp_target_state == KLP_PATCHED ? "patching" : "unpatching"); | ||
88 | |||
85 | if (klp_target_state == KLP_UNPATCHED) { | 89 | if (klp_target_state == KLP_UNPATCHED) { |
86 | /* | 90 | /* |
87 | * All tasks have transitioned to KLP_UNPATCHED so we can now | 91 | * All tasks have transitioned to KLP_UNPATCHED so we can now |
@@ -109,9 +113,6 @@ static void klp_complete_transition(void) | |||
109 | } | 113 | } |
110 | } | 114 | } |
111 | 115 | ||
112 | if (klp_target_state == KLP_UNPATCHED && !immediate_func) | ||
113 | module_put(klp_transition_patch->mod); | ||
114 | |||
115 | /* Prevent klp_ftrace_handler() from seeing KLP_UNDEFINED state */ | 116 | /* Prevent klp_ftrace_handler() from seeing KLP_UNDEFINED state */ |
116 | if (klp_target_state == KLP_PATCHED) | 117 | if (klp_target_state == KLP_PATCHED) |
117 | klp_synchronize_transition(); | 118 | klp_synchronize_transition(); |
@@ -130,6 +131,27 @@ static void klp_complete_transition(void) | |||
130 | } | 131 | } |
131 | 132 | ||
132 | done: | 133 | done: |
134 | klp_for_each_object(klp_transition_patch, obj) { | ||
135 | if (!klp_is_object_loaded(obj)) | ||
136 | continue; | ||
137 | if (klp_target_state == KLP_PATCHED) | ||
138 | klp_post_patch_callback(obj); | ||
139 | else if (klp_target_state == KLP_UNPATCHED) | ||
140 | klp_post_unpatch_callback(obj); | ||
141 | } | ||
142 | |||
143 | pr_notice("'%s': %s complete\n", klp_transition_patch->mod->name, | ||
144 | klp_target_state == KLP_PATCHED ? "patching" : "unpatching"); | ||
145 | |||
146 | /* | ||
147 | * See complementary comment in __klp_enable_patch() for why we | ||
148 | * keep the module reference for immediate patches. | ||
149 | */ | ||
150 | if (!klp_transition_patch->immediate && !immediate_func && | ||
151 | klp_target_state == KLP_UNPATCHED) { | ||
152 | module_put(klp_transition_patch->mod); | ||
153 | } | ||
154 | |||
133 | klp_target_state = KLP_UNDEFINED; | 155 | klp_target_state = KLP_UNDEFINED; |
134 | klp_transition_patch = NULL; | 156 | klp_transition_patch = NULL; |
135 | } | 157 | } |
@@ -145,6 +167,9 @@ void klp_cancel_transition(void) | |||
145 | if (WARN_ON_ONCE(klp_target_state != KLP_PATCHED)) | 167 | if (WARN_ON_ONCE(klp_target_state != KLP_PATCHED)) |
146 | return; | 168 | return; |
147 | 169 | ||
170 | pr_debug("'%s': canceling patching transition, going to unpatch\n", | ||
171 | klp_transition_patch->mod->name); | ||
172 | |||
148 | klp_target_state = KLP_UNPATCHED; | 173 | klp_target_state = KLP_UNPATCHED; |
149 | klp_complete_transition(); | 174 | klp_complete_transition(); |
150 | } | 175 | } |
@@ -408,9 +433,6 @@ void klp_try_complete_transition(void) | |||
408 | } | 433 | } |
409 | 434 | ||
410 | success: | 435 | success: |
411 | pr_notice("'%s': %s complete\n", klp_transition_patch->mod->name, | ||
412 | klp_target_state == KLP_PATCHED ? "patching" : "unpatching"); | ||
413 | |||
414 | /* we're done, now cleanup the data structures */ | 436 | /* we're done, now cleanup the data structures */ |
415 | klp_complete_transition(); | 437 | klp_complete_transition(); |
416 | } | 438 | } |
@@ -426,7 +448,8 @@ void klp_start_transition(void) | |||
426 | 448 | ||
427 | WARN_ON_ONCE(klp_target_state == KLP_UNDEFINED); | 449 | WARN_ON_ONCE(klp_target_state == KLP_UNDEFINED); |
428 | 450 | ||
429 | pr_notice("'%s': %s...\n", klp_transition_patch->mod->name, | 451 | pr_notice("'%s': starting %s transition\n", |
452 | klp_transition_patch->mod->name, | ||
430 | klp_target_state == KLP_PATCHED ? "patching" : "unpatching"); | 453 | klp_target_state == KLP_PATCHED ? "patching" : "unpatching"); |
431 | 454 | ||
432 | /* | 455 | /* |
@@ -482,6 +505,9 @@ void klp_init_transition(struct klp_patch *patch, int state) | |||
482 | */ | 505 | */ |
483 | klp_target_state = state; | 506 | klp_target_state = state; |
484 | 507 | ||
508 | pr_debug("'%s': initializing %s transition\n", patch->mod->name, | ||
509 | klp_target_state == KLP_PATCHED ? "patching" : "unpatching"); | ||
510 | |||
485 | /* | 511 | /* |
486 | * If the patch can be applied or reverted immediately, skip the | 512 | * If the patch can be applied or reverted immediately, skip the |
487 | * per-task transitions. | 513 | * per-task transitions. |
@@ -547,6 +573,11 @@ void klp_reverse_transition(void) | |||
547 | unsigned int cpu; | 573 | unsigned int cpu; |
548 | struct task_struct *g, *task; | 574 | struct task_struct *g, *task; |
549 | 575 | ||
576 | pr_debug("'%s': reversing transition from %s\n", | ||
577 | klp_transition_patch->mod->name, | ||
578 | klp_target_state == KLP_PATCHED ? "patching to unpatching" : | ||
579 | "unpatching to patching"); | ||
580 | |||
550 | klp_transition_patch->enabled = !klp_transition_patch->enabled; | 581 | klp_transition_patch->enabled = !klp_transition_patch->enabled; |
551 | 582 | ||
552 | klp_target_state = !klp_target_state; | 583 | klp_target_state = !klp_target_state; |