[Devel] [PATCH RH8] dm-ploop: Fix middle delta merges

Kirill Tkhai ktkhai at virtuozzo.com
Wed Aug 4 12:08:04 MSK 2021


This makes images size to update after delta metadata re-read
and also fixes algorithm of bat_entries[] assignment.

https://jira.sw.ru/browse/PSBM-132561
Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
---
 drivers/md/dm-ploop-cmd.c |   47 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 36 insertions(+), 11 deletions(-)

diff --git a/drivers/md/dm-ploop-cmd.c b/drivers/md/dm-ploop-cmd.c
index b9be80492eae..8e696ac2fcf4 100644
--- a/drivers/md/dm-ploop-cmd.c
+++ b/drivers/md/dm-ploop-cmd.c
@@ -709,28 +709,33 @@ static void notify_delta_merged(struct ploop *ploop, u8 level,
 			if (clu == size_in_clus - 1)
 				stop = true;
 
-			if (md_page_cluster_is_in_top_delta(ploop, md, i) ||
-			    d_bat_entries[i] == BAT_ENTRY_NONE ||
-			    md->bat_levels[i] < level)
-				continue;
-
 			/* deltas above @level become renumbered */
-			if (md->bat_levels[i] > level) {
+			if (bat_entries[i] != BAT_ENTRY_NONE &&
+			    md->bat_levels[i] > level) {
 				md->bat_levels[i]--;
 				continue;
 			}
 
+			if (bat_entries[i] != BAT_ENTRY_NONE &&
+			     md->bat_levels[i] < level)
+				continue;
+
+			if (d_bat_entries[i] == BAT_ENTRY_NONE) {
+				WARN_ON_ONCE(bat_entries[i] != BAT_ENTRY_NONE);
+				continue;
+			}
+
 			/*
 			 * clusters from deltas of @level become pointing to
 			 * 1)next delta (which became renumbered) or
 			 * 2)prev delta (if !@forward).
 			 */
 			bat_entries[i] = d_bat_entries[i];
-			WARN_ON(bat_entries[i] == BAT_ENTRY_NONE);
 			if (!forward)
-				md->bat_levels[i]--;
+				md->bat_levels[i] = level - 1;
+			else
+				md->bat_levels[i] = level;
 		}
-
 		kunmap_atomic(bat_entries);
 		kunmap_atomic(d_bat_entries);
 		if (stop)
@@ -742,7 +747,8 @@ static void notify_delta_merged(struct ploop *ploop, u8 level,
 	/* Renumber deltas above @level */
 	for (i = level + 1; i < ploop->nr_deltas; i++)
 		ploop->deltas[i - 1] = ploop->deltas[i];
-	ploop->deltas[--ploop->nr_deltas].file = NULL;
+	memset(&ploop->deltas[--ploop->nr_deltas], 0,
+	       sizeof(struct ploop_delta));
 	write_unlock_irq(&ploop->bat_rwlock);
 	fput(file);
 }
@@ -780,24 +786,41 @@ static int process_update_delta_index(struct ploop *ploop, u8 level,
 static int ploop_delta_clusters_merged(struct ploop *ploop, u8 level,
 				       bool forward)
 {
+	struct ploop_delta *deltas = ploop->deltas;
 	struct rb_root md_root = RB_ROOT;
 	struct file *file;
+	loff_t file_size;
 	u32 size_in_clus;
+	u8 changed_level;
 	int ret;
 
 	/* Reread BAT of deltas[@level + 1] (or [@level - 1]) */
-	file = ploop->deltas[level + forward ? 1 : -1].file;
+	changed_level = level + (forward ? 1 : -1);
+	file = deltas[changed_level].file;
+
+	ret = ploop_check_delta_length(ploop, file, &file_size);
+	if (ret)
+		goto out;
 
 	ret = ploop_read_delta_metadata(ploop, file, &md_root, &size_in_clus);
 	if (ret)
 		goto out;
 
+	ret = -EFBIG;
+	if (changed_level != top_level(ploop) &&
+	    size_in_clus > deltas[changed_level + 1].size_in_clus)
+		goto out;
+
 	ret = ploop_suspend_submitting_pios(ploop);
 	if (ret)
 		goto out;
 
 	notify_delta_merged(ploop, level, &md_root, forward, size_in_clus);
 
+	deltas[changed_level].file_size = file_size;
+	deltas[changed_level].file_preallocated_area_start = file_size;
+	deltas[changed_level].size_in_clus = size_in_clus;
+
 	ploop_resume_submitting_pios(ploop);
 	ret = 0;
 out:
@@ -813,6 +836,8 @@ static int ploop_notify_merged(struct ploop *ploop, u8 level, bool forward)
 		return -ENOENT;
 	if (level == 0 && !forward)
 		return -EINVAL;
+	if (level == 0 && ploop->deltas[0].is_raw)
+		return -ENOTSUPP;
 	if (level == top_level(ploop) - 1 && forward)
 		return -EINVAL;
 	if (ploop->nr_deltas < 3)




More information about the Devel mailing list