nbd: server: Report holes for raw images

When querying image extents for raw image, qemu-nbd reports holes as
zero:

$ qemu-nbd -t -r -f raw empty-6g.raw

$ qemu-img map --output json nbd://localhost
[{ "start": 0, "length": 6442450944, "depth": 0, "zero": true, "data": true, "offset": 0}]

$ qemu-img map --output json empty-6g.raw
[{ "start": 0, "length": 6442450944, "depth": 0, "zero": true, "data": false, "offset": 0}]

Turns out that qemu-img map reports a hole based on BDRV_BLOCK_DATA, but
nbd server reports a hole based on BDRV_BLOCK_ALLOCATED.

The NBD protocol says:

    NBD_STATE_HOLE (bit 0): if set, the block represents a hole (and
    future writes to that area may cause fragmentation or encounter an
    NBD_ENOSPC error); if clear, the block is allocated or the server
    could not otherwise determine its status.

qemu-img manual says:

    whether the sectors contain actual data or not (boolean field data;
    if false, the sectors are either unallocated or stored as
    optimized all-zero clusters);

To me, data=false looks compatible with NBD_STATE_HOLE. From user point
of view, getting same results from qemu-nbd and qemu-img is more
important than being more correct about allocation status.

Changing nbd server to report holes using BDRV_BLOCK_DATA makes qemu-nbd
results compatible with qemu-img map:

$ qemu-img map --output json nbd://localhost
[{ "start": 0, "length": 6442450944, "depth": 0, "zero": true, "data": false, "offset": 0}]

Signed-off-by: Nir Soffer <nsoffer@redhat.com>
Message-Id: <20210219160752.1826830-1-nsoffer@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Signed-off-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
Nir Soffer 2021-02-19 18:07:52 +02:00 committed by Eric Blake
parent 3d9330ece5
commit 0da9856851
2 changed files with 4 additions and 4 deletions

View File

@ -2087,8 +2087,8 @@ static int blockstatus_to_extents(BlockDriverState *bs, uint64_t offset,
return ret; return ret;
} }
flags = (ret & BDRV_BLOCK_ALLOCATED ? 0 : NBD_STATE_HOLE) | flags = (ret & BDRV_BLOCK_DATA ? 0 : NBD_STATE_HOLE) |
(ret & BDRV_BLOCK_ZERO ? NBD_STATE_ZERO : 0); (ret & BDRV_BLOCK_ZERO ? NBD_STATE_ZERO : 0);
if (nbd_extent_array_add(ea, num, flags) < 0) { if (nbd_extent_array_add(ea, num, flags) < 0) {
return 0; return 0;

View File

@ -5,7 +5,7 @@ QA output created by 241
size: 1024 size: 1024
min block: 1 min block: 1
[{ "start": 0, "length": 1000, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, [{ "start": 0, "length": 1000, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
{ "start": 1000, "length": 24, "depth": 0, "zero": true, "data": true, "offset": OFFSET}] { "start": 1000, "length": 24, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0)
=== Exporting unaligned raw image, forced server sector alignment === === Exporting unaligned raw image, forced server sector alignment ===
@ -23,6 +23,6 @@ WARNING: Image format was not specified for 'TEST_DIR/t.raw' and probing guessed
size: 1024 size: 1024
min block: 1 min block: 1
[{ "start": 0, "length": 1000, "depth": 0, "zero": false, "data": true, "offset": OFFSET}, [{ "start": 0, "length": 1000, "depth": 0, "zero": false, "data": true, "offset": OFFSET},
{ "start": 1000, "length": 24, "depth": 0, "zero": true, "data": true, "offset": OFFSET}] { "start": 1000, "length": 24, "depth": 0, "zero": true, "data": false, "offset": OFFSET}]
1 KiB (0x400) bytes allocated at offset 0 bytes (0x0) 1 KiB (0x400) bytes allocated at offset 0 bytes (0x0)
*** done *** done