Skip to content

Commit 125cf6e

Browse files
authored
ocaml/libs: Check if blocks are filled with zeros in vhd_format (#6720)
`find_data_blocks` is used to determine which blocks need to be copied to the destination VHD file during export. It uses `lseek(SEEK_DATA)` to skip "holes" in files. Raw files presented by the storage layer, however, do not have holes, instead returning blocks filled with zeros. This means that `vhd-tool` ends up allocating every single block (even if all of them contain zeroes and no actual data). In addition to using `lseek_data`, read the whole block and check if it only contains zeros. This avoids allocating zero blocks and greatly speeds up export from raw to vhd (which happens when exporting qcow2 to vhd as well). Before this fix, when exporting a QCOW2-backed VDI (which vhd-tool falls back to treating as "raw"): $ xe vdi-export uuid=VDI_UUID filename=test.vhd format=vhd $ ll -h test.vhd 2.1G test.vhd Compared to the qcow2 backing file: $ ll -h /var/run/sr-mount/SR_UUID/VDI_UUID.qcow2 165M /var/run/sr-mount/SR_UUID/VDI_UUID.qcow2 After this fix: $ ll -h test.vhd 219M test.vhd
2 parents 73de328 + 8e511dc commit 125cf6e

File tree

1 file changed

+11
-3
lines changed
  • ocaml/libs/vhd/vhd_format

1 file changed

+11
-3
lines changed

ocaml/libs/vhd/vhd_format/f.ml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3273,16 +3273,24 @@ functor
32733273
open Raw
32743274

32753275
let vhd t =
3276-
let include_block block_size index =
3276+
let include_block block_size index zero buffer =
32773277
(* is the next data byte in the next block? *)
32783278
let offset = Int64.(mul block_size (of_int index)) in
32793279
F.lseek_data t.Raw.handle offset >>= fun data ->
3280-
return Int64.(add offset block_size > data)
3280+
if Int64.(add offset block_size > data) then
3281+
(* Check if the block is filled with zeros *)
3282+
really_read t.Raw.handle offset buffer >>= fun () ->
3283+
return (not (Cstruct.equal buffer zero))
3284+
else
3285+
return false
32813286
in
32823287
let find_data_blocks ~blocks ~block_size =
3288+
(* Cstruct.create fills the buffer with 0 bytes *)
3289+
let zero = Cstruct.create (Int64.to_int block_size) in
3290+
let buffer = Memory.alloc (Int64.to_int block_size) in
32833291
let rec loop index acc =
32843292
if index < blocks then
3285-
include_block block_size index >>= function
3293+
include_block block_size index zero buffer >>= function
32863294
| true ->
32873295
loop (index + 1) (index :: acc)
32883296
| false ->

0 commit comments

Comments
 (0)