[Devel] [PATCH hci-8.1 v9 07/10] dm-qcow2: fix md page cleanup on failed reftable relocation
Alexander Ivanov
alexander.ivanov at virtuozzo.com
Wed Oct 28 18:06:42 MSK 2026
relocate_refcount_table() inserts an md page for every page of the new
reftable tail and of the new refblocks, starting at
pos + old_clus * clu_size, but its error path erases only one page per
cluster starting at end. The remaining pages stay in qcow2->md_pages.
Since a failed relocation leaves the header and reftable_max_file_size
unchanged, the next relocation picks the same pos, gets -EEXIST from
md_page_try_insert() and fails with -EIO. So a single -ENOMEM or header
write error makes every later relocation fail until the target is
reloaded.
Erase every page the allocation loop inserted.
Failures after the in-memory header is switched to the new reftable
also jumped there. At that point the new pages back the live reftable
and may be dirty and linked in slow_wb_batch_list, so freeing them
leaves writeback with freed pages. Just return -EIO on these paths, as
freeing with the fixed range would also free the dirty reftable tail.
https://virtuozzo.atlassian.net/browse/VSTOR-148171
Feature: dm-qcow2: block device over QCOW2 files driver
Signed-off-by: Alexander Ivanov <alexander.ivanov at virtuozzo.com>
---
drivers/md/dm-qcow2-map.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/md/dm-qcow2-map.c b/drivers/md/dm-qcow2-map.c
index fa63bd6acfb8..f6e66799bf27 100644
--- a/drivers/md/dm-qcow2-map.c
+++ b/drivers/md/dm-qcow2-map.c
@@ -2372,21 +2372,21 @@ static int relocate_refcount_table(struct qcow2 *qcow2, struct qio **qio)
if (!WARN_ON_ONCE(!md))
qcow2_md_make_dirty(qcow2, md, true);
if (!md)
- break; /* goto err_free_r2_pages */
+ break;
}
spin_unlock_irq(&qcow2->md_pages_lock);
if (i != nr_pages)
- goto err_free_r2_pages;
+ return -EIO;
/* Connect new R2 to new R1 */
for (i = end; i < r2_end; i += clu_size) {
if (calc_refcounters_map(qcow2, i, &r1, &r2) < 0) {
WARN_ON_ONCE(1);
- goto err_free_r2_pages;
+ return -EIO;
}
ret = handle_md_page(qcow2, r1.page_id, NULL, &md);
if (WARN_ON_ONCE(ret <= 0))
- goto err_free_r2_pages;
+ return -EIO;
spin_lock_irq(&qcow2->md_pages_lock);
set_u64_to_be_page(md->page, r1.index_in_page, i);
qcow2_md_make_dirty(qcow2, md, true);
@@ -2397,7 +2397,7 @@ static int relocate_refcount_table(struct qcow2 *qcow2, struct qio **qio)
for (i = pos; i < r2_end; i += clu_size) {
ret = qcow2_handle_r1r2_maps(qcow2, i, NULL, &r1, &r2, false);
if (WARN_ON_ONCE(ret <= 0))
- goto err_free_r2_pages;
+ return -EIO;
mark_cluster_used(qcow2, r2.md, r2.index_in_page);
}
@@ -2405,14 +2405,15 @@ static int relocate_refcount_table(struct qcow2 *qcow2, struct qio **qio)
for (i = old_pos; i < old_end; i += clu_size) {
ret = qcow2_handle_r1r2_maps(qcow2, i, NULL, &r1, &r2, false);
if (WARN_ON_ONCE(ret <= 0))
- goto err_free_r2_pages;
+ return -EIO;
mark_cluster_unused(qcow2, r2.md, r2.index_in_page, i);
}
return 1;
err_free_r2_pages:
- for (i = end; i < r2_end; i += clu_size) {
+ while (i > pos + (u64)old_clus * clu_size) {
+ i -= PAGE_SIZE;
ret = handle_md_page(qcow2, i >> PAGE_SHIFT, NULL, &md);
if (ret <= 0)
break;
--
2.53.0
More information about the Devel
mailing list