@@ -306,37 +306,99 @@ let send_one ofd (__context : Context.t) rpc session_id progress refresh_session
306306 | Ok (Some (driver, path)) when driver = " vhd" || driver = " qcow2"
307307 -> (
308308 try
309- (* Read backing file headers, then only read and write
309+ let last_chunk = Int64. ((to_int size - 1 ) / to_int chunk_size) in
310+ if ! Xapi_globs. vhd_legacy_blocks_format then
311+ (* Read backing file headers, then only read and write
310312 allocated clusters from the bitmap *)
311- let cluster_size, cluster_list =
312- match driver with
313- | "vhd" ->
314- Vhd_tool_wrapper. parse_header path
315- | "qcow2" ->
316- Qcow_tool_wrapper. parse_header path
317- | _ ->
318- failwith (Printf. sprintf " %s: unreachable" __FUNCTION__)
319- in
320- let set =
321- get_allocated_chunks_from_clusters cluster_size cluster_list
322- in
323- (* First and last chunks are always written - it's a limitation
313+ let cluster_size, cluster_list =
314+ match driver with
315+ | "vhd" ->
316+ Vhd_tool_wrapper. parse_header path
317+ | "qcow2" ->
318+ Qcow_tool_wrapper. parse_header path
319+ | _ ->
320+ failwith (Printf. sprintf " %s: unreachable" __FUNCTION__)
321+ in
322+ let set =
323+ get_allocated_chunks_from_clusters cluster_size cluster_list
324+ in
325+ (* First and last chunks are always written - it's a limitation
324326 of the XVA format *)
325- let last_chunk =
326- Int64. ((to_int size - to_int chunk_size + 1 ) / to_int chunk_size)
327- in
328- let set = set |> ChunkSet. add 0 |> ChunkSet. add last_chunk in
329- ChunkSet. iter
330- (fun this_chunk_no ->
331- let offset = Int64. (mul (of_int this_chunk_no) chunk_size) in
332- let _ =
333- write_chunk this_chunk_no offset
334- ~write_check: (fun _ _ -> true )
335- ~seek: true ~timeout_workaround: false
336- in
337- ()
338- )
339- set
327+ let set = set |> ChunkSet. add 0 |> ChunkSet. add last_chunk in
328+ ChunkSet. iter
329+ (fun this_chunk_no ->
330+ let offset =
331+ Int64. (mul (of_int this_chunk_no) chunk_size)
332+ in
333+ let _ =
334+ write_chunk this_chunk_no offset
335+ ~write_check: (fun _ _ -> true )
336+ ~seek: true ~timeout_workaround: false
337+ in
338+ ()
339+ )
340+ set
341+ else
342+ let cluster_size, cluster_list =
343+ match driver with
344+ | "vhd" ->
345+ Vhd_tool_wrapper. parse_header_interval path
346+ | "qcow2" ->
347+ Qcow_tool_wrapper. parse_header_interval path
348+ | _ ->
349+ failwith (Printf. sprintf " %s: unreachable" __FUNCTION__)
350+ in
351+ let process_chunk chunk_no ~force =
352+ if force || (chunk_no <> 0 && chunk_no <> last_chunk) then
353+ let offset = Int64. (mul (of_int chunk_no) chunk_size) in
354+ let _ =
355+ write_chunk chunk_no offset
356+ ~write_check: (fun _ _ -> true )
357+ ~seek: true ~timeout_workaround: false
358+ in
359+ ()
360+ in
361+
362+ process_chunk 0 ~force: true ;
363+
364+ let chunk_size = Int64. to_int chunk_size in
365+ let chunks_in_cluster =
366+ (cluster_size + chunk_size - 1 ) / chunk_size
367+ in
368+ (* Iterate over allocated intervals, copying every cluster inside *)
369+ let _ =
370+ List. fold_left
371+ (fun prev_chunk (cluster_no_left , cluster_no_right ) ->
372+ let calc_chunk cluster =
373+ let cluster_offset = cluster * cluster_size in
374+ let chunk_no = cluster_offset / chunk_size in
375+ chunk_no
376+ in
377+ let left_chunk_no = calc_chunk cluster_no_left in
378+ let right_chunk_no =
379+ calc_chunk cluster_no_right + chunks_in_cluster - 1
380+ in
381+
382+ (* If a chunk contains multiple clusters, we could have
383+ already copied it. In that case, start with the
384+ following chunk. *)
385+ let left_chunk_no =
386+ if left_chunk_no = prev_chunk then
387+ left_chunk_no + 1
388+ else
389+ left_chunk_no
390+ in
391+
392+ for i = left_chunk_no to right_chunk_no do
393+ process_chunk i ~force: false
394+ done ;
395+
396+ right_chunk_no
397+ )
398+ (- 1 ) cluster_list
399+ in
400+
401+ process_chunk last_chunk ~force: true
340402 with e ->
341403 debug " %s: Falling back to reading the whole raw disk after %s"
342404 __FUNCTION__ (Printexc. to_string e) ;
0 commit comments