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

kernel: is_current_single_threaded: don't use ->mmap_sem

is_current_single_threaded() can safely miss a freshly forked CLONE_VM
task, but in this case it must not miss its parent. That is why we take
mm->mmap_sem for writing to make sure a thread/task with the same ->mm
can't pass exit_mm() and disappear.

However we can avoid ->mmap_sem and rely on rcu/barriers:

- if we do not see the exiting parent on thread/process list
we see the result of list_del_rcu(), in this case we must
also see the result of list_add_rcu() which does wmb().

- if we do see the parent but its ->mm == NULL, we need rmb()
to make sure we can't miss the child.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: David Howells <dhowells@redhat.com>
Signed-off-by: James Morris <jmorris@namei.org>

authored by

Oleg Nesterov and committed by
James Morris
967cc537 5bb459bb

+6 -4
+6 -4
lib/is_single_threaded.c
··· 22 22 struct task_struct *p, *t; 23 23 bool ret; 24 24 25 - might_sleep(); 26 - 27 25 if (atomic_read(&task->signal->live) != 1) 28 26 return false; 29 27 ··· 29 31 return true; 30 32 31 33 ret = false; 32 - down_write(&mm->mmap_sem); 33 34 rcu_read_lock(); 34 35 for_each_process(p) { 35 36 if (unlikely(p->flags & PF_KTHREAD)) ··· 42 45 goto found; 43 46 if (likely(t->mm)) 44 47 break; 48 + /* 49 + * t->mm == NULL. Make sure next_thread/next_task 50 + * will see other CLONE_VM tasks which might be 51 + * forked before exiting. 52 + */ 53 + smp_rmb(); 45 54 } while_each_thread(p, t); 46 55 } 47 56 ret = true; 48 57 found: 49 58 rcu_read_unlock(); 50 - up_write(&mm->mmap_sem); 51 59 52 60 return ret; 53 61 }