Commit d73d0035 authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Andrew Morton

memcg: mm_update_next_owner: move for_each_thread() into try_to_set_owner()

mm_update_next_owner() checks the children / real_parent->children to
avoid the "everything else" loop in the likely case, but this won't work
if a child/sibling has a zombie leader with ->mm == NULL.

Move the for_each_thread() logic into try_to_set_owner(), if nothing else
this makes the children/siblings/everything searches more consistent.

Link: https://lkml.kernel.org/r/20240626152930.GA17936@redhat.comSigned-off-by: default avatarOleg Nesterov <oleg@redhat.com>
Acked-by: default avatarMichal Hocko <mhocko@suse.com>
Cc: Christian Brauner <brauner@kernel.org>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Jinliang Zheng <alexjlzheng@tencent.com>
Cc: Mateusz Guzik <mjguzik@gmail.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Tycho Andersen <tandersen@netflix.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 2a22b773
...@@ -440,7 +440,7 @@ static void coredump_task_exit(struct task_struct *tsk) ...@@ -440,7 +440,7 @@ static void coredump_task_exit(struct task_struct *tsk)
#ifdef CONFIG_MEMCG #ifdef CONFIG_MEMCG
/* drops tasklist_lock if succeeds */ /* drops tasklist_lock if succeeds */
static bool try_to_set_owner(struct task_struct *tsk, struct mm_struct *mm) static bool __try_to_set_owner(struct task_struct *tsk, struct mm_struct *mm)
{ {
bool ret = false; bool ret = false;
...@@ -456,12 +456,28 @@ static bool try_to_set_owner(struct task_struct *tsk, struct mm_struct *mm) ...@@ -456,12 +456,28 @@ static bool try_to_set_owner(struct task_struct *tsk, struct mm_struct *mm)
return ret; return ret;
} }
static bool try_to_set_owner(struct task_struct *g, struct mm_struct *mm)
{
struct task_struct *t;
for_each_thread(g, t) {
struct mm_struct *t_mm = READ_ONCE(t->mm);
if (t_mm == mm) {
if (__try_to_set_owner(t, mm))
return true;
} else if (t_mm)
break;
}
return false;
}
/* /*
* A task is exiting. If it owned this mm, find a new owner for the mm. * A task is exiting. If it owned this mm, find a new owner for the mm.
*/ */
void mm_update_next_owner(struct mm_struct *mm) void mm_update_next_owner(struct mm_struct *mm)
{ {
struct task_struct *c, *g, *p = current; struct task_struct *g, *p = current;
/* /*
* If the exiting or execing task is not the owner, it's * If the exiting or execing task is not the owner, it's
...@@ -483,19 +499,17 @@ void mm_update_next_owner(struct mm_struct *mm) ...@@ -483,19 +499,17 @@ void mm_update_next_owner(struct mm_struct *mm)
/* /*
* Search in the children * Search in the children
*/ */
list_for_each_entry(c, &p->children, sibling) { list_for_each_entry(g, &p->children, sibling) {
if (c->mm == mm && try_to_set_owner(c, mm)) if (try_to_set_owner(g, mm))
goto ret; goto ret;
} }
/* /*
* Search in the siblings * Search in the siblings
*/ */
list_for_each_entry(c, &p->real_parent->children, sibling) { list_for_each_entry(g, &p->real_parent->children, sibling) {
if (c->mm == mm && try_to_set_owner(c, mm)) if (try_to_set_owner(g, mm))
goto ret; goto ret;
} }
/* /*
* Search through everything else, we should not get here often. * Search through everything else, we should not get here often.
*/ */
...@@ -504,14 +518,8 @@ void mm_update_next_owner(struct mm_struct *mm) ...@@ -504,14 +518,8 @@ void mm_update_next_owner(struct mm_struct *mm)
break; break;
if (g->flags & PF_KTHREAD) if (g->flags & PF_KTHREAD)
continue; continue;
for_each_thread(g, c) { if (try_to_set_owner(g, mm))
struct mm_struct *c_mm = READ_ONCE(c->mm); goto ret;
if (c_mm == mm) {
if (try_to_set_owner(c, mm))
goto ret;
} else if (c_mm)
break;
}
} }
read_unlock(&tasklist_lock); read_unlock(&tasklist_lock);
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment