exit: Clarify choice of new parent in forget_original_parent()
PATCH 1/1 exit: Clarify choice of new parent in forget_original_parent()
Second parameter of find_new_reaper() and the similarity of its name and find_child_reaper()'s name confuse a reader.
Rename find_child_reaper() for better conformity of its name and its function. Also delete the second parameter of find_new_reaper().
These both improve modularity.
--- kernel/exit.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-)
kernel/exit.c +14 -10
@@ -450,7 +450,7 @@ static struct task_struct *find_alive_thread(struct task_struct *p)return NULL ; } -static struct task_struct *find_child_reaper (struct task_struct *father) +static void exit_pidns_child_reaper (struct task_struct *father) __releases(&tasklist_lock) __acquires(&tasklist_lock) {
@@ -458,12 +458,12 @@ static struct task_struct *find_child_reaper(struct task_struct *father)struct task_struct *reaper = pid_ns->child_reaper;if (likely (reaper != father)) -return reaper; +return ; reaper =find_alive_thread (father);if (reaper) { pid_ns->child_reaper = reaper; -return reaper; +return ; }write_unlock_irq (&tasklist_lock);
@@ -473,8 +473,6 @@ static struct task_struct *find_child_reaper(struct task_struct *father) }zap_pid_ns_processes (pid_ns);write_lock_irq (&tasklist_lock); - -return father; }/*
@@ -484,15 +482,21 @@ static struct task_struct *find_child_reaper(struct task_struct *father)* child_subreaper for its children (like a service manager) * 3. give it to the init process (PID 1) in our pid namespace */ -static struct task_struct *find_new_reaper (struct task_struct *father, -struct task_struct *child_reaper) +static struct task_struct *find_new_reaper (struct task_struct *father) { -struct task_struct *thread, *reaper; +struct task_struct *thread, *reaper, *child_reaper; thread =find_alive_thread (father);if (thread)return thread; + child_reaper =task_active_pid_ns (father)->child_reaper; +/* +* child_reaper doesn't have children after zap_pid_ns_processes(), +* therefore it can't enter this function. +*/ +BUG_ON (child_reaper == father); +if (father->signal->has_child_subreaper) {/* * Find the first ->is_child_subreaper ancestor in our pid_ns.
@@ -557,11 +561,11 @@ static void forget_original_parent(struct task_struct *father,exit_ptrace (father, dead);/* Can drop and reacquire tasklist_lock */ - reaper =find_child_reaper (father); +exit_pidns_child_reaper (father);if (list_empty (&father->children))return ; - reaper =find_new_reaper (father, reaper); + reaper =find_new_reaper (father);list_for_each_entry (p, &father->children, sibling) {for_each_thread (p, t) { t->real_parent = reaper;
Quoted 3 lines · Kirill Tkhai
Second parameter of
find_new_reaper()and the similarity of its name and find_child_reaper()'s name confuse a reader.
OK, I agree that
reaper = find_child_reaper(father); ... reaper = find_new_reaper(father, reaper);
can look confusing and probably deserves a cleanup. How about the patch below then?
Quoted 2 lines
Rename
find_child_reaper()for better conformity of its name and its function.
I never argueus with renames ;) Probably the new name looks better.
Quoted 1 line
Also delete the second parameter of
find_new_reaper().
Yes, we can do this. But this 2nd argument avoids another another task_active_pid_ns(father)->child_reaper, so this is optimization.
I agree, this optimization is minor, but still I think this change needs some justification.
Quoted 5 lines
(quoted diff) +2
-1+static struct task_struct *find_new_reaper(struct task_struct *father) { - struct task_struct *thread, *reaper; + struct task_struct *thread, *reaper, *child_reaper;
Review
Quoted 10 lines
(quoted diff) +6
-0thread = find_alive_thread(father); if (thread) return thread; + child_reaper = task_active_pid_ns(father)->child_reaper; + /* + * child_reaper doesn't have children after zap_pid_ns_processes(), + * therefore it can't enter this function. + */ + BUG_ON(child_reaper == father);
Yes, we can add this BUG_ON(). But please see the comments in zap_pid_ns_processes(). We can change zap_pid_ns_processes() so that it returns with non-empty ->children list due to EXIT_DEAD children.
Unlikely we will actually do this, at least soon, so I won't argue with this BUG_ON().
But. In this case it would be better to add it into forget_original_parent(),
reaper = find_new_reaper(...); BUG_ON(reaper == father);
Oh. Off-topic, but this reminds me that I forgot about another bug with ->has_child_subreaper... this needs another discussion.
Oleg.
kernel/exit.c +3 -3
@@ -551,17 +551,17 @@ static void reparent_leader(struct task_static void forget_original_parent (struct task_struct *father,struct list_head *dead) { -struct task_struct *p, *t, *reaper; +struct task_struct *p, *t, *child_reaper, *reaper;if (unlikely (!list_empty (&father->ptraced)))exit_ptrace (father, dead);/* Can drop and reacquire tasklist_lock */ - reaper =find_child_reaper (father); + child_reaper =find_child_reaper (father);if (list_empty (&father->children))return ; - reaper =find_new_reaper (father, reaper); + reaper =find_new_reaper (father, child_reaper);list_for_each_entry (p, &father->children, sibling) {for_each_thread (p, t) { t->real_parent = reaper;
forgot to mention,
Quoted 12 lines · Oleg Nesterov
Review
Quoted 5 lines · Kirill Tkhai
(quoted diff) +4
-0+ * child_reaper doesn't have children after zap_pid_ns_processes(), + * therefore it can't enter this function. + */ + BUG_ON(child_reaper == father);Yes, we can add this
BUG_ON(). But please see the comments inzap_pid_ns_processes(). We can changezap_pid_ns_processes()so that it returns with non-empty ->children list due toEXIT_DEADchildren.
Quoted 7 lines
Unlikely we will actually do this, at least soon, so I won't argue with this
BUG_ON().But. In this case it would be better to add it into
forget_original_parent(),reaper = find_new_reaper(...); BUG_ON(reaper == father);
because this way:
1. This BUG_ON() will still be valid even if we actually change zap_pid_ns_processes() to return with EXIT_DEAD children
2. If we really want this sanity check, we should not tie it to ->child_reaper case.
OTOH. If for some reason you want to check ->child_reaper only, then you should probably do this right after list_empty(&father->children) check, or at least before find_alive_thread(). Because otherwise it looks confusing, it looks as if "child_reaper == father" is only wrong if find_alive_thread(father) fails.
Oleg.
В Вт, 16/06/2015 в 22:03 +0200, Oleg Nesterov пишет:
Quoted 28 lines
forgot to mention,
Quoted 12 lines · Oleg Nesterov
Review
Quoted 5 lines · Kirill Tkhai
(quoted diff) +4
-0+ * child_reaper doesn't have children after zap_pid_ns_processes(), + * therefore it can't enter this function. + */ + BUG_ON(child_reaper == father);Yes, we can add this
BUG_ON(). But please see the comments inzap_pid_ns_processes(). We can changezap_pid_ns_processes()so that it returns with non-empty ->children list due toEXIT_DEADchildren.Quoted 7 lines
Unlikely we will actually do this, at least soon, so I won't argue with this
BUG_ON().But. In this case it would be better to add it into
forget_original_parent(),reaper = find_new_reaper(...); BUG_ON(reaper == father);because this way:
1. This
BUG_ON()will still be valid even if we actually changezap_pid_ns_processes()to return withEXIT_DEADchildren
Quoted 8 lines
2. If we really want this sanity check, we should not tie it to ->child_reaper case.
OTOH. If for some reason you want to check ->child_reaper only, then you should probably do this right after
list_empty(&father->children)check, or at least beforefind_alive_thread(). Because otherwise it looks confusing, it looks as if "child_reaper== father" is only wrong iffind_alive_thread(father)fails.
Sure, it's more logical. Thanks, Oleg.
В Вт, 16/06/2015 в 21:27 +0200, Oleg Nesterov пишет:
Quoted 5 lines · Kirill Tkhai
Quoted 3 lines
Second parameter of
find_new_reaper()and the similarity of its name and find_child_reaper()'s name confuse a reader.
Quoted 8 lines
OK, I agree that
reaper = find_child_reaper(father); ... reaper = find_new_reaper(father, reaper);can look confusing and probably deserves a cleanup. How about the patch below then?
Good, IMO it improves the readability.
Quoted 6 lines
Quoted 3 lines
Rename
find_child_reaper()for better conformity of its name and its function.I never argueus with renames ;) Probably the new name looks better.
Quoted 7 lines
Quoted 1 line
Also delete the second parameter of
find_new_reaper().Yes, we can do this. But this 2nd argument avoids another another task_active_pid_ns(father)->child_reaper, so this is optimization.
I agree, this optimization is minor, but still I think this change needs some justification.
It looks like gcc inlines both of these function, so it seems there won't be a problem...
Quoted 10 lines
Quoted 10 lines
(quoted diff) +2
-1+static struct task_struct *find_new_reaper(struct task_struct *father) { - struct task_struct *thread, *reaper; + struct task_struct *thread, *reaper, *child_reaper; thread = find_alive_thread(father); if (thread) return thread;
Quoted 10 lines
Review
Quoted 6 lines
(quoted diff) +6
-0+ child_reaper = task_active_pid_ns(father)->child_reaper; + /* + * child_reaper doesn't have children after zap_pid_ns_processes(), + * therefore it can't enter this function. + */ + BUG_ON(child_reaper == father);Yes, we can add this
BUG_ON(). But please see the comments inzap_pid_ns_processes(). We can changezap_pid_ns_processes()so that it returns with non-empty ->children list due toEXIT_DEADchildren.
Yes, I saw. Since zap_pid_ns_processes() waits for nr_hashed, and __unhash_process() deletes from pid chain and sibling list at the same time, pid_ns child_reaper can't have a child after nr_hashed == init_pids.
Quoted 7 lines
Unlikely we will actually do this, at least soon, so I won't argue with this
BUG_ON().But. In this case it would be better to add it into
forget_original_parent(),reaper = find_new_reaper(...); BUG_ON(reaper == father);
Yeah, I'm agree.
Quoted 19 lines
Oh. Off-topic, but this reminds me that I forgot about another bug with ->has_child_subreaper... this needs another discussion.
Oleg.
kernel/exit.c +1
-1@@ -551,17 +551,17 @@ static void reparent_leader(struct task_static void forget_original_parent (struct task_struct *father,struct list_head *dead) { -struct task_struct *p, *t, *reaper; +struct task_struct *p, *t, *child_reaper, *reaper;if (unlikely (!list_empty (&father->ptraced)))exit_ptrace (father, dead);/* Can drop and reacquire tasklist_lock */
kernel/exit.c static void reparent_leader(struct task_ · line 567
Quoted 10 lines
kernel/exit.c +2
-2- reaper =find_child_reaper (father); + child_reaper =find_child_reaper (father);if (list_empty (&father->children))return ; - reaper =find_new_reaper (father, reaper); + reaper =find_new_reaper (father, child_reaper);list_for_each_entry (p, &father->children, sibling) {for_each_thread (p, t) { t->real_parent = reaper;
Thanks,
Kirill