Laszlo Ersek noted that the original example we had did not work
properly if the size of the disk was larger than around 2G.
The nbd_block_status API is really difficult to use correctly! In
particular it is not guaranteed that the server will return extents
covering the size requested. It's also not guaranteed that a bad
server will return any base:allocation extents at all (although such a
server would not be conforming - the protocol says that servers must
always make forward progress).
This commit attempts a fix, although it is not complete especially if
the server is badly behaved. It also makes the output look a bit
better by aligning the columns. Also we use nbdkit-sparse-random-
plugin with a larger size to test the > 2G case.
---
ocaml/examples/extents.ml | 53 ++++++++++++++++++++-------------------
1 file changed, 27 insertions(+), 26 deletions(-)
diff --git a/ocaml/examples/extents.ml b/ocaml/examples/extents.ml
index 6fa70e087..e4422b270 100644
--- a/ocaml/examples/extents.ml
+++ b/ocaml/examples/extents.ml
@@ -4,32 +4,33 @@ let () =
let nbd = NBD.create () in
NBD.add_meta_context nbd "base:allocation";
NBD.connect_command nbd
- ["nbdkit"; "-s";
"--exit-with-parent"; "memory"; "size=128K"];
-
- (* Write some sectors. *)
- let data_sector = Bytes.make 512 'a' in
- let zero_sector = Bytes.make 512 '\000' in
- NBD.pwrite nbd data_sector 0_L;
- NBD.pwrite nbd zero_sector 32768_L;
- NBD.pwrite nbd data_sector 65536_L;
+ ["nbdkit"; "-s";
"--exit-with-parent"; "-r";
+ "sparse-random"; "8G"];
(* Read the extents and print them. *)
let size = NBD.get_size nbd in
- NBD.block_status nbd size 0_L (
- fun meta _ entries err ->
- printf "err=%d\n" !err;
- if meta = "base:allocation" then (
- printf "index\tlength\tflags\n";
- for i = 0 to Array.length entries / 2 - 1 do
- let flags =
- match entries.(i*2+1) with
- | 0_l -> "data"
- | 1_l -> "hole"
- | 2_l -> "zero"
- | 3_l -> "hole+zero"
- | i -> sprintf "unknown (%ld)" i in
- printf "%d:\t%ld\t%s\n" i entries.(i*2) flags
- done
- );
- 0
- )
+ let fetch_offset = ref 0_L in
+ while !fetch_offset < size do
+ let remaining = Int64.sub size !fetch_offset in
+ let fetch_size = min remaining 0x8000_0000_L in
+ NBD.block_status nbd fetch_size !fetch_offset (
+ fun meta _ entries err ->
+ printf "nbd_block_status callback: meta=%s err=%d\n" meta !err;
+ if meta = "base:allocation" then (
+ printf "index\t%-20s %-20s %s\n" "offset"
"length" "flags";
+ for i = 0 to Array.length entries / 2 - 1 do
+ let len = Int64.of_int32 entries.(i*2)
+ and flags =
+ match entries.(i*2+1) with
+ | 0_l -> "data"
+ | 1_l -> "hole"
+ | 2_l -> "zero"
+ | 3_l -> "hole+zero"
+ | i -> sprintf "unknown (%ld)" i in
+ printf "%d:\t%-20Ld %-20Ld %s\n" i !fetch_offset len flags;
+ fetch_offset := Int64.add !fetch_offset len
+ done;
+ );
+ 0
+ ) (* NBD.block_status *)
+ done
--
2.32.0