diff options
author | Miroslav Benes <mbenes@suse.cz> | 2016-11-23 11:16:50 +0100 |
---|---|---|
committer | Jiri Slaby <jslaby@suse.cz> | 2016-11-24 15:57:54 +0100 |
commit | 5b273d777befa4d14e35dcf6860f73b667b59942 (patch) | |
tree | 96c8c1e9c31fd573c5f8efec63f2e9a719130796 | |
parent | 594f072218a72977a9e567f22581414da9845143 (diff) | |
download | kgraft.tar.gz |
kgr: ignore zombie tasks during the patchingkgraft
There is no special treatment of zombie tasks in kGraft. This means that
they can block the patching process almost infinitely if their
TIF_KGR_IN_PROGRESS flag is set, because they cannot run anymore and
cannot clear the flag.
Simple reproducer:
# echo 'main() { if(fork()) sleep(300); }' > zombie.c
# gcc -o zombie zombie.c
# ./zombie &
# ps xa | fgrep Z
# zypper in -t pattern lp_sles
... installation running
# kgr status
in_progress
# kgr -vv blocking
2705 [zombie]
[<ffffffff8105b877>] do_exit+0x6f7/0xa80
[<ffffffff8105bc79>] do_group_exit+0x39/0xa0
[<ffffffff8105bcf0>] __wake_up_parent+0x0/0x30
[<ffffffff8152dd09>] system_call_fastpath+0x16/0x1b
[<00007fd128f9c4f9>] 0x7fd128f9c4f9
[<ffffffffffffffff>] 0xffffffffffffffff
Let's ignore the zombie tasks in kgr_still_patching() check. Such task
is in TASK_DEAD state. We also need to be sure that the task is not
running anymore. Otherwise there would be unpleasant race conditions. So
also check task's ->on_cpu. It is set to 0 by the next task in
finish_lock_switch().
Signed-off-by: Miroslav Benes <mbenes@suse.cz>
Acked-by: Jiri Kosina <jkosina@suse.cz>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
-rw-r--r-- | kernel/kgraft.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/kernel/kgraft.c b/kernel/kgraft.c index 08d27a47583b2d..fdf6b10ac23163 100644 --- a/kernel/kgraft.c +++ b/kernel/kgraft.c @@ -151,7 +151,13 @@ static bool kgr_still_patching(void) read_lock(&tasklist_lock); for_each_process_thread(p, t) { - if (kgr_task_in_progress(t)) { + /* + * Ignore zombie tasks, that is task with ->state == TASK_DEAD. + * We also need to check their ->on_cpu to be sure that they are + * not running any code and they are really almost dead. + */ + if (kgr_task_in_progress(t) && (t->state != TASK_DEAD || + t->on_cpu != 0)) { failed = true; goto unlock; } |