<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: Aptos, Aptos_EmbeddedFont, Aptos_MSFontService, Calibri, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</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);" class="elementToProof">
<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>&nbsp;Pavel Tikhomirov &lt;ptikhomirov@virtuozzo.com&gt;<br>
<b>Sent:</b>&nbsp;Thursday, September 18, 2025 8:34 AM<br>
<b>To:</b>&nbsp;Vasileios Almpanis &lt;vasileios.almpanis@virtuozzo.com&gt;; Andrey Zhadchenko &lt;andrey.zhadchenko@virtuozzo.com&gt;; Konstantin Khorenko &lt;khorenko@virtuozzo.com&gt;<br>
<b>Cc:</b>&nbsp;devel@openvz.org &lt;devel@openvz.org&gt;<br>
<b>Subject:</b>&nbsp;Re: [Devel] [PATCH vz9/vz10] dm-ploop: fix concurrent COW operations on same cluster</div>
<div style="direction: ltr;">&nbsp;</div>
</div>
<div style="font-size: 11pt;" class="elementToProof"><br>
<br>
On 9/16/25 22:02, Vasileios Almpanis wrote:<br>
&gt; When multiple threads attempt operations on the same cluster simultaneously,<br>
&gt; the current code logs warnings but continues with potentially conflicting<br>
&gt; operations, leading to WARN_ON triggers.<br>
&gt;<br>
&gt; Fix by implementing proper deferral when cluster locks fail:<br>
&gt;<br>
&gt; 1. Change ploop_link_pio() to add identical pios to the lock holder's<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; endio list instead of issuing warnings and continuing<br>
&gt; 2. Rename ploop_add_cluster_lk() to ploop_try_add_cluster_lk() to reflect<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; the new behavior<br>
&gt; 3. Update COW and discard paths to abort operations when cluster locking<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp; fails, allowing proper deferral.<br>
&gt;<br>
&gt; This ensures that conflicting operations are serialized rather than<br>
&gt; corrupting shared data structures.<br>
&gt;<br>
&gt; Observed during snapshot creation where filesystem metadata updates<br>
&gt; trigger concurrent operations on the same clusters.<br>
&gt;<br>
&gt; <a data-auth="NotApplicable" class="OWAAutoLink" id="OWA3765b225-abec-a2a4-55f6-9eb5749d7678" href="https://virtuozzo.atlassian.net/browse/VSTOR-115446">
https://virtuozzo.atlassian.net/browse/VSTOR-115446</a><br>
&gt; Signed-off-by: Vasileios Almpanis &lt;vasileios.almpanis@virtuozzo.com&gt;<br>
&gt;<br>
&gt; Feature: dm-ploop: ploop target driver<br>
&gt; ---<br>
&gt;&nbsp;&nbsp; drivers/md/dm-ploop-map.c | 33 +++++++++++++++++++--------------<br>
&gt;&nbsp;&nbsp; 1 file changed, 19 insertions(+), 14 deletions(-)<br>
&gt;<br>
&gt; diff --git a/drivers/md/dm-ploop-map.c b/drivers/md/dm-ploop-map.c<br>
&gt; index 56481d0f8323..db89a668e766 100644<br>
&gt; --- a/drivers/md/dm-ploop-map.c<br>
&gt; +++ b/drivers/md/dm-ploop-map.c<br>
&gt; @@ -535,10 +535,10 @@ static int ploop_link_pio(struct hlist_head head[], struct pio *pio,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (pe == pio)<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; return 1;<br>
&gt;&nbsp;&nbsp;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WARN_ON_ONCE(pe != NULL);<br>
&gt; -<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (pe)<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PL_ERR(&quot;clu:%u already exclusively locked\n&quot;, clu);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (pe) {<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ploop_add_endio_pio(pe, pio);<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!hlist_unhashed_lockless(&amp;pio-&gt;hlist_node)) {<br>
&gt; @@ -569,7 +569,7 @@ static int ploop_unlink_pio(struct ploop *ploop, struct pio *pio,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<br>
&gt;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp;<br>
&gt; -static int ploop_add_cluster_lk(struct ploop *ploop, struct pio *pio, u32 clu)<br>
&gt; +static int ploop_try_add_cluster_lk(struct ploop *ploop, struct pio *pio, u32 clu)<br>
&gt;&nbsp;&nbsp; {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long flags;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int ret;<br>
&gt; @@ -741,6 +741,10 @@ static int ploop_handle_discard_pio(struct ploop *ploop, struct pio *pio,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (ploop-&gt;nr_deltas != 1)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto punch_hole;<br>
&gt;&nbsp;&nbsp;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; if (!ploop_try_add_cluster_lk(ploop, pio, clu)) {<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 1;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
Please remove excess {} brackets.<br>
<br>
&nbsp;&gt; Do not unnecessarily use braces where a single statement will do.<br>
<br>
<a data-auth="NotApplicable" class="OWAAutoLink" id="OWA0937d644-a30d-2367-6c2b-3b53dc1b0e7b" href="https://www.kernel.org/doc/html/v4.10/process/coding-style.html#placing-braces-and-spaces">https://www.kernel.org/doc/html/v4.10/process/coding-style.html#placing-braces-and-spaces</a><br>
<br>
&gt; +<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spin_lock_irqsave(&amp;ploop-&gt;inflight_lock, flags);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inflight_h = ploop_find_inflight_bio(ploop, clu);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (inflight_h)<br>
&gt; @@ -754,8 +758,6 @@ static int ploop_handle_discard_pio(struct ploop *ploop, struct pio *pio,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; if (!ploop_add_cluster_lk(ploop, pio, clu))<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PL_ERR(&quot;dis clu %d already locked\n&quot;, clu);<br>
<br>
Why do we move it above inflight-delay code? Is there a specific reason?<br>
Except that code looks good.<br>
<br>
You are right, we should leave it as is. There is no particular reason for moving it.<br>
<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pio-&gt;wants_discard_index_cleanup = true;<br>
&gt;&nbsp;&nbsp;<br>
&gt;&nbsp;&nbsp; punch_hole:<br>
&gt; @@ -1585,12 +1587,18 @@ static int ploop_submit_cluster_cow(struct ploop *ploop, unsigned int level,<br>
&gt;&nbsp;&nbsp; {<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct ploop_cow *cow = NULL;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct pio *aux_pio = NULL;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; int ret = 0;<br>
&gt;&nbsp;&nbsp;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Prepare new delta read */<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aux_pio = ploop_alloc_pio_with_pages(ploop);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cow = kmem_cache_alloc(cow_cache, GFP_ATOMIC);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; if (!aux_pio || !cow)<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto err;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; if (!aux_pio || !cow) {<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ret = -ENOMEM;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto cleanup;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; }<br>
<br>
Please add newline here to separate allocation checks from cluster<br>
locking to improve code readability.<br>
<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; if (!ploop_try_add_cluster_lk(ploop, cow_pio, clu))<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; goto cleanup;<br>
&gt; +<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ploop_init_pio(ploop, REQ_OP_READ, aux_pio);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ploop_pio_prepare_offsets(ploop, aux_pio, clu);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; aux_pio-&gt;css = cow_pio-&gt;css;<br>
&gt; @@ -1602,17 +1610,14 @@ static int ploop_submit_cluster_cow(struct ploop *ploop, unsigned int level,<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cow-&gt;aux_pio = aux_pio;<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cow-&gt;cow_pio = cow_pio;<br>
&gt;&nbsp;&nbsp;<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; if (!ploop_add_cluster_lk(ploop, cow_pio, clu))<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PL_ERR(&quot;cowclu %d already locked\n&quot;, clu);<br>
&gt; -<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Stage #0: read secondary delta full clu */<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ploop_map_and_submit_rw(ploop, dst_clu, aux_pio, level);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br>
&gt; -err:<br>
&gt; +cleanup:<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (aux_pio)<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ploop_free_pio_with_pages(ploop, aux_pio);<br>
&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; kfree(cow);<br>
&gt; -&nbsp;&nbsp;&nbsp;&nbsp; return -ENOMEM;<br>
&gt; +&nbsp;&nbsp;&nbsp;&nbsp; return ret;<br>
&gt;&nbsp;&nbsp; }<br>
&gt;&nbsp;&nbsp;<br>
&gt;&nbsp;&nbsp; static int ploop_initiate_cluster_cow(struct ploop *ploop, unsigned int level,<br>
<br>
--<br>
Best regards, Pavel Tikhomirov<br>
Senior Software Developer, Virtuozzo.<br>
<br>
</div>
</body>
</html>