[Libguestfs] [PATCH] nbdcopy: Speed up raw images copy
Eric Blake
eblake at redhat.com
Fri Feb 19 14:02:06 UTC 2021
On 2/18/21 5:32 PM, Nir Soffer wrote:
> When exporting sparse raw image, qemu-nbd reports unallocated area as
> zero:
>
> $ qemu-nbd --persistent --socket /tmp/nbd.sock --read-only --shared=10 \
> --format raw empty-6g.raw --cache=none --aio=native
>
> $ nbdinfo --map nbd+unix:///?socket=/tmp/nbd.sock
> 0 6442450944 2 zero
>
More precisely, lseek(SEEK_HOLE) only tells us what areas of the file
read as zero; it does NOT tell us if that area of the file is also
allocated (for that, you need the FIEMAP ioctl, but that is a
performance hit). Yes, it's a bit confusing that SEEK_HOLE can't
identify actual holes: when it was first introduced by Solaris, the only
way to have a sparse file was with holes that read as zero, and it was
only with later filesystems on Linux where file allocation was made
independent from read-as-zero, making SEEK_HOLE a bit of a misnomer.
It would be nice if the kernel could give us an easy way to learn which
portions of a file are allocated.
> When using qcow2 image, it reports unallocated areas as a hole:
>
> $ qemu-nbd --persistent --socket /tmp/nbd.sock --read-only --shared=10 \
> --format qcow2 empty-6g.qcow2 --cache=none --aio=native
>
> $ nbdinfo --map nbd+unix:///?socket=/tmp/nbd.sock
> 0 6442450944 3 hole,zero
>
> Since nbdcopy is ignoring the ZERO flag and using only the HOLE flag,
> coping raw images is extremely slow:
>
> +++ b/copy/multi-thread-copying.c
> @@ -157,8 +157,8 @@ worker_thread (void *indexp)
> char *data;
> size_t len;
>
> - if (exts.ptr[i].hole) {
> - /* The source is a hole so we can proceed directly to
> + if (exts.ptr[i].zero) {
> + /* The source is zero so we can proceed directly to
> * skipping, trimming or writing zeroes at the destination.
> +++ b/copy/nbd-ops.c
> @@ -190,8 +190,14 @@ add_extent (void *vp, const char *metacontext,
>
> e.offset = offset;
> e.length = entries[i];
> - /* Note we deliberately don't care about the ZERO flag. */
> - e.hole = (entries[i+1] & LIBNBD_STATE_HOLE) != 0;
> +
> + /*
> + * Note we deliberately don't care about the HOLE flag. There is no need to
> + * read extent that reads as zeroes. We will convert to it to a hole or
> + * allocated extents based on the command line arguments.
> + */
> + e.zero = (entries[i+1] & LIBNBD_STATE_ZERO) != 0;
But this patch is absolutely correct: we care less about the allocation
pattern and more whether we know the data reads as zeroes. So checking
for holes is not the right metric, and this patch is correct.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization: qemu.org | libvirt.org
More information about the Libguestfs
mailing list