qcow2: Add subcluster support to discard_in_l2_slice()
Two things need to be taken into account here:
1) With full_discard == true the L2 entry must be cleared completely.
This also includes the L2 bitmap if the image has extended L2
entries.
2) With full_discard == false we have to make the discarded cluster
read back as zeroes. With normal L2 entries this is done with the
QCOW_OFLAG_ZERO bit, whereas with extended L2 entries this is done
with the individual 'all zeroes' bits for each subcluster.
Note however that QCOW_OFLAG_ZERO is not supported in v2 qcow2
images so, if there is a backing file, discard cannot guarantee
that the image will read back as zeroes. If this is important for
the caller it should forbid it as qcow2_co_pdiscard() does (see
80f5c01183
for more details).
Signed-off-by: Alberto Garcia <berto@igalia.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Message-Id: <5ef8274e628aa3ab559bfac467abf488534f2b76.1594396418.git.berto@igalia.com>
Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
parent
205fa50750
commit
a68cd70326
@ -1848,11 +1848,17 @@ static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
|
||||
assert(nb_clusters <= INT_MAX);
|
||||
|
||||
for (i = 0; i < nb_clusters; i++) {
|
||||
uint64_t old_l2_entry;
|
||||
|
||||
old_l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
|
||||
uint64_t old_l2_entry = get_l2_entry(s, l2_slice, l2_index + i);
|
||||
uint64_t old_l2_bitmap = get_l2_bitmap(s, l2_slice, l2_index + i);
|
||||
uint64_t new_l2_entry = old_l2_entry;
|
||||
uint64_t new_l2_bitmap = old_l2_bitmap;
|
||||
QCow2ClusterType cluster_type =
|
||||
qcow2_get_cluster_type(bs, old_l2_entry);
|
||||
|
||||
/*
|
||||
* If full_discard is true, the cluster should not read back as zeroes,
|
||||
* but rather fall through to the backing file.
|
||||
*
|
||||
* If full_discard is false, make sure that a discarded area reads back
|
||||
* as zeroes for v3 images (we cannot do it for v2 without actually
|
||||
* writing a zero-filled buffer). We can skip the operation if the
|
||||
@ -1861,40 +1867,28 @@ static int discard_in_l2_slice(BlockDriverState *bs, uint64_t offset,
|
||||
*
|
||||
* TODO We might want to use bdrv_block_status(bs) here, but we're
|
||||
* holding s->lock, so that doesn't work today.
|
||||
*
|
||||
* If full_discard is true, the sector should not read back as zeroes,
|
||||
* but rather fall through to the backing file.
|
||||
*/
|
||||
switch (qcow2_get_cluster_type(bs, old_l2_entry)) {
|
||||
case QCOW2_CLUSTER_UNALLOCATED:
|
||||
if (full_discard || !bs->backing) {
|
||||
continue;
|
||||
if (full_discard) {
|
||||
new_l2_entry = new_l2_bitmap = 0;
|
||||
} else if (bs->backing || qcow2_cluster_is_allocated(cluster_type)) {
|
||||
if (has_subclusters(s)) {
|
||||
new_l2_entry = 0;
|
||||
new_l2_bitmap = QCOW_L2_BITMAP_ALL_ZEROES;
|
||||
} else {
|
||||
new_l2_entry = s->qcow_version >= 3 ? QCOW_OFLAG_ZERO : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case QCOW2_CLUSTER_ZERO_PLAIN:
|
||||
if (!full_discard) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case QCOW2_CLUSTER_ZERO_ALLOC:
|
||||
case QCOW2_CLUSTER_NORMAL:
|
||||
case QCOW2_CLUSTER_COMPRESSED:
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
if (old_l2_entry == new_l2_entry && old_l2_bitmap == new_l2_bitmap) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* First remove L2 entries */
|
||||
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_slice);
|
||||
if (!full_discard && s->qcow_version >= 3) {
|
||||
set_l2_entry(s, l2_slice, l2_index + i, QCOW_OFLAG_ZERO);
|
||||
} else {
|
||||
set_l2_entry(s, l2_slice, l2_index + i, 0);
|
||||
set_l2_entry(s, l2_slice, l2_index + i, new_l2_entry);
|
||||
if (has_subclusters(s)) {
|
||||
set_l2_bitmap(s, l2_slice, l2_index + i, new_l2_bitmap);
|
||||
}
|
||||
|
||||
/* Then decrease the refcount */
|
||||
qcow2_free_any_clusters(bs, old_l2_entry, 1, type);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user