# HG changeset patch # User David Scott # Date 1282565811 -3600 # Node ID 980bea836c4e7e93b586f42e632bdf3c4a863cdb # Parent 5205cfa6a3251017698baffa7825024823705314 CA-43021: When copying a VDI and using the BATs for acceleration, remember to union the BATs of the whole vhd chain. If anything goes wrong in the chain analysis, fall back to normal copy. Signed-off-by: David Scott diff -r 5205cfa6a325 -r 980bea836c4e ocaml/xapi/OMakefile --- a/ocaml/xapi/OMakefile Mon Aug 23 13:16:51 2010 +0100 +++ b/ocaml/xapi/OMakefile Mon Aug 23 13:16:51 2010 +0100 @@ -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 @@ OCamlProgram(http_test, http_test) OCamlProgram(sparse_dd, sparse_dd) +OCamlProgram(show_bat, show_bat) COMMON = \ xapi_templates \ diff -r 5205cfa6a325 -r 980bea836c4e ocaml/xapi/sparse_dd.ml --- a/ocaml/xapi/sparse_dd.ml Mon Aug 23 13:16:51 2010 +0100 +++ b/ocaml/xapi/sparse_dd.ml Mon Aug 23 13:16:51 2010 +0100 @@ -237,7 +237,7 @@ 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 @@ | 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 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