Thank you, Eric, for the thorough information—truly appreciate it.

Just to confirm what I understood, when we are reading a bitmap with
'x-dirty-bitmap' (for powered on vm of course), the 'start' is always a
logical offset no matter whether the record has 'offset' value or not. Is
this correct?

Also, I came across a case wherein we get the entire disk as allocated for
a raw format disk which is present on lvm or lvm-thin storage (the disk has
just a few MB data added, and the vm is in running state). Here is an
example of 1Gb data. Is this expected behaviour?
[{ "start": 0, "length": 1073741824, "depth": 0, "present": true, "zero":
false, "data": true, "compressed": false, "offset": 0}]

Regards,
Prashant

On Mon, Apr 7, 2025 at 8:24 PM Eric Blake <ebl...@redhat.com> wrote:

> On Mon, Apr 07, 2025 at 02:46:17PM +0530, prashant patil wrote:
> > Thanks Eric.
>
> [top-posting makes conversations harder to follow, so on this list we
> typically reply inline]
>
> > I have a few questions about the bitmap content shown by 'qemu-img map'.
> > From below sample bitmap data:
> > 1. Why only some of the extents have start and offset values? And why are
> > they the same values?
> > 2. What does the start value indicate? Is it logical offset or physical
> > offset of data into qcow2?
>
> Normally (when there is no x-dirty-bitmap in play), 'start' denotes
> the logical offset being reported on (you'd expect a map to list every
> logical offset; so the start of entry N+1 should be the sum of start +
> length of entry N), while 'offset' is where that extent begins in the
> underlying file.  For a raw source, offset and start will be
> identical; for other sources, like qcow2, start is obviously logical,
> while offset is physical.  Entries without 'offset' are places where
> the logical contents are compressed, synthesized, or otherwise have no
> 1:1 correspondence to an offset in the physical file.  'present'
> indicates whether the data is synthesized or not; 'offset' is going to
> be absent if 'present' is false; although it can also be absent even
> when 'present' is true such as in the case of compression.
>
> When it comes to exposing a qcow2 file over NBD, you generally want to
> have:
>
> qemu-nbd using '-f qcow2' => raw view => qemu-img using '-f raw'
>
> to expose only the logical contents over the wire.  It is also
> possible to flip the responsibility:
>
> qemu-nbd using '-f raw' => qcow2 view => qemu-img using '-f qcow2'
>
> to expose the bare-metal qcow2 contents over the wire, but that gets
> less testing, in part because if you make the image writable, it tends
> to cause problems if the client writing to the qcow2 layer needs to
> allocate (since NBD does not have a resize command).  Having the
> server open the file as qcow2 and only serving raw contents means the
> server can resize transparently.  What's more, block status commands
> over NBD only work when the server is aware of the qcow2 nature of the
> file it is serving (if you expose qcow2 bits over the wire, the server
> treats the entire file as allocated, and there is is no dirty bitmap
> context for the client to read over NBD).
>
> Therefore, 'start' and 'offset' are going to be identical if you are
> using qemu-img map to read bitmaps from a server, since bitmaps can
> only be read when the wire has the raw view (not the qcow2 view).
>
> But when you add x-dirty-bitmap into the mix, you are asking qemu to
> DISREGARD the normal rules of backing file information and instead
> report on dirty bitmap information as if it were backing file info.
> This means that anywhere the dirty bitmap response differs from a
> normal backing file response, the output of qemu-img is reporting
> garbage data (for example, the 'present' bit is now bogus, which
> explains why the rows where qemu-img claims 'present' is false omit an
> 'offset').  Only 'start', 'length', and 'data' matter when using
> x-dirty-bitmap, with 'data=false' meaning the section was reported
> dirty, and 'data=true' meaning the section was reported unchanged.
>
> And if that is confusing, well yeah. Which is why I recommend using
> libnbd's nbdinfo --map, where the output is more obvious.
>
> >
> > root@be-proxmox1:/# qemu-img map --output=json --image-opts
> > "$IMG,x-dirty-bitmap=qemu:dirty-bitmap:bitmap1"
> >   [{ "start": 0, "length": 196608, "depth": 0, "present": true, "zero":
> > false, "data": true, "compressed": false, "offset": 0},
>
> The extent starting at logical offset 0 and lasting 196608 bytes is
> unchanged.
>
> > { "start": 196608, "length": 65536, "depth": 0, "present": false, "zero":
> > false, "data": false, "compressed": false},
>
> The extent starting at 196608 and lasting 65536 bytes is dirty
> (altered since the point in time when the bitmap was created).
>
> > > > qemu-img
> > > > map with x-dirty-bitmap image-opts.
> > >
> > > Here, this works, but feels like a hack, because it is relying on the
> > > x-dirty-bitmap feature of qemu.  The libnbd project ships with an
> > > application 'nbdinfo --map' that can read the same information as
> > > 'qemu-img map' but with a much nicer layout.  It's not going to
> > > necessarily be faster, but because it is a fully-supported feature of
> > > libnbd rather than a hack in qemu, it may prove more stable in the
> > > long run, and certainly easier to understand.
>
>
> For a worked example:
>
> # Create an image, dirty two different offsets, with a bitmap created in
> between
> $ qemu-img create -f qcow2 foo.qcow2 3M
> Formatting 'foo.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off
> compression_type=zlib size=3145728 lazy_refcounts=off refcount_bits=16
> $ qemu-io -f qcow2 foo.qcow2 -c 'w 1M 512'
> wrote 512/512 bytes at offset 1048576
> 512 bytes, 1 ops; 00.01 sec (42.906 KiB/sec and 85.8112 ops/sec)
> $ qemu-img bitmap -f qcow2 foo.qcow2 --add b1
> $ qemu-io -f qcow2 foo.qcow2 -c 'w 2M 512'
> wrote 512/512 bytes at offset 2097152
> 512 bytes, 1 ops; 00.00 sec (107.735 KiB/sec and 215.4704 ops/sec)
>
> # Now, expose the raw bytes of the image over NBD, and inspect with nbdinfo
>
> $ qemu-nbd -f qcow2 foo.qcow2 -A -Bb1 -t
> $ nbdinfo --map=qemu:dirty-bitmap:b1 nbd://localhost
>          0     2097152    0  clean
>    2097152       65536    1  dirty
>    2162688      983040    0  clean
> $ nbdinfo --map nbd://localhost
>          0     1048576    3  hole,zero
>    1048576        4096    0  data
>    1052672       61440    2  zero
>    1114112      983040    3  hole,zero
>    2097152        4096    0  data
>    2101248       61440    2  zero
>    2162688      983040    3  hole,zero
>
> Comparing those to qemu-img map --output=json should be instructive.
>
>
> --
> Eric Blake, Principal Software Engineer
> Red Hat, Inc.
> Virtualization:  qemu.org | libguestfs.org
>
>

Reply via email to