On 12/11/21 14:41, Richard W.M. Jones wrote:
 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;
Should we use right-justification for the numbers?
Reviewed-by: Laszlo Ersek <lersek(a)redhat.com>
Thanks!
Laszlo
 +            fetch_offset := Int64.add !fetch_offset len
 +          done;
 +        );
 +        0
 +    ) (* NBD.block_status *)
 +  done