]> xenbits.xensource.com Git - xcp/xen-api.git/commitdiff
CA-43021: When copying a VDI and using the BATs for acceleration, remember to union...
authorDavid Scott <dave.scott@eu.citrix.com>
Mon, 23 Aug 2010 12:16:51 +0000 (13:16 +0100)
committerDavid Scott <dave.scott@eu.citrix.com>
Mon, 23 Aug 2010 12:16:51 +0000 (13:16 +0100)
If anything goes wrong in the chain analysis, fall back to normal copy.

Signed-off-by: David Scott <dave.scott@eu.citrix.com>
ocaml/xapi/OMakefile
ocaml/xapi/sparse_dd.ml

index 0b79cbdd1343c6eff41b6ced0729252950830516..a6c4c5b73669f6e9467eecafe87bc272b55cbf7f 100644 (file)
@@ -1,4 +1,4 @@
-OCAMLPACKS    = xml-light2 cdrom pciutil sexpr log stunnel http-svr rss xen-utils netdev tapctl vhd
+OCAMLPACKS    = xml-light2 cdrom pciutil sexpr log stunnel http-svr rss xen-utils netdev tapctl vhd xs
 OCAML_LIBS    =  ../util/version ../util/vm_memory_constraints ../util/sanitycheck ../util/stats \
        ../idl/ocaml_backend/common ../idl/ocaml_backend/client ../idl/ocaml_backend/server ../util/ocamltest
 OCAMLINCLUDES = ../idl ../idl/ocaml_backend \
@@ -33,6 +33,7 @@ OCAMLPACKS = $(if $(equal $(COMPILE_XENSTUFF), yes), $(XEN_OCAMLPACKS) $(OCAMLPA
 
 OCamlProgram(http_test, http_test)
 OCamlProgram(sparse_dd, sparse_dd)
+OCamlProgram(show_bat, show_bat)
 
 COMMON = \
        xapi_templates \
index 993d087ff240aeba5d277f0433d73790a415898a..fe1f9a5ff2c612e1a33d35ae5fc8e4a4692b2651 100644 (file)
@@ -237,7 +237,7 @@ let vhd_of_device path =
                                        let backend = xs.Xs.read (Printf.sprintf "device/vbd/%d/backend" id) in
                                        let params = xs.Xs.read (Printf.sprintf "%s/params" backend) in
                                        match String.split '/' backend with
-                                       | "local" :: "domain" :: bedomid :: _ ->
+                                       | "" :: "local" :: "domain" :: bedomid :: _ ->
                                                assert (self = bedomid);
                                                Some params
                                        | _ -> raise Not_found
@@ -263,15 +263,43 @@ let vhd_of_device path =
                | None -> None
                end
 
+let deref_symlinks path = 
+       let rec inner seen_already path = 
+               if List.mem path seen_already
+               then failwith "Circular symlink";
+               let stats = Unix.lstat path in
+               if stats.Unix.st_kind = Unix.S_LNK
+               then inner (path :: seen_already) (Unix.readlink path)
+               else path in
+       inner [] path
+
+let with_rdonly_vhd path f = 
+       let h = Vhd._open path [ Vhd.Open_rdonly ] in
+       finally
+       (fun () -> f h)
+       (fun () -> Vhd.close h)
+
+let parent_of_vhd vhd = 
+       let vhd' = deref_symlinks vhd in
+       let parent = with_rdonly_vhd vhd' Vhd.get_parent in
+       (* Make path absolute *)
+       if String.length parent > 0 && String.startswith "./" parent
+       then Filename.concat (Filename.dirname vhd') parent
+       else parent
+
+let rec chain_of_vhd vhd = 
+       try
+               let p = parent_of_vhd vhd in
+               vhd :: (chain_of_vhd p)
+       with (Failure "Disk is not a differencing disk") -> [ vhd ]
+
 (** Given a vhd filename, return the BAT *)
 let bat vhd = 
-       let h = Vhd._open vhd [ Vhd.Open_rdonly ] in
-       finally
-       (fun () -> 
+       with_rdonly_vhd vhd
+       (fun h ->
                let b = Vhd.get_bat h in
                let b' = List.map_tr (fun (s, l) -> 2L ** mib ** (Int64.of_int s), 2L ** mib ** (Int64.of_int l)) b in
                Bat.of_list b')
-       (fun () -> Vhd.close h)
 
 (* Record when the binary started for performance measuring *)
 let start = Unix.gettimeofday ()
@@ -338,9 +366,19 @@ let _ =
         let size = Some !size in
        let src_vhd = vhd_of_device !src and dest_vhd = vhd_of_device !dest in
        Printf.printf "auto-detect src vhd:  %s\n" (Opt.default "None" (Opt.map (fun x -> "Some " ^ x) src_vhd));
-       let src_bat = Opt.map bat src_vhd in 
+       let bat = match src_vhd with
+       | Some vhd ->
+               (try
+                       let chain = chain_of_vhd vhd in
+                       Printf.printf "chain: %s\n" (String.concat "; " chain);
+                       let empty = Bat.of_list [] in
+                       Some (List.fold_left Bat.union empty (List.map bat chain))
+               with e ->
+                       Printf.printf "Caught exception: %s while calculating BAT. Ignoring all BAT information\n" (Printexc.to_string e);
+                       None)
+       | None -> None in
        progress_cb 0.;
-       let stats = file_dd ~progress_cb ?size ?bat:src_bat !prezeroed !src !dest in
+       let stats = file_dd ~progress_cb ?size ?bat !prezeroed !src !dest in
        Printf.printf "Time: %.2f seconds\n" (Unix.gettimeofday () -. start);
        Printf.printf "\nNumber of writes: %d\n" stats.writes;
        Printf.printf "Number of bytes: %Ld\n" stats.bytes