Skip to content

Commit 407f8dd

Browse files
nirsebblake
authored andcommitted
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>
1 parent 757f525 commit 407f8dd

File tree

1 file changed

+32
-0
lines changed

1 file changed

+32
-0
lines changed

plugins/file/file.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ struct handle {
121121
int fd;
122122
bool can_punch_hole;
123123
bool can_zero_range;
124+
bool can_fallocate;
124125
};
125126

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

165+
h->can_fallocate = true;
166+
164167
return h;
165168
}
166169

@@ -301,6 +304,35 @@ file_zero (void *handle, uint32_t count, uint64_t offset, int may_trim)
301304
}
302305
#endif
303306

307+
#ifdef FALLOC_FL_PUNCH_HOLE
308+
/* If we can punch hole but may not trim, we can combine punching hole and
309+
* fallocate to zero a range. This is expected to be more efficient than
310+
* writing zeros manually. */
311+
if (h->can_punch_hole && h->can_fallocate) {
312+
r = do_fallocate (h->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
313+
offset, count);
314+
if (r == 0) {
315+
r = do_fallocate (h->fd, 0, offset, count);
316+
if (r == 0)
317+
return 0;
318+
319+
if (errno != EOPNOTSUPP) {
320+
nbdkit_error ("zero: %m");
321+
return -1;
322+
}
323+
324+
h->can_fallocate = false;
325+
} else {
326+
if (errno != EOPNOTSUPP) {
327+
nbdkit_error ("zero: %m");
328+
return -1;
329+
}
330+
331+
h->can_punch_hole = false;
332+
}
333+
}
334+
#endif
335+
304336
/* Trigger a fall back to writing */
305337
errno = EOPNOTSUPP;
306338
return -1;

0 commit comments

Comments
 (0)