|
|
696189 |
From 96efdcf54c887ae88d54332df12a5f5dd962fd0a Mon Sep 17 00:00:00 2001
|
|
|
696189 |
From: "Richard W.M. Jones" <rjones@redhat.com>
|
|
|
696189 |
Date: Fri, 15 Jul 2022 11:25:45 +0100
|
|
|
696189 |
Subject: [PATCH] output: Permit output modes to wait on the local NBD server
|
|
|
696189 |
|
|
|
696189 |
Output.output_to_local_file is used by several output modes that write
|
|
|
696189 |
to local files or devices. It launches an instance of qemu-nbd or
|
|
|
696189 |
nbdkit connected to the local file.
|
|
|
696189 |
|
|
|
696189 |
Previously we unconditionally added an On_exit handler to kill the NBD
|
|
|
696189 |
server. This is usually safe because nbdcopy --flush has guaranteed
|
|
|
696189 |
that the data was written through to permanent storage, and so killing
|
|
|
696189 |
the NBD server is just there to prevent orphaned processes.
|
|
|
696189 |
|
|
|
696189 |
However for output to RHV (-o rhv) we actually need the NBD server to
|
|
|
696189 |
be cleaned up before we exit. See the analysis here:
|
|
|
696189 |
|
|
|
696189 |
https://bugzilla.redhat.com/show_bug.cgi?id=1953286#c26
|
|
|
696189 |
|
|
|
696189 |
Allow an alternate strategy of waiting for the NBD server to exit
|
|
|
696189 |
during virt-v2v shutdown.
|
|
|
696189 |
|
|
|
696189 |
We only need this in virt-v2v so implement it here instead of pushing
|
|
|
696189 |
it all the way into the On_exit module.
|
|
|
696189 |
|
|
|
696189 |
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
|
|
|
696189 |
(cherry picked from commit e2a1a7b4dfb6a9e44260da10a7e7029c09753b5c)
|
|
|
696189 |
---
|
|
|
696189 |
output/output.ml | 91 ++++++++++++++++++++++++++++-------------------
|
|
|
696189 |
output/output.mli | 17 +++++++--
|
|
|
696189 |
2 files changed, 69 insertions(+), 39 deletions(-)
|
|
|
696189 |
|
|
|
696189 |
diff --git a/output/output.ml b/output/output.ml
|
|
|
696189 |
index 496c32b6..8f83a324 100644
|
|
|
696189 |
--- a/output/output.ml
|
|
|
696189 |
+++ b/output/output.ml
|
|
|
696189 |
@@ -69,7 +69,10 @@ let error_if_disk_count_gt dir n =
|
|
|
696189 |
if Sys.file_exists socket then
|
|
|
696189 |
error (f_"this output module doesn't support copying more than %d disks") n
|
|
|
696189 |
|
|
|
696189 |
+type on_exit_kill = Kill | KillAndWait
|
|
|
696189 |
+
|
|
|
696189 |
let output_to_local_file ?(changeuid = fun f -> f ()) ?(compressed = false)
|
|
|
696189 |
+ ?(on_exit_kill = Kill)
|
|
|
696189 |
output_alloc output_format filename size socket =
|
|
|
696189 |
(* Check nbdkit is installed and has the required plugin. *)
|
|
|
696189 |
if not (Nbdkit.is_installed ()) then
|
|
|
696189 |
@@ -94,46 +97,60 @@ let output_to_local_file ?(changeuid = fun f -> f ()) ?(compressed = false)
|
|
|
696189 |
fun () -> g#disk_create ?preallocation filename output_format size
|
|
|
696189 |
);
|
|
|
696189 |
|
|
|
696189 |
- match output_format with
|
|
|
696189 |
- | "raw" ->
|
|
|
696189 |
- let cmd = Nbdkit.create "file" in
|
|
|
696189 |
- Nbdkit.add_arg cmd "file" filename;
|
|
|
696189 |
- if Nbdkit.version nbdkit_config >= (1, 22, 0) then (
|
|
|
696189 |
- let cmd = Nbdkit.add_arg cmd "cache" "none" in
|
|
|
696189 |
- cmd
|
|
|
696189 |
- );
|
|
|
696189 |
- let _, pid = Nbdkit.run_unix socket cmd in
|
|
|
696189 |
+ let pid =
|
|
|
696189 |
+ match output_format with
|
|
|
696189 |
+ | "raw" ->
|
|
|
696189 |
+ let cmd = Nbdkit.create "file" in
|
|
|
696189 |
+ Nbdkit.add_arg cmd "file" filename;
|
|
|
696189 |
+ if Nbdkit.version nbdkit_config >= (1, 22, 0) then (
|
|
|
696189 |
+ let cmd = Nbdkit.add_arg cmd "cache" "none" in
|
|
|
696189 |
+ cmd
|
|
|
696189 |
+ );
|
|
|
696189 |
+ let _, pid = Nbdkit.run_unix socket cmd in
|
|
|
696189 |
+ pid
|
|
|
696189 |
|
|
|
696189 |
- (* --exit-with-parent should ensure nbdkit is cleaned
|
|
|
696189 |
- * up when we exit, but it's not supported everywhere.
|
|
|
696189 |
- *)
|
|
|
696189 |
- On_exit.kill pid
|
|
|
696189 |
+ | "qcow2" ->
|
|
|
696189 |
+ let cmd =
|
|
|
696189 |
+ if compressed then (
|
|
|
696189 |
+ let qemu_quote str = String.replace str "," ",," in
|
|
|
696189 |
+ let image_opts = [ "driver=compress";
|
|
|
696189 |
+ "file.driver=qcow2";
|
|
|
696189 |
+ "file.file.driver=file";
|
|
|
696189 |
+ "file.file.filename=" ^ qemu_quote filename ] in
|
|
|
696189 |
+ let image_opts = String.concat "," image_opts in
|
|
|
696189 |
+ let cmd = QemuNBD.create image_opts in
|
|
|
696189 |
+ QemuNBD.set_image_opts cmd true;
|
|
|
696189 |
+ cmd
|
|
|
696189 |
+ )
|
|
|
696189 |
+ else (* not compressed *) (
|
|
|
696189 |
+ let cmd = QemuNBD.create filename in
|
|
|
696189 |
+ QemuNBD.set_format cmd (Some "qcow2");
|
|
|
696189 |
+ cmd
|
|
|
696189 |
+ ) in
|
|
|
696189 |
+ QemuNBD.set_snapshot cmd false;
|
|
|
696189 |
+ let _, pid = QemuNBD.run_unix socket cmd in
|
|
|
696189 |
+ pid
|
|
|
696189 |
|
|
|
696189 |
- | "qcow2" ->
|
|
|
696189 |
- let cmd =
|
|
|
696189 |
- if compressed then (
|
|
|
696189 |
- let qemu_quote str = String.replace str "," ",," in
|
|
|
696189 |
- let image_opts = [ "driver=compress";
|
|
|
696189 |
- "file.driver=qcow2";
|
|
|
696189 |
- "file.file.driver=file";
|
|
|
696189 |
- "file.file.filename=" ^ qemu_quote filename ] in
|
|
|
696189 |
- let image_opts = String.concat "," image_opts in
|
|
|
696189 |
- let cmd = QemuNBD.create image_opts in
|
|
|
696189 |
- QemuNBD.set_image_opts cmd true;
|
|
|
696189 |
- cmd
|
|
|
696189 |
- )
|
|
|
696189 |
- else (* not compressed *) (
|
|
|
696189 |
- let cmd = QemuNBD.create filename in
|
|
|
696189 |
- QemuNBD.set_format cmd (Some "qcow2");
|
|
|
696189 |
- cmd
|
|
|
696189 |
- ) in
|
|
|
696189 |
- QemuNBD.set_snapshot cmd false;
|
|
|
696189 |
- let _, pid = QemuNBD.run_unix socket cmd in
|
|
|
696189 |
- On_exit.kill pid
|
|
|
696189 |
+ | _ ->
|
|
|
696189 |
+ error (f_"output mode only supports raw or qcow2 format (format: %s)")
|
|
|
696189 |
+ output_format in
|
|
|
696189 |
+
|
|
|
696189 |
+ match on_exit_kill with
|
|
|
696189 |
+ | Kill ->
|
|
|
696189 |
+ (* Kill the NBD server on exit. (For nbdkit we use --exit-with-parent
|
|
|
696189 |
+ * but it's not supported everywhere).
|
|
|
696189 |
+ *)
|
|
|
696189 |
+ On_exit.kill pid
|
|
|
696189 |
|
|
|
696189 |
- | _ ->
|
|
|
696189 |
- error (f_"output mode only supports raw or qcow2 format (format: %s)")
|
|
|
696189 |
- output_format
|
|
|
696189 |
+ | KillAndWait ->
|
|
|
696189 |
+ On_exit.f (
|
|
|
696189 |
+ fun () ->
|
|
|
696189 |
+ kill pid Sys.sigterm;
|
|
|
696189 |
+ (* Errors from the NBD server don't matter. On successful
|
|
|
696189 |
+ * completion we've already committed the data to disk.
|
|
|
696189 |
+ *)
|
|
|
696189 |
+ ignore (waitpid [] pid)
|
|
|
696189 |
+ )
|
|
|
696189 |
|
|
|
696189 |
let disk_path os name i =
|
|
|
696189 |
let outdisk = sprintf "%s/%s-sd%s" os name (drive_name i) in
|
|
|
696189 |
diff --git a/output/output.mli b/output/output.mli
|
|
|
696189 |
index c1f0f53d..c4486311 100644
|
|
|
696189 |
--- a/output/output.mli
|
|
|
696189 |
+++ b/output/output.mli
|
|
|
696189 |
@@ -83,14 +83,27 @@ val error_if_disk_count_gt : string -> int -> unit
|
|
|
696189 |
"in[n]" in the v2v directory [dir]. If the socket exists, [error] is
|
|
|
696189 |
called. *)
|
|
|
696189 |
|
|
|
696189 |
+type on_exit_kill = Kill | KillAndWait
|
|
|
696189 |
+
|
|
|
696189 |
val output_to_local_file : ?changeuid:((unit -> unit) -> unit) ->
|
|
|
696189 |
- ?compressed:bool ->
|
|
|
696189 |
+ ?compressed:bool -> ?on_exit_kill:on_exit_kill ->
|
|
|
696189 |
Types.output_allocation ->
|
|
|
696189 |
string -> string -> int64 -> string ->
|
|
|
696189 |
unit
|
|
|
696189 |
(** When an output mode wants to create a local file with a
|
|
|
696189 |
particular format (only "raw" or "qcow2" allowed) then
|
|
|
696189 |
- this common function can be used. *)
|
|
|
696189 |
+ this common function can be used.
|
|
|
696189 |
+
|
|
|
696189 |
+ Optional parameter [?on_exit_kill] controls how the NBD server
|
|
|
696189 |
+ is cleaned up. The default is {!Kill} which registers an
|
|
|
696189 |
+ {!On_exit.kill} handler that kills (but does not wait for)
|
|
|
696189 |
+ the server when virt-v2v exits. Most callers should use this.
|
|
|
696189 |
+
|
|
|
696189 |
+ Setting [~on_exit_kill:KillAndWait] should be used if the NBD
|
|
|
696189 |
+ server must fully exit before we continue with the rest of
|
|
|
696189 |
+ virt-v2v shut down. This is only necessary if some other action
|
|
|
696189 |
+ (such as unmounting a host filesystem or removing a host device)
|
|
|
696189 |
+ depends on the NBD server releasing resources. *)
|
|
|
696189 |
|
|
|
696189 |
val disk_path : string -> string -> int -> string
|
|
|
696189 |
(** For [-o disk|qemu], return the output disk name of the i'th disk,
|