Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
file: Support zero without ZERO_RANGE
File systems not supporting FALLOC_FL_ZERO_RANGE yet fall back to manual
zeroing.

We can avoid this by combining two fallocate calls:

    fallocate(FALLOC_FL_PUNCH_HOLE)
    fallocate(0)

Based on my tests this is much more efficient compared to manual
zeroing. The idea came from this qemu patch:
qemu/qemu@1cdc3239f1bb

Here is an example run with NFS 4.2 without this change, converting
fedora 27 image created with virt-builder:

$ export SOCK=/tmp/nbd.sock
$ export FILE=/nfs-mount/fedora-27.img
$ src/nbdkit plugins/file/.libs/nbdkit-file-plugin.so file=$FILE -U $SOCK

$ time qemu-img convert -n -f raw -O raw /var/tmp/fedora-27.img nbd:unix:/tmp/nbd.sock

real	0m17.481s
user	0m0.199s
sys	0m0.691s

$ time qemu-img convert -n -f raw -O raw -W /var/tmp/fedora-27.img nbd:unix:/tmp/nbd.sock

real	0m17.072s
user	0m0.191s
sys	0m0.738s

With this change:

$ time qemu-img convert -n -f raw -O raw /var/tmp/fedora-27.img nbd:unix:/tmp/nbd.sock

real	0m6.285s
user	0m0.217s
sys	0m0.829s

$ time qemu-img convert -n -f raw -O raw -W /var/tmp/fedora-27.img nbd:unix:/tmp/nbd.sock

real	0m3.967s
user	0m0.193s
sys	0m0.702s

Note: the image is sparse, but nbdkit creates a fully allocated image.
This may be a bug in nbdkit or qemu-img.
Message-Id: <20180819165655.21785-3-nsoffer@redhat.com>
  • Loading branch information
nirs authored and ebblake committed Aug 20, 2018
1 parent 757f525 commit 407f8dd
Showing 1 changed file with 32 additions and 0 deletions.
32 changes: 32 additions & 0 deletions plugins/file/file.c
Expand Up @@ -121,6 +121,7 @@ struct handle {
int fd;
bool can_punch_hole;
bool can_zero_range;
bool can_fallocate;
};

/* Create the per-connection handle. */
Expand Down Expand Up @@ -161,6 +162,8 @@ file_open (int readonly)
h->can_zero_range = false;
#endif

h->can_fallocate = true;

return h;
}

Expand Down Expand Up @@ -301,6 +304,35 @@ file_zero (void *handle, uint32_t count, uint64_t offset, int may_trim)
}
#endif

#ifdef FALLOC_FL_PUNCH_HOLE
/* If we can punch hole but may not trim, we can combine punching hole and
* fallocate to zero a range. This is expected to be more efficient than
* writing zeros manually. */
if (h->can_punch_hole && h->can_fallocate) {
r = do_fallocate (h->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
offset, count);
if (r == 0) {
r = do_fallocate (h->fd, 0, offset, count);
if (r == 0)
return 0;

if (errno != EOPNOTSUPP) {
nbdkit_error ("zero: %m");
return -1;
}

h->can_fallocate = false;
} else {
if (errno != EOPNOTSUPP) {
nbdkit_error ("zero: %m");
return -1;
}

h->can_punch_hole = false;
}
}
#endif

/* Trigger a fall back to writing */
errno = EOPNOTSUPP;
return -1;
Expand Down

0 comments on commit 407f8dd

Please sign in to comment.