Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

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