Blame SOURCES/0028-output-Permit-output-modes-to-wait-on-the-local-NBD-.patch

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,