OpenVZ / Virtuozzo kernel development (devel@openvz.org)
 help / color / mirror / Atom feed
From: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
To: den@openvz.org
Cc: devel@openvz.org
Subject: [Devel] [PATCH hci-8.1 v5 09/11] dm-ploop: fix use-after-free on the last inflight_md decrement
Date: Tue, 13 Oct 2026 09:55:11 +0200	[thread overview]
Message-ID: <20261013075513.90618-10-alexander.ivanov@virtuozzo.com> (raw)
In-Reply-To: <20261013075513.90618-1-alexander.ivanov@virtuozzo.com>

The last piwb reference is often dropped from the BAT write completion
in aio context. ploop_bat_write_finish() completes the data pios there,
and once the last original request is done, suspend can finish and a
table reload or remove can free the ploop in ploop_destroy(). The
completing CPU still decrements inflight_md, calls wake_up() on
inflight_md_wq and frees the piwb into ploop->pio_pool, so it can lock
a freed waitqueue or free into a destroyed mempool.

Nothing on the suspend or destroy path waits for inflight_md, and the
one waiter that exists, ploop_suspend_submitting_pios(), checks the
counter without a lock. It can see zero and return before wake_up() and
ploop_free_piwb() are done with the ploop, so the message can finish
and the table can be destroyed under the waker.

Free the piwb first, then decrement inflight_md and wake the waiters
under inflight_md_wq.lock as the last access to the ploop. Have the
waiters take the same lock once they see zero, so they cannot proceed
until the waker has released it, and wait for it in ploop_destroy()
before freeing anything.

https://virtuozzo.atlassian.net/browse/VSTOR-148171
Feature: dm-ploop: ploop target driver

Signed-off-by: Alexander Ivanov <alexander.ivanov@virtuozzo.com>
---
 drivers/md/dm-ploop-cmd.c    |  6 ++++--
 drivers/md/dm-ploop-map.c    | 22 ++++++++++++++++++----
 drivers/md/dm-ploop-target.c |  7 +++++++
 3 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/drivers/md/dm-ploop-cmd.c b/drivers/md/dm-ploop-cmd.c
index ab17520c2d56..977b6920a5b4 100644
--- a/drivers/md/dm-ploop-cmd.c
+++ b/drivers/md/dm-ploop-cmd.c
@@ -154,8 +154,10 @@ static int ploop_suspend_submitting_pios(struct ploop *ploop)
 	if (ret)
 		goto out;
 
-	ret = wait_event_interruptible(ploop->inflight_md_wq,
-				       !atomic_read(&ploop->inflight_md));
+	spin_lock_irq(&ploop->inflight_md_wq.lock);
+	ret = wait_event_interruptible_locked_irq(ploop->inflight_md_wq,
+					!atomic_read(&ploop->inflight_md));
+	spin_unlock_irq(&ploop->inflight_md_wq.lock);
 out:
 	if (ret)
 		ploop_resume_submitting_pios(ploop);
diff --git a/drivers/md/dm-ploop-map.c b/drivers/md/dm-ploop-map.c
index c313f303fff9..e2b70cb3c142 100644
--- a/drivers/md/dm-ploop-map.c
+++ b/drivers/md/dm-ploop-map.c
@@ -909,9 +909,25 @@ static void ploop_free_piwb(struct ploop_index_wb *piwb)
 
 static void ploop_bat_write_finish(struct pio *pio, void *piwb_ptr,
 				     blk_status_t bi_status);
+/*
+ * Waiters do not act on zero inflight_md without holding inflight_md_wq.lock,
+ * so the ploop stays valid while we hold it. Once we drop it, the ploop may
+ * be freed, so this must be the last access to it.
+ */
+static void ploop_dec_inflight_md(struct ploop *ploop)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ploop->inflight_md_wq.lock, flags);
+	if (atomic_dec_and_test(&ploop->inflight_md))
+		wake_up_locked(&ploop->inflight_md_wq);
+	spin_unlock_irqrestore(&ploop->inflight_md_wq.lock, flags);
+}
+
 static void ploop_put_piwb(struct ploop_index_wb *piwb)
 {
 	if (atomic_dec_and_test(&piwb->count)) {
+		struct ploop *ploop = piwb->ploop;
 
 		ploop_bat_write_finish(piwb->pio, piwb, piwb->bi_status);
 
@@ -925,9 +941,8 @@ static void ploop_put_piwb(struct ploop_index_wb *piwb)
 		 * zero keeps it as is
 		 */
 
-		if (atomic_dec_and_test(&piwb->ploop->inflight_md))
-			wake_up(&piwb->ploop->inflight_md_wq);
 		ploop_free_piwb(piwb);
+		ploop_dec_inflight_md(ploop);
 	}
 }
 
@@ -1105,9 +1120,8 @@ void ploop_break_bat_update(struct ploop *ploop, struct md_page *md,
 	spin_unlock(&md->md_lock);
 	spin_unlock_irqrestore(&ploop->bat_lock, flags);
 
-	if (atomic_dec_and_test(&ploop->inflight_md))
-		wake_up(&ploop->inflight_md_wq);
 	ploop_free_piwb(piwb);
+	ploop_dec_inflight_md(ploop);
 }
 
 static void ploop_bat_page_zero_cluster(struct ploop *ploop,
diff --git a/drivers/md/dm-ploop-target.c b/drivers/md/dm-ploop-target.c
index 3b589579741c..dc9410212831 100644
--- a/drivers/md/dm-ploop-target.c
+++ b/drivers/md/dm-ploop-target.c
@@ -192,6 +192,13 @@ static void ploop_destroy(struct ploop *ploop)
 		if (ploop->kt_allocator)
 			kthread_stop(ploop->kt_allocator->task);
 
+		/* BAT writes may still be completing from aio context */
+		wait_event(ploop->inflight_md_wq,
+			   !atomic_read(&ploop->inflight_md));
+		/* Wait for ploop_dec_inflight_md() to drop the lock */
+		spin_lock_irq(&ploop->inflight_md_wq.lock);
+		spin_unlock_irq(&ploop->inflight_md_wq.lock);
+
 		WARN_ON(!llist_empty(&ploop->pios[PLOOP_LIST_PREPARE]));
 		WARN_ON(!llist_empty(&ploop->llresubmit_pios));
 		WARN_ON(!llist_empty(&ploop->enospc_pios));
-- 
2.53.0

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

  parent reply	other threads:[~2026-10-13  7:57 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-13  7:55 [Devel] [PATCH hci-8.1 v5 00/11] dm-ploop: give back unused tail of top delta on suspend Alexander Ivanov
2026-10-13  7:55 ` [Devel] [PATCH hci-8.1 v5 01/11] dm-ploop: fix u32 overflow of the delta BAT byte size Alexander Ivanov
2026-10-13  8:02   ` no-reply
2026-10-13  9:24     ` Alexander Ivanov
2026-10-13  7:55 ` [Devel] [PATCH hci-8.1 v5 02/11] dm-ploop: fix lost wakeup in ploop_allocator() Alexander Ivanov
2026-10-13  8:00   ` no-reply
2026-10-13  7:55 ` [Devel] [PATCH hci-8.1 v5 03/11] dm-ploop: reject a delta header whose BAT does not cover the target Alexander Ivanov
2026-10-13  8:01   ` no-reply
2026-10-13  7:55 ` [Devel] [PATCH hci-8.1 v5 04/11] dm-ploop: reject empty deltas Alexander Ivanov
2026-10-13  8:02   ` no-reply
2026-10-13  7:55 ` [Devel] [PATCH hci-8.1 v5 05/11] dm-ploop: set delta is_raw before applying its mappings Alexander Ivanov
2026-10-13  8:03   ` no-reply
2026-10-13  7:55 ` [Devel] [PATCH hci-8.1 v5 06/11] dm-ploop: factor out ploop_read_delta() from ploop_add_delta() Alexander Ivanov
2026-10-13  8:04   ` no-reply
2026-10-13  7:55 ` [Devel] [PATCH hci-8.1 v5 07/11] dm-ploop: take bat_lock around md page lookup in ploop_llseek_hole() Alexander Ivanov
2026-10-13  8:06   ` no-reply
2026-10-13  7:55 ` [Devel] [PATCH hci-8.1 v5 08/11] dm-ploop: use wake_up() for inflight_md_wq and dispatcher_wq_prealloc Alexander Ivanov
2026-10-13  8:04   ` no-reply
2026-10-13  7:55 ` Alexander Ivanov [this message]
2026-10-13  8:11   ` [Devel] [PATCH hci-8.1 v5 09/11] dm-ploop: fix use-after-free on the last inflight_md decrement no-reply
2026-10-13  7:55 ` [Devel] [PATCH hci-8.1 v5 10/11] dm-ploop: reload metadata on resume Alexander Ivanov
2026-10-13  8:16   ` no-reply
2026-10-13  7:55 ` [Devel] [PATCH hci-8.1 v5 11/11] dm-ploop: truncate unused tail of top delta on suspend Alexander Ivanov
2026-10-13  8:20   ` no-reply
2026-10-13 11:00     ` Alexander Ivanov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261013075513.90618-10-alexander.ivanov@virtuozzo.com \
    --to=alexander.ivanov@virtuozzo.com \
    --cc=den@openvz.org \
    --cc=devel@openvz.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox