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
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,7 +239,7 @@ static int klp_check_stack_func(struct klp_func *func, unsigned long *entries, · 220 unmodified lines
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;
@@ -248,12 +247,8 @@ static int klp_check_stack(struct task_struct *task, char *err_buf) · 1 unmodified line
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,11 +257,8 @@ static int klp_check_stack(struct task_struct *task, char *err_buf) · 2 unmodified lines
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 }
@@ -274,6 +266,22 @@ static int klp_check_stack(struct task_struct *task, char *err_buf) · 1 unmodified line
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
@@ -281,13 +289,8 @@ static int klp_check_stack(struct task_struct *task, char *err_buf) · 1 unmodified line
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) · 11 unmodified lines
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 /*