[Devel] [PATCH v3 1/1] dm-ploop: Fix file handle leaks when merging deltas

Vasileios Almpanis vasileios.almpanis at virtuozzo.com
Tue Sep 30 12:19:22 MSK 2025


When merging deltas, we rewrite the deltas array and remove the lower
delta. Each delta holds file handles for its runners, but these were not
being released. On vStorage, the files were deleted but a
temporary handle remained, causing EBUSY errors until reboot. As a
result, directories containing snapshots could not be deleted.

https://virtuozzo.atlassian.net/browse/VSTOR-116285

Signed-off-by: Vasileios Almpanis <vasileios.almpanis at virtuozzo.com>
Feature: dm-ploop: ploop target driver
---

v2: Extract delta cleanup into helper function
v3: Remove unused variable

---
 drivers/md/dm-ploop-bat.c    | 18 ++++++++++++++++++
 drivers/md/dm-ploop-cmd.c    |  9 +++++----
 drivers/md/dm-ploop-target.c | 13 +------------
 drivers/md/dm-ploop.h        |  1 +
 4 files changed, 25 insertions(+), 16 deletions(-)

diff --git a/drivers/md/dm-ploop-bat.c b/drivers/md/dm-ploop-bat.c
index 88b1d02b47d5..a0b678b30b97 100644
--- a/drivers/md/dm-ploop-bat.c
+++ b/drivers/md/dm-ploop-bat.c
@@ -526,3 +526,21 @@ int ploop_add_delta(struct ploop *ploop, u32 level, struct file *file, bool is_r
 	return ret;
 }
 ALLOW_ERROR_INJECTION(ploop_add_delta, ERRNO);
+
+void ploop_put_delta(struct ploop *ploop, struct ploop_delta *delta)
+{
+	int i;
+
+	if (delta->file) {
+		vfs_fsync(delta->file, 1);
+		fput(delta->file);
+	}
+
+	if (delta->mtfile) {
+		for (i = 0; i < ploop->nkt_runners; i++) {
+			if (delta->mtfile[i])
+				fput(delta->mtfile[i]);
+		}
+		kfree(delta->mtfile);
+	}
+}
diff --git a/drivers/md/dm-ploop-cmd.c b/drivers/md/dm-ploop-cmd.c
index 2043162164be..b8edfc8d5d89 100644
--- a/drivers/md/dm-ploop-cmd.c
+++ b/drivers/md/dm-ploop-cmd.c
@@ -744,10 +744,11 @@ static int ploop_merge_latest_snapshot(struct ploop *ploop)
 		goto out;
 
 	level = ploop->nr_deltas - 2;
-	file = ploop->deltas[level].file;
+
+	ploop_put_delta(ploop, &ploop->deltas[level]);
+
 	ploop->deltas[level] = ploop->deltas[level + 1];
 	ploop->nr_deltas--;
-	fput(file);
 
 	ploop_resume_submitting_pios(ploop);
 out:
@@ -817,13 +818,13 @@ static void notify_delta_merged(struct ploop *ploop, u8 level,
 		d_md = ploop_md_next_entry(d_md);
 	}
 
-	file = ploop->deltas[level].file;
+	ploop_put_delta(ploop, &ploop->deltas[level]);
+
 	/* Renumber deltas above @level */
 	for (i = level + 1; i < ploop->nr_deltas; i++)
 		ploop->deltas[i - 1] = ploop->deltas[i];
 	memset(&ploop->deltas[--ploop->nr_deltas], 0,
 	       sizeof(struct ploop_delta));
-	fput(file);
 }
 
 static int ploop_process_update_delta_index(struct ploop *ploop, u8 level,
diff --git a/drivers/md/dm-ploop-target.c b/drivers/md/dm-ploop-target.c
index 89a2b520ca32..507916841b7e 100644
--- a/drivers/md/dm-ploop-target.c
+++ b/drivers/md/dm-ploop-target.c
@@ -203,18 +203,7 @@ static void ploop_destroy(struct ploop *ploop)
 		percpu_ref_exit(&ploop->inflight_bios_ref[i]);
 	/* Nobody uses it after destroy_workqueue() */
 	while (ploop->nr_deltas-- > 0) {
-		if (ploop->deltas[ploop->nr_deltas].file) {
-			vfs_fsync(ploop->deltas[ploop->nr_deltas].file, 1);
-			fput(ploop->deltas[ploop->nr_deltas].file);
-		}
-
-		if (ploop->deltas[ploop->nr_deltas].mtfile) {
-			for (i = 0; i < ploop->nkt_runners; i++) {
-				if (ploop->deltas[ploop->nr_deltas].mtfile[i])
-					fput(ploop->deltas[ploop->nr_deltas].mtfile[i]);
-			}
-		}
-		kfree(ploop->deltas[ploop->nr_deltas].mtfile);
+		ploop_put_delta(ploop, &ploop->deltas[ploop->nr_deltas]);
 	}
 	WARN_ON(ploop_has_pending_activity(ploop));
 	WARN_ON(!ploop_empty_htable(ploop->exclusive_pios));
diff --git a/drivers/md/dm-ploop.h b/drivers/md/dm-ploop.h
index 54d51ab8126b..fc12efeb0cd9 100644
--- a/drivers/md/dm-ploop.h
+++ b/drivers/md/dm-ploop.h
@@ -600,6 +600,7 @@ extern bool ploop_try_update_bat_entry(struct ploop *ploop, u32 clu,
 
 extern int ploop_add_delta(struct ploop *ploop, u32 level,
 			   struct file *file, bool is_raw);
+extern void ploop_put_delta(struct ploop *ploop, struct ploop_delta *delta);
 extern int ploop_check_delta_length(struct ploop *ploop, struct file *file,
 				    loff_t *file_size);
 extern void ploop_submit_embedded_pios(struct ploop *ploop,
-- 
2.43.0



More information about the Devel mailing list