Skip to content

Commit 8e511dc

Browse files
committed
ocaml/libs: Check if blocks are filled with zeros in vhd_format
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 Signed-off-by: Andrii Sultanov <[email protected]>
1 parent 61792e7 commit 8e511dc

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)