<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<font size="2"><span style="font-size:11pt">&gt;&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;ve-&gt;referring_cgroups_lock);<br>
&gt;&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; list_add_tail(&amp;ve-&gt;referring_cgroups, &amp;cgrp-&gt;ve_reference);<br>
&gt;&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;ve-&gt;referring_cgroups_lock);<br>
&gt;<br>
&gt;How does this work?<br>
&gt;<br>
&gt;ve is entry here, and you link it to ve_reference list.<br>
&gt;In case of this function is called for another cgroup from the same ve,<br>
&gt;ve will be linked at another list. How can it be linked to two lists<br>
&gt;at the same time?</span></font></div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<font size="2"><span style="font-size:11pt"><br>
</span></font></div>
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<font size="2"><span style="font-size:11pt">Yes, the agrument ordering in list_add_tail is wrong. cgroup is being added to ve's list. My bug, thanks.</span></font><br>
</div>
<div id="appendonsend"></div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
<br>
</div>
<hr tabindex="-1" style="display:inline-block; width:98%">
<div id="divRplyFwdMsg" dir="ltr"><font style="font-size:11pt" face="Calibri, sans-serif" color="#000000"><b>From:</b> Kirill Tkhai &lt;ktkhai@virtuozzo.com&gt;<br>
<b>Sent:</b> Friday, March 13, 2020 2:08 PM<br>
<b>To:</b> Valeriy Vdovin &lt;Valeriy.Vdovin@virtuozzo.com&gt;; devel@openvz.org &lt;devel@openvz.org&gt;; Konstantin Khorenko &lt;khorenko@virtuozzo.com&gt;; Pavel Tikhomirov &lt;ptikhomirov@virtuozzo.com&gt;<br>
<b>Subject:</b> Re: [Devel] [PATCH 2/2 v0] ve/cgroup: Added cross links between cgroups and owning ve</font>
<div>&nbsp;</div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt">
<div class="PlainText">On 13.03.2020 13:09, Valeriy Vdovin wrote:<br>
&gt; Follow-up patch to per-cgroup release_agent property. Currently there is<br>
&gt; a problem with release_agent notification semantics that all<br>
&gt; notification processes spawn under ve0 (host). Due to that any processes<br>
&gt; inside of a container expecting a notification will never get it<br>
&gt; because notification will never hit container namespaces. To address<br>
&gt; this problem a process should be launched from a namespace, relative to<br>
&gt; cgroup owning ve. So we need to somehow know the right 've' during<br>
&gt; spawning of a notification process. This time it's not possible to use<br>
&gt; current-&gt;task_ve, because notifications are spawned from a dedicated<br>
&gt; kthread which knows which cgroup needs to be released, but knows nothing<br>
&gt; about what ve 'owns' this cgroup. Naturally, this can be solved by<br>
&gt; adding 've_owner' field to 'struct cgroup'.<br>
&gt; <br>
&gt; It's not enough because cgroup's lifespan isn't bound to ve's, ve<br>
&gt; might be destroyed earlier than cgroup and opposite is also true. At any<br>
&gt; time a link to ve from cgroup might become invalid without proper<br>
&gt; cleanup.<br>
&gt; <br>
&gt; To manage this we add a list of all cgroups into ve structure. All<br>
&gt; cgroups that need a reference to owning ve, are added to this list. At<br>
&gt; destruction ve will clean all references on itself from cgroups in this<br>
&gt; list.<br>
&gt; <br>
&gt; <a href="https://jira.sw.ru/browse/PSBM-83887">https://jira.sw.ru/browse/PSBM-83887</a><br>
&gt; Signed-off-by: Valeriy Vdovin &lt;valeriy.vdovin@virtuozzo.com&gt;<br>
&gt; ---<br>
&gt;&nbsp; include/linux/cgroup.h | 11 &#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;<br>
&gt;&nbsp; include/linux/ve.h&nbsp;&nbsp;&nbsp;&nbsp; | 19 &#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;<br>
&gt;&nbsp; kernel/cgroup.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | 75 &#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;<br>
&gt;&nbsp; kernel/ve/ve.c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | 73 &#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;&#43;<br>
&gt;&nbsp; 4 files changed, 178 insertions(&#43;)<br>
&gt; <br>
&gt; diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h<br>
&gt; index cad5b4f..833f249 100644<br>
&gt; --- a/include/linux/cgroup.h<br>
&gt; &#43;&#43;&#43; b/include/linux/cgroup.h<br>
&gt; @@ -287,6 &#43;287,17 @@ struct cgroup {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; u64 subgroups_limit;<br>
&gt;&nbsp; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Cgroups that have non-empty release_agent_path get in this<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * this list. At ve destruction, ve will walk this list<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * to unlink itself from each cgroup.<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head ve_reference;<br>
&gt; &#43;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; /* ve_owner, responsible for running release agent. */<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; struct ve_struct *ve_owner;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; struct mutex ve_owner_mutex;<br>
&gt; &#43;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Per-cgroup path to release agent binary for release<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * notifications.<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; diff --git a/include/linux/ve.h b/include/linux/ve.h<br>
&gt; index 9d60838..49f772c 100644<br>
&gt; --- a/include/linux/ve.h<br>
&gt; &#43;&#43;&#43; b/include/linux/ve.h<br>
&gt; @@ -91,6 &#43;91,17 @@ struct ve_struct {<br>
&gt;&nbsp; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; down_at;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cleanup_list;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * cgroups that need to be unreferenced from this ve<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * at this ve's destruction<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; referring_cgroups;<br>
&gt; &#43;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * operations on referring_cgroups are performed under this<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * lock<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; spinlock_t referring_cgroups_lock;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; meminfo_val;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int _randomize_va_space;<br>
&gt;&nbsp; <br>
&gt; @@ -268,6 &#43;279,14 @@ static inline struct cgroup *cgroup_get_ve_root(struct cgroup *cgrp)<br>
&gt;&nbsp; struct seq_file;<br>
&gt;&nbsp; struct kernel_cpustat;<br>
&gt;&nbsp; <br>
&gt; &#43;/*<br>
&gt; &#43; * cgroup needs to know it's owning ve for some of operations, but<br>
&gt; &#43; * cgroup's lifetime is independant of ve's, in theory ve can be destroyed<br>
&gt; &#43; * earlier than some of it's cgroups.<br>
&gt; &#43; */<br>
&gt; &#43;void ve_add_referring_cgroup(struct ve_struct *ve, struct cgroup *cgrp);<br>
&gt; &#43;void ve_remove_referring_cgroups(struct ve_struct *ve);<br>
&gt; &#43;<br>
&gt;&nbsp; #if defined(CONFIG_VE) &amp;&amp; defined(CONFIG_CGROUP_SCHED)<br>
&gt;&nbsp; int ve_show_cpu_stat(struct ve_struct *ve, struct seq_file *p);<br>
&gt;&nbsp; int ve_show_loadavg(struct ve_struct *ve, struct seq_file *p);<br>
&gt; diff --git a/kernel/cgroup.c b/kernel/cgroup.c<br>
&gt; index 0b64d88..3ecdb5b 100644<br>
&gt; --- a/kernel/cgroup.c<br>
&gt; &#43;&#43;&#43; b/kernel/cgroup.c<br>
&gt; @@ -1442,10 &#43;1442,12 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INIT_LIST_HEAD(&amp;cgrp-&gt;allcg_node);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INIT_LIST_HEAD(&amp;cgrp-&gt;release_list);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INIT_LIST_HEAD(&amp;cgrp-&gt;pidlists);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; INIT_LIST_HEAD(&amp;cgrp-&gt;ve_reference);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mutex_init(&amp;cgrp-&gt;pidlist_mutex);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INIT_LIST_HEAD(&amp;cgrp-&gt;event_list);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock_init(&amp;cgrp-&gt;event_list_lock);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; simple_xattrs_init(&amp;cgrp-&gt;xattrs);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; mutex_init(&amp;cgrp-&gt;ve_owner_mutex);<br>
&gt;&nbsp; }<br>
&gt;&nbsp; <br>
&gt;&nbsp; static void init_cgroup_root(struct cgroupfs_root *root)<br>
&gt; @@ -2325,6 &#43;2327,14 @@ static int cgroup_release_agent_write(struct cgroup *cgrp, struct cftype *cft,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!cgroup_lock_live_group(cgrp))<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -ENODEV;<br>
&gt;&nbsp; <br>
&gt; &#43;#ifdef CONFIG_VE<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * This is the only place when we can bind ve information to<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * cgroup, assuming that the writer does it inside of the<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * right VE.<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; ve_add_referring_cgroup(get_exec_env(), cgrp);<br>
&gt; &#43;#endif<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = cgroup_set_release_agent_locked(cgrp, buffer);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mutex_unlock(&amp;cgroup_mutex);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>
&gt; @@ -4534,6 &#43;4544,36 @@ static void css_ref_killed_fn(struct percpu_ref *ref)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cgroup_css_killed(css-&gt;cgroup);<br>
&gt;&nbsp; }<br>
&gt;&nbsp; <br>
&gt; &#43;/*<br>
&gt; &#43; * cgroup_unreference_ve removes cgroup's reference to ve<br>
&gt; &#43; * ve_owner_mutex ensures ve pointer is valid, then checks<br>
&gt; &#43; * if cgoup is still in ve's list. Otherwise ve is already<br>
&gt; &#43; * removing cgroup itself, so we dont' need to do it.<br>
&gt; &#43; */<br>
&gt; &#43;void cgroup_unreference_ve(struct cgroup *cgrp)<br>
&gt; &#43;{<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head *pos;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * We are only safe to query ve_owner under it's lock, cause<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * ve could zero it out at destruction step.<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; mutex_lock(&amp;cgrp-&gt;ve_owner_mutex);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; if (cgrp-&gt;ve_owner) {<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct ve_struct *ve = cgrp-&gt;ve_owner;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;ve-&gt;referring_cgroups_lock);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list_for_each(pos, &amp;ve-&gt;referring_cgroups) {<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (pos == &amp;cgrp-&gt;ve_reference) {<br>
&gt; &#43;&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; list_del(&amp;cgrp-&gt;ve_reference);<br>
&gt; &#43;&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; break;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;ve-&gt;referring_cgroups_lock);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cgrp-&gt;ve_owner = NULL;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; mutex_unlock(&amp;cgrp-&gt;ve_owner_mutex);<br>
&gt; &#43;}<br>
&gt; &#43;<br>
&gt; &#43;<br>
&gt;&nbsp; /**<br>
&gt;&nbsp;&nbsp; * cgroup_destroy_locked - the first stage of cgroup destruction<br>
&gt;&nbsp;&nbsp; * @cgrp: cgroup to be destroyed<br>
&gt; @@ -4645,6 &#43;4685,8 @@ static int cgroup_destroy_locked(struct cgroup *cgrp)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;cgrp-&gt;event_list_lock);<br>
&gt;&nbsp; <br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; cgroup_unreference_ve(cgrp);<br>
&gt; &#43;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; kfree(cgrp-&gt;release_agent_path);<br>
&gt;&nbsp; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
&gt; @@ -5455,6 &#43;5497,7 @@ static void cgroup_release_agent(struct work_struct *work)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; raw_spin_lock(&amp;release_list_lock);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (!list_empty(&amp;release_list)) {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *argv[3], *envp[3];<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct ve_struct *ve;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i, err;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char *pathbuf = NULL, *agentbuf = NULL;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct cgroup *root_cgrp;<br>
&gt; @@ -5468,7 &#43;5511,33 @@ static void cgroup_release_agent(struct work_struct *work)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto continue_free;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (__cgroup_path(cgrp, pathbuf, PAGE_SIZE, true) &lt; 0)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto continue_free;<br>
&gt; &#43;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * root_cgrp is the relative root for cgrp, for host<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * cgroups root_cgrp is root-&gt;top_cgroup, for container<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * cgroups it is any up the parent chain from cgrp marked<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * as VE_ROOT.<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; root_cgrp = cgroup_get_local_root(cgrp);<br>
&gt; &#43;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Under lock we are safe to check that ve_owner is not<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * NULL. Until cgroup has non-NULL pointer to VE, we are<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * safe to increase it's refcount and then until reference<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * is held, we are safe to address it's memory. If at this<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * point VE undergoes destruction steps, at maximum<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * call_usermodehelper_fns_ve will gracefully fail, but<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * nobody will care at desctuction.<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ve = NULL;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mutex_lock(&amp;root_cgrp-&gt;ve_owner_mutex);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (root_cgrp-&gt;ve_owner) {<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ve = root_cgrp-&gt;ve_owner;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get_ve(ve);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mutex_unlock(&amp;root_cgrp-&gt;ve_owner_mutex);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!ve)<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto continue_free;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (root_cgrp-&gt;release_agent_path)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; agentbuf = kstrdup(root_cgrp-&gt;release_agent_path,<br>
&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;&nbsp;&nbsp; GFP_KERNEL);<br>
&gt; @@ -5490,7 &#43;5559,13 @@ static void cgroup_release_agent(struct work_struct *work)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * since the exec could involve hitting disk and hence<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * be a slow process */<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mutex_unlock(&amp;cgroup_mutex);<br>
&gt; &#43;#ifdef CONFIG_VE<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err = call_usermodehelper_fns_ve(ve, argv[0], argv,<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; envp, UMH_WAIT_EXEC, NULL, NULL, NULL);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; put_ve(ve);<br>
&gt; &#43;#else<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);<br>
&gt; &#43;#endif<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (err &lt; 0)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pr_warn_ratelimited(&quot;cgroup release_agent &quot;<br>
&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;%s %s failed: %d\n&quot;,<br>
&gt; diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c<br>
&gt; index a64b4a7..4ead5cc 100644<br>
&gt; --- a/kernel/ve/ve.c<br>
&gt; &#43;&#43;&#43; b/kernel/ve/ve.c<br>
&gt; @@ -575,6 &#43;575,13 @@ void ve_stop_ns(struct pid_namespace *pid_ns)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ve-&gt;is_running = 0;<br>
&gt;&nbsp; <br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * After is_running is cleared, we are safe to cleanup<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * referring cgroups list. Additional cgroups will fail<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * to add themselves on is_running check.<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; ve_remove_referring_cgroups(ve);<br>
&gt; &#43;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Neither it can be in pseudosuper state<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * anymore, setup it again if needed.<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; @@ -704,6 &#43;711,7 @@ do_init:<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INIT_LIST_HEAD(&amp;ve-&gt;devices);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INIT_LIST_HEAD(&amp;ve-&gt;ve_list);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; INIT_LIST_HEAD(&amp;ve-&gt;devmnt_list);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; INIT_LIST_HEAD(&amp;ve-&gt;referring_cgroups);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mutex_init(&amp;ve-&gt;devmnt_mutex);<br>
&gt;&nbsp; <br>
&gt;&nbsp; #ifdef CONFIG_AIO<br>
&gt; @@ -1713,3 &#43;1721,68 @@ int ve_get_cpu_stat(struct ve_struct *ve, struct kernel_cpustat *kstat)<br>
&gt;&nbsp; }<br>
&gt;&nbsp; EXPORT_SYMBOL(ve_get_cpu_stat);<br>
&gt;&nbsp; #endif /* CONFIG_CGROUP_SCHED */<br>
&gt; &#43;<br>
&gt; &#43;/*<br>
&gt; &#43; * Add cgroup to list of cgroups that hold a pointer to this<br>
&gt; &#43; * ve. List and ve is protected by lock.<br>
&gt; &#43; */<br>
&gt; &#43;void ve_add_referring_cgroup(struct ve_struct *ve, struct cgroup *cgrp)<br>
&gt; &#43;{<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * The only case when we are adding a cgroup and ve isn't<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * running is during or after ve_stop_ns. And it's already<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * late to add.<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; if (!ve-&gt;is_running)<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return;<br>
&gt; &#43;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * ve_owner is protected by lock, so that cgroup could safely<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * call get_ve if ve_owner is not NULL<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; mutex_lock(&amp;cgrp-&gt;ve_owner_mutex);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; cgrp-&gt;ve_owner = ve;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; mutex_unlock(&amp;cgrp-&gt;ve_owner_mutex);<br>
&gt; &#43;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;ve-&gt;referring_cgroups_lock);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; list_add_tail(&amp;ve-&gt;referring_cgroups, &amp;cgrp-&gt;ve_reference);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;ve-&gt;referring_cgroups_lock);<br>
<br>
How does this work?<br>
<br>
ve is entry here, and you link it to ve_reference list.<br>
In case of this function is called for another cgroup from the same ve,<br>
ve will be linked at another list. How can it be linked to two lists<br>
at the same time?<br>
<br>
&gt; &#43;}<br>
&gt; &#43;<br>
&gt; &#43;/*<br>
&gt; &#43; * ve_remove_referring_cgroups is called at destruction of VE to<br>
&gt; &#43; * eliminate<br>
&gt; &#43; */<br>
&gt; &#43;void ve_remove_referring_cgroups(struct ve_struct *ve)<br>
&gt; &#43;{<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; LIST_HEAD(list);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head *pos, *next;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; BUG_ON(ve-&gt;is_running);<br>
&gt; &#43;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * Put ve list on stack to resolve cross locking of<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * ve_owner_mutex and referring_cgroups_lock.<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;ve-&gt;referring_cgroups_lock);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; list_splice_init(&amp;ve-&gt;referring_cgroups, &amp;list);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;ve-&gt;referring_cgroups_lock);<br>
&gt; &#43;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; list_for_each_safe(pos, next, &amp;list) {<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct cgroup *cgrp;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cgrp = list_entry(pos, struct cgroup, ve_reference);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; list_del(&amp;cgrp-&gt;ve_reference);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * This lock protects use of ve list on cgroup side.<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 1. cgroup can remove itself from ve's list, then<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * it needs to get valid ve owner pointer first<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * find itself in ve list, without lock, it can get<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * a valid pointer and then start to work with a<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * freed ve structure.<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * 2. cgroup may want to get_ve at some point, same<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * logic as in 1. applies to this case.<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mutex_lock(&amp;cgrp-&gt;ve_owner_mutex);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cgrp-&gt;ve_owner = NULL;<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; mutex_unlock(&amp;cgrp-&gt;ve_owner_mutex);<br>
&gt; &#43;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt; &#43;}<br>
&gt; <br>
<br>
</div>
</span></font></div>
</body>
</html>