Instead of frobbing around with scheduler internals, use the shiny new task_call_func() interface.
Showing the changes to kernel/livepatch (1 of 1 file). Show all
Unified · Split
| @@ -13,7 +13,6 @@ · 12 unmodified lines | ||
| 13 | 13 | #include "core.h" |
| 14 | 14 | #include "patch.h" |
| 15 | 15 | #include "transition.h" |
| 16 | −#include "../sched/sched.h" | |
| 17 | 16 | |
| 18 | 17 | #define MAX_STACK_ENTRIES 100 |
| 19 | 18 | #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 | 239 | * Determine whether it's safe to transition the task to the target patch state |
| 241 | 240 | * by looking for any to-be-patched or to-be-unpatched functions on its stack. |
| 242 | 241 | */ |
| 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) | |
| 244 | 243 | { |
| 245 | 244 | static unsigned long entries[MAX_STACK_ENTRIES]; |
| 246 | 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 | 247 | int ret, nr_entries; |
| 249 | 248 | |
| 250 | 249 | 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; | |
| 257 | 252 | nr_entries = ret; |
| 258 | 253 | |
| 259 | 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 | 257 | klp_for_each_func(obj, func) { |
| 263 | 258 | ret = klp_check_stack_func(func, entries, nr_entries); |
| 264 | 259 | 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; | |
| 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 | 266 | return 0; |
| 275 | 267 | } |
| 276 | 268 | |
| 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 | + | |
| 277 | 285 | /* |
| 278 | 286 | * Try to safely switch a task to the target patch state. If it's currently |
| 279 | 287 | * 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 | */ |
| 282 | 290 | static bool klp_try_switch_task(struct task_struct *task) |
| 283 | 291 | { |
| 284 | − static char err_buf[STACK_ERR_BUF_SIZE]; | |
| 285 | − struct rq *rq; | |
| 286 | − struct rq_flags flags; | |
| 292 | + const char *old_name; | |
| 287 | 293 | int ret; |
| 288 | − bool success = false; | |
| 289 | − | |
| 290 | − err_buf[0] = '\0'; | |
| 291 | 294 | |
| 292 | 295 | /* check if this task has already switched over */ |
| 293 | 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 | 308 | * functions. If all goes well, switch the task to the target patch |
| 306 | 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) { | |
| 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; | |
| 315 | 333 | } |
| 316 | 334 | |
| 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; | |
| 338 | 336 | } |
| 339 | 337 | |
| 340 | 338 | /* |