History

sched,livepatch: Use task_call_func()

Instead of frobbing around with scheduler internals, use the shiny new task_call_func() interface.

Peter Zijlstra committed 5 years ago

Commit 00619f71 parent 9b3c4ab1 file · +44 −46Browse files

Showing the changes to kernel/livepatch (1 of 1 file). Show all

Unified · Split

kernel/livepatch/transition.c+44−46
@@ -13,7 +13,6 @@ · 12 unmodified lines
13#include "core.h"13#include "core.h"
14#include "patch.h"14#include "patch.h"
15#include "transition.h"15#include "transition.h"
16#include "../sched/sched.h"
17 16
18#define MAX_STACK_ENTRIES 10017#define MAX_STACK_ENTRIES 100
19#define STACK_ERR_BUF_SIZE 12818#define STACK_ERR_BUF_SIZE 128
@@ -240,7 +239,7 @@ static int klp_check_stack_func(struct klp_func *func, unsigned long *entries, · 220 unmodified lines
240 * Determine whether it's safe to transition the task to the target patch state239 * Determine whether it's safe to transition the task to the target patch state
241 * by looking for any to-be-patched or to-be-unpatched functions on its stack.240 * by looking for any to-be-patched or to-be-unpatched functions on its stack.
242 */241 */
243static int klp_check_stack(struct task_struct *task, char *err_buf)242static int klp_check_stack(struct task_struct *task, const char **oldname)
244{243{
245 static unsigned long entries[MAX_STACK_ENTRIES];244 static unsigned long entries[MAX_STACK_ENTRIES];
246 struct klp_object *obj;245 struct klp_object *obj;
@@ -248,12 +247,8 @@ static int klp_check_stack(struct task_struct *task, char *err_buf) · 1 unmodified line
248 int ret, nr_entries;247 int ret, nr_entries;
249 248
250 ret = stack_trace_save_tsk_reliable(task, entries, ARRAY_SIZE(entries));249 ret = stack_trace_save_tsk_reliable(task, entries, ARRAY_SIZE(entries));
251 if (ret < 0) {250 if (ret < 0)
252 snprintf(err_buf, STACK_ERR_BUF_SIZE,251 return -EINVAL;
253 "%s: %s:%d has an unreliable stack\n",
254 __func__, task->comm, task->pid);
255 return ret;
256 }
257 nr_entries = ret;252 nr_entries = ret;
258 253
259 klp_for_each_object(klp_transition_patch, obj) {254 klp_for_each_object(klp_transition_patch, obj) {
@@ -262,11 +257,8 @@ static int klp_check_stack(struct task_struct *task, char *err_buf) · 2 unmodified lines
262 klp_for_each_func(obj, func) {257 klp_for_each_func(obj, func) {
263 ret = klp_check_stack_func(func, entries, nr_entries);258 ret = klp_check_stack_func(func, entries, nr_entries);
264 if (ret) {259 if (ret) {
265 snprintf(err_buf, STACK_ERR_BUF_SIZE,260 *oldname = func->old_name;
266 "%s: %s:%d is sleeping on function %s\n",261 return -EADDRINUSE;
267 __func__, task->comm, task->pid,
268 func->old_name);
269 return ret;
270 }262 }
271 }263 }
272 }264 }
@@ -274,6 +266,22 @@ static int klp_check_stack(struct task_struct *task, char *err_buf) · 1 unmodified line
274 return 0;266 return 0;
275}267}
276 268
269static int klp_check_and_switch_task(struct task_struct *task, void *arg)
270{
271 int ret;
272
273 if (task_curr(task) && task != current)
274 return -EBUSY;
275
276 ret = klp_check_stack(task, arg);
277 if (ret)
278 return ret;
279
280 clear_tsk_thread_flag(task, TIF_PATCH_PENDING);
281 task->patch_state = klp_target_state;
282 return 0;
283}
284
277/*285/*
278 * Try to safely switch a task to the target patch state. If it's currently286 * Try to safely switch a task to the target patch state. If it's currently
279 * running, or it's sleeping on a to-be-patched or to-be-unpatched function, or287 * running, or it's sleeping on a to-be-patched or to-be-unpatched function, or
@@ -281,13 +289,8 @@ static int klp_check_stack(struct task_struct *task, char *err_buf) · 1 unmodified line
281 */289 */
282static bool klp_try_switch_task(struct task_struct *task)290static bool klp_try_switch_task(struct task_struct *task)
283{291{
284 static char err_buf[STACK_ERR_BUF_SIZE];292 const char *old_name;
285 struct rq *rq;
286 struct rq_flags flags;
287 int ret;293 int ret;
288 bool success = false;
289
290 err_buf[0] = '\0';
291 294
292 /* check if this task has already switched over */295 /* check if this task has already switched over */
293 if (task->patch_state == klp_target_state)296 if (task->patch_state == klp_target_state)
@@ -305,36 +308,31 @@ static bool klp_try_switch_task(struct task_struct *task) · 11 unmodified lines
305 * functions. If all goes well, switch the task to the target patch308 * functions. If all goes well, switch the task to the target patch
306 * state.309 * state.
307 */310 */
308 rq = task_rq_lock(task, &flags);311 ret = task_call_func(task, klp_check_and_switch_task, &old_name);
312 switch (ret) {
313 case 0: /* success */
314 break;
309 315
310 if (task_running(rq, task) && task != current) {316 case -EBUSY: /* klp_check_and_switch_task() */
311 snprintf(err_buf, STACK_ERR_BUF_SIZE,317 pr_debug("%s: %s:%d is running\n",
312 "%s: %s:%d is running\n", __func__, task->comm,318 __func__, task->comm, task->pid);
313 task->pid);319 break;
314 goto done;320 case -EINVAL: /* klp_check_and_switch_task() */
321 pr_debug("%s: %s:%d has an unreliable stack\n",
322 __func__, task->comm, task->pid);
323 break;
324 case -EADDRINUSE: /* klp_check_and_switch_task() */
325 pr_debug("%s: %s:%d is sleeping on function %s\n",
326 __func__, task->comm, task->pid, old_name);
327 break;
328
329 default:
330 pr_debug("%s: Unknown error code (%d) when trying to switch %s:%d\n",
331 __func__, ret, task->comm, task->pid);
332 break;
315 }333 }
316 334
317 ret = klp_check_stack(task, err_buf);335 return !ret;
318 if (ret)
319 goto done;
320
321 success = true;
322
323 clear_tsk_thread_flag(task, TIF_PATCH_PENDING);
324 task->patch_state = klp_target_state;
325
326done:
327 task_rq_unlock(rq, task, &flags);
328
329 /*
330 * Due to console deadlock issues, pr_debug() can't be used while
331 * holding the task rq lock. Instead we have to use a temporary buffer
332 * and print the debug message after releasing the lock.
333 */
334 if (err_buf[0] != '\0')
335 pr_debug("%s", err_buf);
336
337 return success;
338}336}
339 337
340/*338/*