aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiroslav Benes <mbenes@suse.cz>2016-11-23 11:16:50 +0100
committerJiri Slaby <jslaby@suse.cz>2016-11-24 15:57:54 +0100
commit5b273d777befa4d14e35dcf6860f73b667b59942 (patch)
tree96c8c1e9c31fd573c5f8efec63f2e9a719130796
parent594f072218a72977a9e567f22581414da9845143 (diff)
downloadkgraft.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.c8
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;
}