<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 class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
Yeah, the first issue is valid and serious, especially when working with the older user-space where there is still connect timeout.</div>
<div class="elementToProof" style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
I've made the changes to the patch, please take the version 2.&nbsp;</div>
<div id="appendonsend"></div>
<div style="font-family: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<hr style="display: inline-block; width: 98%;">
<div id="divRplyFwdMsg">
<div style="direction: ltr; font-family: Calibri, sans-serif; font-size: 11pt; color: rgb(0, 0, 0);">
<b>From:</b> Konstantin Khorenko &lt;khorenko@virtuozzo.com&gt;<br>
<b>Sent:</b> 02 September 2026 04:59<br>
<b>To:</b> Kui Liu &lt;kui.liu@virtuozzo.com&gt;<br>
<b>Cc:</b> Andrey Zaitsev &lt;azaitsev@virtuozzo.com&gt;; Alexey Kuznetsov &lt;kuznet@virtuozzo.com&gt;; devel@openvz.org &lt;devel@openvz.org&gt;<br>
<b>Subject:</b> Re: [Devel] [PATCH VZ10] fs/fuse kio: track pending kRPC connect via state machine only</div>
<div style="direction: ltr;">&nbsp;</div>
</div>
<div style="font-size: 11pt;">&gt; Rework the previous fix (&quot;fs/fuse kio: fix kRPC connect issues&quot;) to not<br>
&gt; require the new struct pcs_krpc member &quot;connect_req&quot;, so the fix can be<br>
&gt; shipped as a livepatch.<br>
&gt;<br>
&gt; Both things connect_req was tracking are already derivable from the<br>
&gt; existing state machine once PCS_KRPC_STATE_CONNECT is made to mean<br>
&gt; exactly &quot;a connect req is in flight&quot;:<br>
&gt;<br>
&gt;&nbsp; - krpc_connect_done() settles a failed connect back to UNCONN instead<br>
&gt;&nbsp;&nbsp;&nbsp; of leaving the state in CONNECT forever;<br>
&gt;<br>
&gt;&nbsp; - pcs_krpc_abort() no longer resets CONNECT to UNCONN: the req is<br>
&gt;&nbsp;&nbsp;&nbsp; still in flight, and only its completion settles the state;<br>
&gt;<br>
&gt;&nbsp; - pcs_krpc_connect() proceeds only from UNCONN or ABORTED, refusing<br>
&gt;&nbsp;&nbsp;&nbsp; new connects (-EPERM) while a req is in flight - at most one connect<br>
&gt;&nbsp;&nbsp;&nbsp; req exists at a time, same as with the connect_req check;<br>
&gt;<br>
&gt;&nbsp; - pcs_krpc_poll() reports EPOLLERR on UNCONN: poll bails out earlier<br>
&gt;&nbsp;&nbsp;&nbsp; unless ctx-&gt;gen == krpc-&gt;gen, and the current session can only be in<br>
&gt;&nbsp;&nbsp;&nbsp; UNCONN if its connect failed or was aborted, which is what the<br>
&gt;&nbsp;&nbsp;&nbsp; (CONNECT &amp;&amp; !connect_req) test used to detect.<br>
&gt;<br>
&gt; gen only advances in pcs_krpc_connect(), which is blocked during<br>
&gt; CONNECT, so within that state the in-flight req always carries the<br>
&gt; current gen and krpc_connect_done()'s existing staleness check is<br>
&gt; sufficient.<br>
&gt;<br>
&gt; Related to:<br>
&gt; <a href="https://virtuozzo.atlassian.net/browse/VSTOR-135626" data-auth="NotApplicable" id="OWA2eb79a82-ff9f-8b21-2276-b403ca3406ce" class="OWAAutoLink">
https://virtuozzo.atlassian.net/browse/VSTOR-135626</a><br>
&gt; Fixes: d0d6034c36010 (&quot;fs/fuse kio: fix kRPC connect issues&quot;)<br>
&gt; Feature: fuse: kRPC - single RPC for kernel and userspace<br>
&gt;<br>
&gt; Signed-off-by: Liu Kui &lt;kui.liu@virtuozzo.com&gt;<br>
&gt;<br>
&gt; diff --git a/fs/fuse/kio/pcs/pcs_krpc.c b/fs/fuse/kio/pcs/pcs_krpc.c<br>
&gt; index 0930fb4adf125..f9fb6b3699062 100644<br>
&gt; --- a/fs/fuse/kio/pcs/pcs_krpc.c<br>
&gt; +++ b/fs/fuse/kio/pcs/pcs_krpc.c<br>
&gt; @@ -787,8 +787,12 @@ static int pcs_krpc_abort(struct pcs_krpc *krpc)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;krpc-&gt;lock);<br>
&gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (krpc-&gt;state != PCS_KRPC_STATE_CONNECTED) {<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (krpc-&gt;state == PCS_KRPC_STATE_CONNECT)<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; krpc-&gt;state = PCS_KRPC_STATE_UNCONN;<br>
&gt; +&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; * A pending connect stays in CONNECT state: its connect req<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * is still in flight and krpc_connect_done() will settle the<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * state to UNCONN when it completes.&nbsp; Until then new connects<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * are refused, so at most one connect req exists at a time.<br>
&gt; +&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; spin_unlock(&amp;krpc-&gt;lock);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
[Severity: High]<br>
Can this change leave a krpc stuck in the connected state with no<br>
session fd attached to it?<br>
<br>
Consider a connect req in flight (state is CONNECT) whose fd is closed<br>
by userspace after its connect timeout expires - the scenario the<br>
original fix was written for:<br>
<br>
pcs_krpc_release()<br>
&nbsp;&nbsp;&nbsp; if (ctx-&gt;gen == krpc-&gt;gen)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pcs_krpc_abort(krpc);&nbsp;&nbsp;&nbsp; /* state is CONNECT: does nothing now */<br>
<br>
gen cannot advance while the state stays CONNECT, because<br>
pcs_krpc_connect() refuses new connects with -EPERM in that state.&nbsp; So<br>
when the in-flight req later completes successfully (the peer became<br>
reachable again), krpc_connect_done() passes its staleness check and<br>
commits the dead session:<br>
<br>
&nbsp;&nbsp;&nbsp; if (req-&gt;gen != krpc-&gt;gen || krpc-&gt;state != PCS_KRPC_STATE_CONNECT) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_unlock(&amp;krpc-&gt;lock);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto out;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; if (!pcs_if_error(&amp;msg-&gt;error)) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; krpc-&gt;state = PCS_KRPC_STATE_CONNECTED;<br>
<br>
Now the krpc is CONNECTED while its gen still names a session whose fd<br>
is gone.&nbsp; Every following PCS_IOC_KRPC_CONNECT returns -EPERM, there is<br>
no fd left on which userspace could issue PCS_KRPC_IOC_ABORT, and no<br>
kernel path resets the state, so the node stays unconnectable until the<br>
krpc is destroyed.<br>
<br>
The connect_req based code handled this case: pcs_krpc_abort() moved<br>
CONNECT to UNCONN, a successful krpc_connect_done() then took the stale<br>
path without transitioning to CONNECTED, and the next connect was<br>
allowed as soon as the old req completed.<br>
<br>
Does the abort/release path need to invalidate the pending connect, so<br>
that a late successful completion settles the state to UNCONN instead<br>
of resurrecting the closed session?<br>
<br>
&gt; @@ -956,8 +960,13 @@ static __poll_t pcs_krpc_poll(struct file *file, poll_table *wait)<br>
&gt;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock(&amp;krpc-&gt;lock);<br>
&gt;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * ctx-&gt;gen == krpc-&gt;gen (checked above) means this is the current<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * session, so UNCONN here can only mean its connect attempt has<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * failed (see krpc_connect_done()) or the session was aborted.<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (krpc-&gt;state == PCS_KRPC_STATE_ABORTED ||<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (krpc-&gt;state == PCS_KRPC_STATE_CONNECT &amp;&amp; !krpc-&gt;connect_req)) {<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; krpc-&gt;state == PCS_KRPC_STATE_UNCONN) {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pollflags |= EPOLLERR;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (krpc-&gt;state == PCS_KRPC_STATE_CONNECTED) {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pollflags |= EPOLLOUT;<br>
<br>
[Severity: Low]<br>
This isn't a bug, but after this change pcs_krpc_abort() never sets<br>
UNCONN, and an aborted session is left in ABORTED, which the first<br>
check already handles.<br>
<br>
For a session with ctx-&gt;gen == krpc-&gt;gen, can UNCONN still be reached<br>
through an abort as the comment says, or only through a failed<br>
connect?&nbsp; The commit message carries the same wording (&quot;the current<br>
session can only be in UNCONN if its connect failed or was aborted&quot;).<br>
<br>
[ ... ]<br>
<br>
--<br>
Konstantin Khorenko &lt;khorenko@virtuozzo.com&gt;</div>
</body>
</html>