[Devel] [PATCH VZ10 02/10] drivers/md/dm-qcow2: generalize COW index update machinery

Andrey Zhadchenko andrey.zhadchenko at virtuozzo.com
Wed Aug 12 21:56:30 MSK 2026


The two-stage L1/L2 entry update pipeline is not COW-specific:
backward merge already uses it to zero L2 entries, and upcoming
discard support will be the third user. Rename it to reflect
what it does.

No functional changes.

Feature: dm-qcow2: block device over QCOW2 files driver
https://virtuozzo.atlassian.net/browse/VSTOR-139406
Signed-off-by: Andrey Zhadchenko <andrey.zhadchenko at virtuozzo.com>
---
 drivers/md/dm-qcow2-map.c | 100 +++++++++++++++++++-------------------
 drivers/md/dm-qcow2.h     |  10 ++--
 2 files changed, 55 insertions(+), 55 deletions(-)

diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c
index 2cd8e174049f8..08d46eb177dd1 100644
--- a/drivers/md/dm-qcow2-map.c
+++ b/drivers/md/dm-qcow2-map.c
@@ -2579,10 +2579,10 @@ static int prepare_l1l2_allocation(struct qcow2 *qcow2, struct qio *qio,
  * we have to wait all previous READs. We do that around
  * index wb. See md->wpc_noread_count update details.
  */
-static int prepare_l_entry_cow(struct qcow2 *qcow2, struct qcow2_map *map,
-			       struct qio *qio, struct md_page *md,
-			       u32 index_in_page, loff_t cow_clu_pos,
-			       loff_t cow_clu_end, u8 cow_level)
+static int prepare_l_entry_replace(struct qcow2 *qcow2, struct qcow2_map *map,
+				   struct qio *qio, struct md_page *md,
+				   u32 index_in_page, loff_t unuse_clu_pos,
+				   loff_t unuse_clu_end, u8 lx_level)
 {
 	struct lock_desc *lockd = NULL;
 	struct qio_ext *ext;
@@ -2591,9 +2591,9 @@ static int prepare_l_entry_cow(struct qcow2 *qcow2, struct qcow2_map *map,
 		return -ENOMEM;
 
 	ext = qio->ext;
-	ext->cow_clu_pos = cow_clu_pos;
-	ext->cow_clu_end = cow_clu_end;
-	ext->cow_level = cow_level;
+	ext->unuse_clu_pos = unuse_clu_pos;
+	ext->unuse_clu_end = unuse_clu_end;
+	ext->lx_level = lx_level;
 
 	spin_lock_irq(&qcow2->md_pages_lock);
 	if (!md->lockd) {
@@ -2614,23 +2614,23 @@ static int prepare_l_entry_cow(struct qcow2 *qcow2, struct qcow2_map *map,
 	return 1;
 }
 
-static int prepare_l1l2_cow(struct qcow2 *qcow2, struct qio *qio,
-			    struct qcow2_map *map)
+static int prepare_l1l2_replace(struct qcow2 *qcow2, struct qio *qio,
+				struct qcow2_map *map)
 {
 	if (WARN_ON_ONCE(!(map->level & L1_LEVEL)))
 		return -EIO; /* Sanity check: L1 must be cached */
 
 	if (!(map->level & L2_LEVEL)) {
-		return prepare_l_entry_cow(qcow2, map, qio, map->l1.md,
-					   map->l1.index_in_page,
-					   map->cow_clu_pos,
-					   map->cow_clu_end, L1_LEVEL);
+		return prepare_l_entry_replace(qcow2, map, qio, map->l1.md,
+					       map->l1.index_in_page,
+					       map->cow_clu_pos,
+					       map->cow_clu_end, L1_LEVEL);
 	}
 
-	return prepare_l_entry_cow(qcow2, map, qio, map->l2.md,
-				  map->l2.index_in_page,
-				  map->cow_clu_pos,
-				  map->cow_clu_end, L2_LEVEL);
+	return prepare_l_entry_replace(qcow2, map, qio, map->l2.md,
+				       map->l2.index_in_page,
+				       map->cow_clu_pos,
+				       map->cow_clu_end, L2_LEVEL);
 }
 
 static void backward_merge_write_complete(struct qcow2_target *tgt, struct qio *unused,
@@ -2648,7 +2648,7 @@ static void backward_merge_write_complete(struct qcow2_target *tgt, struct qio *
 	WARN_ON_ONCE(qio->flags & QIO_IS_DISCARD_FL);
 	qio->flags |= QIO_IS_DISCARD_FL;
 
-	qio->queue_list_id = QLIST_COW_INDEXES;
+	qio->queue_list_id = QLIST_INDEXES_WRITE;
 	qcow2_dispatch_qios(qcow2, qio, NULL);
 }
 
@@ -2704,7 +2704,7 @@ static int prepare_backward_merge(struct qcow2 *qcow2, struct qio **qio,
 	if (!op_is_write((*qio)->bi_op)) {
 		/*
 		 * READ qio may data may be contained in several deltas.
-		 * We can't read lower delta after prepare_l1l2_cow()
+		 * We can't read lower delta after prepare_l1l2_replace()
 		 * prepares us.
 		 */
 		aux_qio = qcow2_alloc_qio(qcow2->tgt->qio_pool, true);
@@ -2725,10 +2725,10 @@ static int prepare_backward_merge(struct qcow2 *qcow2, struct qio **qio,
 	}
 
 	/*
-	 * Mark as COW, as this completely defers any parallel qios.
-	 * @qio is COW status holder.
+	 * Lock the entry, as this completely defers any parallel qios.
+	 * @qio is the lock holder.
 	 */
-	ret = prepare_l1l2_cow(qcow2, *qio, map);
+	ret = prepare_l1l2_replace(qcow2, *qio, map);
 	if (ret < 0) {
 		(*qio)->bi_status = errno_to_blk_status(ret);
 		goto endio;
@@ -2736,13 +2736,13 @@ static int prepare_backward_merge(struct qcow2 *qcow2, struct qio **qio,
 
 	if (!map->clu_is_cow) {
 		/* Forced set these to unuse them after discard */
-		(*qio)->ext->cow_clu_pos = map->data_clu_pos;
-		(*qio)->ext->cow_clu_end = map->data_clu_pos + qcow2->clu_size;
+		(*qio)->ext->unuse_clu_pos = map->data_clu_pos;
+		(*qio)->ext->unuse_clu_end = map->data_clu_pos + qcow2->clu_size;
 	}
 
 	return 1;
 endio:
-	qio_endio(*qio); /* Breaks COW set in prepare_l1l2_cow() */
+	qio_endio(*qio); /* Releases the lock set in prepare_l1l2_replace() */
 	return 0;
 }
 
@@ -3348,7 +3348,7 @@ static int handle_metadata(struct qcow2 *qcow2, struct qio **qio,
 		   (!qio_is_fully_alloced(qcow2, *qio, map) || map->clu_is_cow)) {
 		if (map->clu_is_cow) {
 			/* COW to compressed or shared with snapshot cluster */
-			ret = prepare_l1l2_cow(qcow2, *qio, map);
+			ret = prepare_l1l2_replace(qcow2, *qio, map);
 		} else if ((map->level & L2_LEVEL) &&
 		    qio_border_is_inside_unmapped_unit(qcow2, *qio, map) &&
 		    maybe_mapped_in_lower_delta(qcow2, *qio)) {
@@ -3358,7 +3358,7 @@ static int handle_metadata(struct qcow2 *qcow2, struct qio **qio,
 			 * snapshots). Here is data COW on L2_LEVEL.
 			 */
 			map->backing_file_cow = true;
-			ret = prepare_l1l2_cow(qcow2, *qio, map);
+			ret = prepare_l1l2_replace(qcow2, *qio, map);
 		} else if (unlikely(op_is_discard((*qio)->bi_op) &&
 				    (map->level & L2_LEVEL))) {
 			if (!map->data_clu_alloced) {
@@ -3837,7 +3837,7 @@ static void cow_data_write_endio(struct qcow2_target *tgt, struct qio *unused,
 		qio->bi_status = bi_status;
 		qio_endio(qio);
 	} else {
-		qio->queue_list_id = QLIST_COW_INDEXES;
+		qio->queue_list_id = QLIST_INDEXES_WRITE;
 		qcow2_dispatch_qios(qcow2, qio, NULL);
 	}
 }
@@ -3885,7 +3885,7 @@ static void sliced_cow_data_write_complete(struct qcow2_target *tgt, struct qio
 		qio->bi_status = bi_status;
 		qio_endio(qio);
 	} else {
-		qio->queue_list_id = QLIST_COW_INDEXES;
+		qio->queue_list_id = QLIST_INDEXES_WRITE;
 		qcow2_dispatch_qios(qcow2, qio, NULL);
 	}
 }
@@ -3919,7 +3919,7 @@ static void process_cow_data_write(struct qcow2 *qcow2, struct list_head *cow_li
 		ext = qio->ext;
 
 		if (ext->only_set_ext_l2) {
-			WARN_ON_ONCE(ext->cow_level != L2_LEVEL);
+			WARN_ON_ONCE(ext->lx_level != L2_LEVEL);
 			pos = ext->allocated_clu_pos;
 			goto submit;
 		}
@@ -3938,14 +3938,14 @@ static void process_cow_data_write(struct qcow2 *qcow2, struct list_head *cow_li
 		ext->allocated_clu_pos = pos;
 		ext->cleanup_mask |= FREE_ALLOCATED_CLU;
 submit:
-		if (ext->cow_level == L2_LEVEL)
+		if (ext->lx_level == L2_LEVEL)
 			submit_sliced_cow_data_write(qcow2, qio, pos);
 		else
 			submit_cow_data_write(qcow2, qio, pos);
 	}
 }
 
-static void process_cow_indexes_write(struct qcow2 *qcow2,
+static void process_indexes_write(struct qcow2 *qcow2,
 				      struct list_head *qio_list)
 {
 	struct qcow2_bvec *qvec;
@@ -3965,7 +3965,7 @@ static void process_cow_indexes_write(struct qcow2 *qcow2,
 		lx_md = ext->lx_md;
 
 		/* Return back to the same stage in case of writeback */
-		qio->queue_list_id = QLIST_COW_INDEXES;
+		qio->queue_list_id = QLIST_INDEXES_WRITE;
 		if (delay_if_writeback(qcow2, lx_md, -1, &qio, true))
 			continue;
 
@@ -3974,7 +3974,7 @@ static void process_cow_indexes_write(struct qcow2 *qcow2,
 
 		arg_mask = (discard ? 0 : LU_SET_ONE_MASK) | LU_WANTS_PE_PAGE;
 		if (ext->only_set_ext_l2) {
-			WARN_ON_ONCE(ext->cow_level != L2_LEVEL);
+			WARN_ON_ONCE(ext->lx_level != L2_LEVEL);
 			goto set_ext_l2;
 		}
 
@@ -3982,14 +3982,14 @@ static void process_cow_indexes_write(struct qcow2 *qcow2,
 		ret = prepare_l_entry_update(qcow2, qio, lx_md,
 					     ext->lx_index_in_page,
 					     &ext->allocated_clu_pos,
-					     arg_mask, ext->cow_level);
+					     arg_mask, ext->lx_level);
 		if (ret < 0) {
 			qio->bi_status = errno_to_blk_status(ret);
 			qio_endio(qio);
 			continue;
 		}
 set_ext_l2:
-		if (qcow2->ext_l2 && ext->cow_level == L2_LEVEL) {
+		if (qcow2->ext_l2 && ext->lx_level == L2_LEVEL) {
 			arg_mask &= ~LU_SET_ONE_MASK;
 			ret = prepare_l_entry_update(qcow2, qio, lx_md,
 					     ext->lx_index_in_page + 1,
@@ -3999,7 +3999,7 @@ static void process_cow_indexes_write(struct qcow2 *qcow2,
 		}
 
 		/* Next stage */
-		qio->queue_list_id = QLIST_COW_END;
+		qio->queue_list_id = QLIST_INDEXES_END;
 
 		spin_lock_irq(&qcow2->md_pages_lock);
 		/*
@@ -4015,8 +4015,8 @@ static void process_cow_indexes_write(struct qcow2 *qcow2,
 	}
 }
 
-/* Finalize successful COW */
-static void process_cow_end(struct qcow2 *qcow2, struct list_head *qio_list)
+/* Finalize successful L1/L2 entry replace */
+static void process_indexes_end(struct qcow2 *qcow2, struct list_head *qio_list)
 {
 	struct dm_target *ti = qcow2->tgt->ti;
 	u32 mask, clu_size = qcow2->clu_size;
@@ -4036,7 +4036,7 @@ next:		qio = qio_list_pop(qio_list);
 			ext->cleanup_mask &= ~FREE_ALLOCATED_CLU;
 
 		/* Should be already set... */
-		qio->queue_list_id = QLIST_COW_END;
+		qio->queue_list_id = QLIST_INDEXES_END;
 		/*
 		 * Wait last user before we (possible) mark clusters
 		 * unused. In real only compressed COW requires this.
@@ -4044,8 +4044,8 @@ next:		qio = qio_list_pop(qio_list);
 		if (delay_if_has_wpc_readers(qcow2, ext->lx_md, &qio))
 			goto next;
 
-		pos = ext->cow_clu_pos;
-		for (; pos < ext->cow_clu_end; pos += clu_size) {
+		pos = ext->unuse_clu_pos;
+		for (; pos < ext->unuse_clu_end; pos += clu_size) {
 			ret = __handle_r1r2_maps(qcow2, pos, &qio, &r1, &r2);
 			if (ret == 0) /* We never shrink md pages, impossible */
 				goto next;
@@ -4053,7 +4053,7 @@ next:		qio = qio_list_pop(qio_list);
 				QC_ERR(ti, "clu at %lld leaked", pos);
 			else
 				dec_cluster_usage(qcow2, r2.md, r2.index_in_page, pos);
-			ext->cow_clu_pos += clu_size;
+			ext->unuse_clu_pos += clu_size;
 		}
 
 		mask = MD_INDEX_SET_UNLOCKED|DEC_WPC_NOREAD_COUNT;
@@ -4061,7 +4061,7 @@ next:		qio = qio_list_pop(qio_list);
 			mask |= FREE_QIO_DATA_QVEC;
 		WARN_ON_ONCE(ext->cleanup_mask != mask); /* Sanity check */
 
-		if (ext->cow_level == L1_LEVEL) {
+		if (ext->lx_level == L1_LEVEL) {
 			finalize_qio_ext(qio);
 			/* COW on L1 completed, it's time for COW on L2 */
 			qio->queue_list_id = QLIST_DEFERRED;
@@ -4101,8 +4101,8 @@ void do_qcow2_work(struct work_struct *ws)
 	LIST_HEAD(zread_qios);
 	LIST_HEAD(bwrite_qios);
 	LIST_HEAD(cow_data_qios);
-	LIST_HEAD(cow_indexes_qios);
-	LIST_HEAD(cow_end_qios);
+	LIST_HEAD(indexes_write_qios);
+	LIST_HEAD(indexes_end_qios);
 	LIST_HEAD(resubmit_qios);
 	LIST_HEAD(seek_qios);
 	unsigned int pflags = current->flags;
@@ -4114,8 +4114,8 @@ void do_qcow2_work(struct work_struct *ws)
 	list_splice_init(&qcow2->qios[QLIST_ZREAD], &zread_qios);
 	list_splice_init(&qcow2->qios[QLIST_BMERGE_WRITE], &bwrite_qios);
 	list_splice_init(&qcow2->qios[QLIST_COW_DATA], &cow_data_qios);
-	list_splice_init(&qcow2->qios[QLIST_COW_INDEXES], &cow_indexes_qios);
-	list_splice_init(&qcow2->qios[QLIST_COW_END], &cow_end_qios);
+	list_splice_init(&qcow2->qios[QLIST_INDEXES_WRITE], &indexes_write_qios);
+	list_splice_init(&qcow2->qios[QLIST_INDEXES_END], &indexes_end_qios);
 	list_splice_init(&qcow2->resubmit_qios, &resubmit_qios);
 	list_splice_init(&qcow2->qios[QLIST_SEEK], &seek_qios);
 	spin_unlock_irq(&qcow2->deferred_lock);
@@ -4125,8 +4125,8 @@ void do_qcow2_work(struct work_struct *ws)
 	process_compressed_read(&zread_qios, &cow_data_qios);
 	process_backward_merge_write(qcow2, &bwrite_qios);
 	process_cow_data_write(qcow2, &cow_data_qios);
-	process_cow_indexes_write(qcow2, &cow_indexes_qios);
-	process_cow_end(qcow2, &cow_end_qios);
+	process_indexes_write(qcow2, &indexes_write_qios);
+	process_indexes_end(qcow2, &indexes_end_qios);
 	process_resubmit_qios(qcow2, &resubmit_qios);
 	process_seek_qios(qcow2, &seek_qios);
 
diff --git a/drivers/md/dm-qcow2.h b/drivers/md/dm-qcow2.h
index aa3487007523f..230e7a4a34e76 100644
--- a/drivers/md/dm-qcow2.h
+++ b/drivers/md/dm-qcow2.h
@@ -228,8 +228,8 @@ enum {
 	QLIST_ZREAD,
 	QLIST_BMERGE_WRITE,
 	QLIST_COW_DATA,
-	QLIST_COW_INDEXES,
-	QLIST_COW_END,
+	QLIST_INDEXES_WRITE,
+	QLIST_INDEXES_END,
 	QLIST_SEEK,
 
 	QLIST_COUNT,
@@ -307,13 +307,13 @@ struct qio_ext {
 	u32 lx_index_in_page, r2_index_in_page;
 	u64 allocated_clu_pos;
 
-	loff_t cow_clu_pos;
-	loff_t cow_clu_end;
+	loff_t unuse_clu_pos;
+	loff_t unuse_clu_end;
 	u64 new_ext_l2;
 	u32 cow_mask;
 	bool only_set_ext_l2:1;
 
-	u8 cow_level;
+	u8 lx_level;
 
 #define MD_INDEX_SET_UNLOCKED	(1ULL << 0)
 #define DEC_WPC_NOREAD_COUNT	(1ULL << 1)
-- 
2.43.5



More information about the Devel mailing list