<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<div dir="auto">
<div><br>
<div class="gmail_extra"><br>
<div class="gmail_quote">19 июля 2017 г. 9:37 PM пользователь Andrey Vagin &lt;avagin@virtuozzo.com&gt; написал:<br type="attribution">
<blockquote class="quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><font size="2"><span style="font-size:10pt">
<div>On Wed, Jul 19, 2017 at 11:31:28AM -0700, Stanislav Kinsburskiy wrote:<br>
&gt; <br>
&gt; <br>
&gt; 19 июля 2017 г. 9:14 PM пользователь Andrey Vagin &lt;avagin@virtuozzo.com&gt;<br>
&gt; написал:<br>
&gt; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; On Wed, Jul 19, 2017 at 08:04:22PM &#43;0300, Andrey Ryabinin wrote:<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; On 07/19/2017 04:14 AM, Andrei Vagin wrote:<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; From: Andrei Vagin &lt;avagin@virtuozzo.com&gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; task_work_run() has to be called before exit_task_namespaces(),<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; because fuse_abort_conn() is called from __fput(). If it will not<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; be executed, we can hang in request_wait_answer(). We have seen this<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; situation when a process was the last member of a mount namespace<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; and the mount namespace has a vstorage fuse mount.<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; Can we pleas have a changelog that doesn't look like an output of random<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; text generator?<br>
&gt; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; Thanks!<br>
&gt; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; The fact that &quot;fuse_abort_conn() is called from __fput()&quot; doesn't really<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; explain why<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; task_work_run() needs to be called before exit_task_namespaces.<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt;<br>
&gt; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; Here is another version of my random text generator. It has to be more<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; detailed.<br>
&gt; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; This patch solves a problem for a following case. We have a container (a<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; group of processes in pid and mount namespaces) with a fuse mount. An<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; init process exits and the kernel kills all process in its pid<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; namespace. There is a fuse daemon, which handle the fuse mount.<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; Currently the kernel kills this process and closes all its file<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; descriptors, but __fput() for them is postponed and they will be<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; called from a task_work.&nbsp; Then the kernel starts destroying the mount<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; namespace and the fuse mount, it sees that a control descriptor for<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; this mount is alive and sends a request to a fuse daemon:<br>
&gt; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; $ cat /proc/4353/task/4355/stack<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffffa04c3451&gt;] request_wait_answer&#43;0x91/0x270 [fuse]<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffffa04c36b7&gt;] __fuse_request_send&#43;0x87/0xe0 [fuse]<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffffa04c6c47&gt;] fuse_request_check_and_send&#43;0x27/0x30 [fuse]<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffffa04c6c60&gt;] fuse_request_send&#43;0x10/0x20 [fuse]<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffffa04d2f35&gt;] fuse_put_super&#43;0x55/0xc0 [fuse]<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff81218b32&gt;] generic_shutdown_super&#43;0x72/0xf0<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff81218f12&gt;] kill_anon_super&#43;0x12/0x20<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffffa04d2577&gt;] fuse_kill_sb_anon&#43;0x47/0x50 [fuse]<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff812194a9&gt;] deactivate_locked_super&#43;0x49/0x80<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff81219526&gt;] deactivate_super&#43;0x46/0x60<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff81237145&gt;] mntput_no_expire&#43;0xc5/0x120<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff812371c4&gt;] mntput&#43;0x24/0x40<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff812372f8&gt;] namespace_unlock&#43;0x118/0x130<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff81239f2b&gt;] put_mnt_ns&#43;0x4b/0x60<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff810b786b&gt;] free_nsproxy&#43;0x1b/0x90<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff810b7a0a&gt;] switch_task_namespaces&#43;0x5a/0x70<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff810b7ae0&gt;] exit_task_namespaces&#43;0x10/0x20<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff8108c883&gt;] do_exit&#43;0x2f3/0xb20<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff8108d12f&gt;] do_group_exit&#43;0x3f/0xa0<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff8109e760&gt;] get_signal_to_deliver&#43;0x1d0/0x6d0<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff8102a357&gt;] do_signal&#43;0x57/0x6b0<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff8102aa0f&gt;] do_notify_resume&#43;0x5f/0xb0<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffff8169273d&gt;] int_signal&#43;0x12/0x17<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; [&lt;ffffffffffffffff&gt;] 0xffffffffffffffff<br>
&gt; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; But we know that a fuse daemon is already dead and the control<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; descriptor isn't closed completely, because __fput() was postponed.<br>
&gt; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; This patch calls task_work_run() before destroying namespaces to<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; complete closing all process files.<br>
&gt; <br>
&gt; <br>
&gt; Now I have a question. Because rised questions look reasonable.<br>
&gt; This sounds like a generic issue.<br>
&gt; I.e. it's either solved in upstream likewise or otherwise. Or not solved at<br>
&gt; all.<br>
&gt; I.e. what's the status of this issue in linux-next?<br>
&gt; <br>
<br>
In the upstream kernel deactivate_super() is called from a task_work too,<br>
so there is not this problem. But we can't backport these changes from<br>
the upstream, because they are too big.<br>
</div>
</span></font></div>
</blockquote>
</div>
</div>
</div>
<div dir="auto"><br>
</div>
<div dir="auto">Then probably it worth to mention the upsteam solution in the change log and why we can't use it, and how our patch logic correlates with the upstream one.</div>
<div dir="auto">Hm?</div>
<div dir="auto"><br>
</div>
<div dir="auto">
<div class="gmail_extra">
<div class="gmail_quote">
<blockquote class="quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><font size="2"><span style="font-size:10pt">
<div><br>
&gt; <br>
&gt;&nbsp;&nbsp;&nbsp; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; <a href="https://jira.sw.ru/browse/PSBM-68266">https://jira.sw.ru/browse/PSBM-68266</a><br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; Signed-off-by: Andrei Vagin &lt;avagin@virtuozzo.com&gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; ---<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp; include/linux/task_work.h | 9 &#43;&#43;&#43;&#43;&#43;&#43;&#43;--<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp; kernel/exit.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | 9 &#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp; kernel/task_work.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | 4 &#43;&#43;--<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp; 3 files changed, 18 insertions(&#43;), 4 deletions(-)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; diff --git a/include/linux/task_work.h b/include/linux/task_work.h<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; index ca5a1cf..b3af76d 100644<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; --- a/include/linux/task_work.h<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;&#43;&#43; b/include/linux/task_work.h<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; @@ -14,11 &#43;14,16 @@ init_task_work(struct callback_head *twork,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; task_work_func_t func)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp; int task_work_add(struct task_struct *task, struct callback_head<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; *twork, bool);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp; struct callback_head *task_work_cancel(struct task_struct *,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; task_work_func_t);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; -void task_work_run(void);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;void __task_work_run(bool exiting);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;static inline void task_work_run(void)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;{<!-- --><br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;&nbsp;&nbsp; return __task_work_run(false);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;}<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp; static inline void exit_task_work(struct task_struct *task)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp; {<!-- --><br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; -&nbsp;&nbsp; task_work_run();<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;&nbsp;&nbsp; __task_work_run(true);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp; }<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp; #endif&nbsp;&nbsp;&nbsp;&nbsp; /* _LINUX_TASK_WORK_H */<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; diff --git a/kernel/exit.c b/kernel/exit.c<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; index 3c83db2..ea54a73 100644<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; --- a/kernel/exit.c<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;&#43;&#43; b/kernel/exit.c<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; @@ -827,6 &#43;827,15 @@ void do_exit(long code)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit_fs(tsk);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (group_dead)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; disassociate_ctty(1);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;&nbsp;&nbsp; /*<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;&nbsp;&nbsp;&nbsp; * task_work_run() has to be called before exit_task_namespaces(),<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;&nbsp;&nbsp;&nbsp; * because fuse_abort_conn() is called from __fput(). If it will<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; not<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;&nbsp;&nbsp;&nbsp; * be executed, we can hang in request_wait_answer(). We have seen<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; this<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;&nbsp;&nbsp;&nbsp; * situation when a process was the last member of a mount<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; namespace<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;&nbsp;&nbsp;&nbsp; * and the mount namespace has a vstorage fuse mount.<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;&nbsp;&nbsp;&nbsp; */<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;&nbsp;&nbsp; task_work_run();<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; Given that this is purely fuse's problem, maybe request_wait_answer()<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; could just call task_work_run()?<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; Or maybe we can just call exit_task_work(tsk) before exit_task_namespaces<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; (tsk). This seems fine to me,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; but perhaps I'm missing something.<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit_task_namespaces(tsk);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; exit_task_work(tsk);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; diff --git a/kernel/task_work.c b/kernel/task_work.c<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; index 65bd3c9..f0000c4 100644<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; --- a/kernel/task_work.c<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;&#43;&#43; b/kernel/task_work.c<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; @@ -46,7 &#43;46,7 @@ task_work_cancel(struct task_struct *task,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; task_work_func_t func)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return work;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp; }<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; -void task_work_run(void)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;void __task_work_run(bool exiting)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp; {<!-- --><br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct *task = current;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct callback_head *work, *head, *next;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; @@ -58,7 &#43;58,7 @@ void task_work_run(void)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do {<!-- --><br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; work = ACCESS_ONCE(task-&gt;task_works);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; head = !work &amp;&amp; (task-&gt;flags &amp; PF_EXITING) ?<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; head = !work &amp;&amp; exiting ?<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; Why we need this change? AFAIU this will allow to add more task_works in<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; exit_task_namespaces()<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; before final exit_task_work(). What's the point of this?<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;work_exited : NULL;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } while (cmpxchg(&amp;task-&gt;task_works, work, head) != work);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; &gt; &gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; _______________________________________________<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; Devel mailing list<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; Devel@openvz.org<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; <a href="https://lists.openvz.org/mailman/listinfo/devel">https://lists.openvz.org/mailman/listinfo/devel</a><br>
&gt; <br>
&gt; <br>
</div>
</span></font></div>
</blockquote>
</div>
<br>
</div>
</div>
</div>
</body>
</html>