Skip to content

Commit 00619f7

Browse files
author
Peter Zijlstra
committed
sched,livepatch: Use task_call_func()
Instead of frobbing around with scheduler internals, use the shiny new task_call_func() interface. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Reviewed-by: Petr Mladek <pmladek@suse.com> Acked-by: Miroslav Benes <mbenes@suse.cz> Acked-by: Vasily Gorbik <gor@linux.ibm.com> Tested-by: Petr Mladek <pmladek@suse.com> Tested-by: Vasily Gorbik <gor@linux.ibm.com> # on s390 Link: https://lkml.kernel.org/r/20210929152428.709906138@infradead.org
1 parent 9b3c4ab commit 00619f7

File tree

1 file changed

+44
-46
lines changed

1 file changed

+44
-46
lines changed

kernel/livepatch/transition.c

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include "core.h"
1414
#include "patch.h"
1515
#include "transition.h"
16-
#include "../sched/sched.h"
1716

1817
#define MAX_STACK_ENTRIES 100
1918
#define STACK_ERR_BUF_SIZE 128
@@ -240,20 +239,16 @@ static int klp_check_stack_func(struct klp_func *func, unsigned long *entries,
240239
* Determine whether it's safe to transition the task to the target patch state
241240
* by looking for any to-be-patched or to-be-unpatched functions on its stack.
242241
*/
243-
static int klp_check_stack(struct task_struct *task, char *err_buf)
242+
static int klp_check_stack(struct task_struct *task, const char **oldname)
244243
{
245244
static unsigned long entries[MAX_STACK_ENTRIES];
246245
struct klp_object *obj;
247246
struct klp_func *func;
248247
int ret, nr_entries;
249248

250249
ret = stack_trace_save_tsk_reliable(task, entries, ARRAY_SIZE(entries));
251-
if (ret < 0) {
252-
snprintf(err_buf, STACK_ERR_BUF_SIZE,
253-
"%s: %s:%d has an unreliable stack\n",
254-
__func__, task->comm, task->pid);
255-
return ret;
256-
}
250+
if (ret < 0)
251+
return -EINVAL;
257252
nr_entries = ret;
258253

259254
klp_for_each_object(klp_transition_patch, obj) {
@@ -262,32 +257,40 @@ static int klp_check_stack(struct task_struct *task, char *err_buf)
262257
klp_for_each_func(obj, func) {
263258
ret = klp_check_stack_func(func, entries, nr_entries);
264259
if (ret) {
265-
snprintf(err_buf, STACK_ERR_BUF_SIZE,
266-
"%s: %s:%d is sleeping on function %s\n",
267-
__func__, task->comm, task->pid,
268-
func->old_name);
269-
return ret;
260+
*oldname = func->old_name;
261+
return -EADDRINUSE;
270262
}
271263
}
272264
}
273265

274266
return 0;
275267
}
276268

269+
static 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+
277285
/*
278286
* Try to safely switch a task to the target patch state. If it's currently
279287
* running, or it's sleeping on a to-be-patched or to-be-unpatched function, or
280288
* if the stack is unreliable, return false.
281289
*/
282290
static bool klp_try_switch_task(struct task_struct *task)
283291
{
284-
static char err_buf[STACK_ERR_BUF_SIZE];
285-
struct rq *rq;
286-
struct rq_flags flags;
292+
const char *old_name;
287293
int ret;
288-
bool success = false;
289-
290-
err_buf[0] = '\0';
291294

292295
/* check if this task has already switched over */
293296
if (task->patch_state == klp_target_state)
@@ -305,36 +308,31 @@ static bool klp_try_switch_task(struct task_struct *task)
305308
* functions. If all goes well, switch the task to the target patch
306309
* state.
307310
*/
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;
309315

310-
if (task_running(rq, task) && task != current) {
311-
snprintf(err_buf, STACK_ERR_BUF_SIZE,
312-
"%s: %s:%d is running\n", __func__, task->comm,
313-
task->pid);
314-
goto done;
316+
case -EBUSY: /* klp_check_and_switch_task() */
317+
pr_debug("%s: %s:%d is running\n",
318+
__func__, task->comm, task->pid);
319+
break;
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;
315333
}
316334

317-
ret = klp_check_stack(task, err_buf);
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-
326-
done:
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;
335+
return !ret;
338336
}
339337

340338
/*

0 commit comments

Comments
 (0)