qemu-block
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Block alignment of qcow2 compress driver


From: Hanna Reitz
Subject: Re: Block alignment of qcow2 compress driver
Date: Fri, 28 Jan 2022 12:39:11 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.5.0

On 28.01.22 12:07, Richard W.M. Jones wrote:
The commands below set up a sparse RAM disk, with an allocated block
at offset 32K and another one at offset 1M-32K.  Then it tries to copy
this to a compressed qcow2 file using qemu-nbd + the qemu compress
filter:

   $ qemu-img create -f qcow2 output.qcow2 1M
   $ qemu-nbd -t --image-opts 
driver=compress,file.driver=qcow2,file.file.driver=file,file.file.filename=output.qcow2
 & sleep 1
   $ nbdkit -U - \
            data '@32768 1*32768 @1015808 1*32768' \
            --run 'nbdcopy $uri nbd://localhost -p'

The nbdcopy command fails when zeroing the first 32K with:

   nbd://localhost: nbd_aio_zero: request is unaligned: Invalid argument

This is a bug in nbdcopy because it ignores the minimum block size
being correctly declared by the compress filter:

   $ nbdinfo nbd://localhost
   protocol: newstyle-fixed without TLS
   export="":
        export-size: 1048576 (1M)
        uri: nbd://localhost:10809/
        contexts:
   ...
                block_size_minimum: 65536          <----
                block_size_preferred: 65536
                block_size_maximum: 33554432

The compress filter sets the minimum block size to the the same as the
qcow2 cluster size here:

   
https://gitlab.com/qemu-project/qemu/-/blob/cfe63e46be0a1f8a7fd2fd5547222f8344a43279/block/filter-compress.c#L117

I patched qemu to force this to 4K:

-    bs->bl.request_alignment = bdi.cluster_size;
+    //bs->bl.request_alignment = bdi.cluster_size;
+    bs->bl.request_alignment = 4096;

and the copy above works, and the output file is compressed!

So my question is, does the compress filter in qemu really need to
declare the large minimum block size?  I'm not especially concerned
about efficiency, I'd prefer it just worked, and changing nbdcopy to
understand block sizes is painful.

Is it already adjustable at run time?  (I tried using --image-opts
like compress.request_alignment=4096 but it seems like the filter
doesn't support anything I could think of, and I don't know how to
list the supported options.)

I’m kind of amazed this works because the qcow2 driver rejects unaligned compressed writes[1].

And if I apply your diff, I can see that, too:
$ ./qemu-img create -f qcow2 test.qcow2 64M
Formatting 'test.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16

$ ./qemu-io -c 'write 0 32k' --image-opts \
driver=compress,file.driver=qcow2,file.file.driver=file,file.file.filename=test.qcow2
write failed: Invalid argument

So I actually don’t know why it works for you.  OTOH, I don’t understand why the block size affects you over NBD, because I would have expected qemu to internally auto-align requests when they are not aligned (in bdrv_co_pwritev_part()).  Like, when I set the NBD block driver’s alignment to 512[2], the following still succeeds:

$ ./qemu-img create -f qcow2 test.qcow2 64M
Formatting 'test.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=67108864 lazy_refcounts=off refcount_bits=16

$ ./qemu-nbd --fork --image-opts \
driver=compress,file.driver=qcow2,file.file.driver=file,file.file.filename=test.qcow2

$ ./qemu-io -c 'write 0 32k' -f raw nbd://localhost
wrote 32768/32768 bytes at offset 0
32 KiB, 1 ops; 00.00 sec (9.034 MiB/sec and 289.0960 ops/sec)


So I wonder why your diff works on your end, and I also wonder whether we couldn’t just have the NBD server expose some custom alignment (because qemu should auto-align all requests the NBD server generates anyway).

Hanna

[1] https://gitlab.com/qemu-project/qemu/-/blob/master/block/qcow2.c#L4662
[2] https://gitlab.com/qemu-project/qemu/-/blob/master/block/nbd.c#L1918




reply via email to

[Prev in Thread] Current Thread [Next in Thread]