[Devel] [PATCH hci-8.1 v10 08/10] dm-qcow2: leak clusters allocated for a failed L1/L2 writeback

Alexander Ivanov alexander.ivanov at virtuozzo.com
Mon Nov 9 15:41:39 MSK 2026


>>   static void revert_l_entries_update(struct qcow2 *qcow2, struct wb_desc *wbd)
>>   {
>> +	struct page *pe_page = wbd->pe_page;
>> +	u64 old;
>> +	int i;
>>   
>>   	lockdep_assert_held(&qcow2->md_pages_lock);
>>   	for_each_set_bit(i, wbd->changed_indexes, LX_INDEXES_PER_PAGE) {
>>   		/* Here we restore prealloced and compressed clu mappings */
>> +		old = pe_page ? get_u64_from_be_page(pe_page, i) : 0;
>> +		set_u64_to_be_page(wbd->md->page, i, old);
>>   	}
>>   }
> [Severity: Medium]
> Does this leave the newly allocated clusters permanently allocated for the
> lifetime of the running instance?
>
> The data cluster from LU_WANTS_ALLOC and the new L2-table cluster from an
> L1 update are allocated in prepare_l_entry_update(), and
> mark_cluster_used() sets their refcount to 1.
>
> If the md page writeback then fails, complete_wbd() calls
> revert_l_entries_update(), which now only restores the in-memory entry
> from pe_page, or to 0. Nothing calls mark_cluster_unused() for these
> clusters any more, and no other path frees them.
>
> The guest can retry the failed write, and that retry allocates a new
> cluster because the old one is still marked used. With a persistently
> failing backing device, would each retry consume one more cluster until
> the image or the refcount table is exhausted?
>
> Nothing counts or reclaims these clusters, and no QC_ERR message is
> logged, so the operator is not told that a check is needed. Would it make
> sense to log when a cluster is intentionally leaked here?
>
> The comment above complete_wbd() that says "clusters allocations
> reverted" also looks stale now.
The leak is intentional. The failed write may have partially reached
the disk, so L1/L2 on disk may point to the allocated cluster. Freeing
it lets the allocator hand it to another offset, and two guest offsets
then share it, which corrupts the image. A leaked cluster is harmless,
and check reclaims it.

The retry concern is mostly theoretical. Refcounts reach the disk
before L1/L2 does, so on a persistently failing device the R2
writeback is expected to fail first. That sets MD_WRITEBACK_ERROR and
the image needs check anyway. A leak needs the R2 and data writes to
succeed while the L2 write fails, e.g. a transient ENOSPC on an L2
overwrite. Such a write is retried no more often than the ENOSPC
timeout. The refcount table is not exhausted either: it is relocated
and the file grows.

A message is not added: the image stays consistent, and space is the
only thing lost.

The stale comment above complete_wbd() is fixed, thanks.
>
>> @@ -1415,6 +1381,8 @@ static void complete_wbd(struct qcow2 *qcow2, struct wb_desc *wbd)
>>   				       &wait_list, &end_list);
>>   		spin_unlock_irqrestore(&qcow2->md_pages_lock, flags);
>>   
>> +		list_for_each_entry(qio, &end_list, link)
>> +			qio->ext->cleanup_mask &= ~FREE_ALLOCATED_CLU;
>>   		qcow2_dispatch_qios(qcow2, NULL, &wait_list);
>>   		end_qios(&end_list, errno_to_blk_status(wbd->ret));
> Clearing FREE_ALLOCATED_CLU here makes handle_cleanup_mask() skip its
> mark_cluster_unused() call for COW qios on the failed end_list.
>
> That removes the only remaining path that would free the COW-allocated
> cluster. Is this loop always safe, given that qio->ext is dereferenced
> for every qio on end_list? Can any qio on dependent_list have a NULL ext?
>
> The commit message also says:
>
>    "Keep the refcount of these clusters instead. If L1/L2 on disk points to
>    such a cluster, the image stays consistent; otherwise the cluster is
>    leaked, which check repairs by freeing it. So the image needs no check
>    and resume needs no refusal."
>
> Is this accurate? The message itself says a leaked cluster is repaired by
> check, so the statement that the image needs no check appears to
> contradict it. Could the message be reworded to say that the image stays
> consistent but may need a check to reclaim leaked clusters?
A leak needs the data write to succeed while the L2 overwrite fails,
e.g. with a transient ENOSPC. With the disk full, the data write fails
first and the cluster is freed as before. The image stays consistent;
only space is lost, so no message is added.
> diff --git a/drivers/md/dm-qcow2-target.c b/drivers/md/dm-qcow2-target.c
>
> [ ... ]
>
>> 	/*
>> 	 * We need second iteration, since revert_l_entries_update()
>> 	 * may start timer again after failed wb.
>> 	 */
>> 	for (i = 0; i < 2; i++) {
> [Severity: Low]
> This isn't a bug, but is this comment in qcow2_flush_deferred_activity()
> now stale?
>
> It says revert_l_entries_update() may start the slow-writeback timer again
> after a failed writeback. That relied on revert_l_entries_update() calling
> mark_cluster_unused(), which dirtied R2 pages and re-armed slow_wb_timer.
> This patch removes that call, so revert_l_entries_update() only rewrites
> L1/L2 entries in the page.
>
> Timer restarts can still come from other end_qios()/qio_endio() cleanup
> paths. Could the comment be rewritten to describe the current reason for
> the second iteration?
Rewrote the comment.


More information about the Devel mailing list