Blame SOURCES/0018-qemu-nbd-Implement-output-compression-for-qcow2-file.patch

696189
From 80831868395d161af8c47edf2f54234c63581d8d Mon Sep 17 00:00:00 2001
696189
From: "Richard W.M. Jones" <rjones@redhat.com>
696189
Date: Fri, 28 Jan 2022 09:30:29 +0000
696189
Subject: [PATCH] qemu-nbd: Implement output compression for qcow2 files
696189
696189
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
696189
(cherry picked from commit 71c4301909cb307def02ebcd0e89beee4138e7f2)
696189
---
696189
 lib/qemuNBD.ml    | 11 +++++++++--
696189
 lib/qemuNBD.mli   |  5 +++++
696189
 output/output.ml  | 39 ++++++++++++++++++++++++++++++++++++---
696189
 output/output.mli |  1 +
696189
 4 files changed, 51 insertions(+), 5 deletions(-)
696189
696189
diff --git a/lib/qemuNBD.ml b/lib/qemuNBD.ml
696189
index ae21b17c..bbb65f41 100644
696189
--- a/lib/qemuNBD.ml
696189
+++ b/lib/qemuNBD.ml
696189
@@ -55,14 +55,16 @@ type cmd = {
696189
   disk : string;
696189
   mutable snapshot : bool;
696189
   mutable format : string option;
696189
+  mutable imgopts : bool;
696189
 }
696189
 
696189
-let create disk = { disk; snapshot = false; format = None }
696189
+let create disk = { disk; snapshot = false; format = None; imgopts = false }
696189
 
696189
 let set_snapshot cmd snap = cmd.snapshot <- snap
696189
 let set_format cmd format = cmd.format <- format
696189
+let set_image_opts cmd imgopts = cmd.imgopts <- imgopts
696189
 
696189
-let run_unix socket { disk; snapshot; format } =
696189
+let run_unix socket { disk; snapshot; format; imgopts } =
696189
   assert (disk <> "");
696189
 
696189
   (* Create a temporary directory where we place the PID file. *)
696189
@@ -85,6 +87,11 @@ let run_unix socket { disk; snapshot; format } =
696189
   (* -s adds a protective overlay. *)
696189
   if snapshot then List.push_back args "-s";
696189
 
696189
+  (* --image-opts reinterprets the filename parameter as a set of
696189
+   * image options.
696189
+   *)
696189
+  if imgopts then List.push_back args "--image-opts";
696189
+
696189
   if have_selinux && qemu_nbd_has_selinux_label_option () then (
696189
     List.push_back args "--selinux-label";
696189
     List.push_back args "system_u:object_r:svirt_socket_t:s0"
696189
diff --git a/lib/qemuNBD.mli b/lib/qemuNBD.mli
696189
index e10d3106..afe9d944 100644
696189
--- a/lib/qemuNBD.mli
696189
+++ b/lib/qemuNBD.mli
696189
@@ -43,6 +43,11 @@ val set_snapshot : cmd -> bool -> unit
696189
 val set_format : cmd -> string option -> unit
696189
 (** Set the format [--format] parameter. *)
696189
 
696189
+val set_image_opts : cmd -> bool -> unit
696189
+(** Set whether the [--image-opts] parameter is used.  This changes
696189
+    the meaning of the [filename] parameter to a set of image options.
696189
+    Consult the qemu-nbd man page for more details. *)
696189
+
696189
 val run_unix : string -> cmd -> string * int
696189
 (** Start qemu-nbd command listening on a Unix domain socket,
696189
     waiting for the process to start up.
696189
diff --git a/output/output.ml b/output/output.ml
696189
index 5c6670b9..23c3932d 100644
696189
--- a/output/output.ml
696189
+++ b/output/output.ml
696189
@@ -69,7 +69,7 @@ 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
-let output_to_local_file ?(changeuid = fun f -> f ())
696189
+let output_to_local_file ?(changeuid = fun f -> f ()) ?(compressed = false)
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
@@ -78,6 +78,24 @@ let output_to_local_file ?(changeuid = fun f -> f ())
696189
     error (f_"nbdkit-file-plugin is not installed or not working");
696189
   let nbdkit_config = Nbdkit.config () in
696189
 
696189
+  if compressed then (
696189
+    (* Only allow compressed with -of qcow2. *)
696189
+    if output_format <> "qcow2" then
696189
+      error (f_"‘-oo compressed’ is only allowed when the output format \
696189
+                is a local qcow2-format file, i.e. ‘-of qcow2’");
696189
+
696189
+    (* Check nbdcopy is new enough.  This assumes that the version of
696189
+     * libnbd is the same as the version of nbdcopy, but parsing this
696189
+     * is easier.  We can remove this check when we build-depend on
696189
+     * libnbd >= 1.14.
696189
+     *)
696189
+    let version =
696189
+      NBD.create () |> NBD.get_version |>
696189
+      String.nsplit "." |> List.map int_of_string in
696189
+    if version < [1; 13; 5] then
696189
+      error (f_"-oo compressed option requires nbdcopy >= 1.13.5")
696189
+  );
696189
+
696189
   let g = open_guestfs () in
696189
   let preallocation =
696189
     match output_alloc with
696189
@@ -103,9 +121,24 @@ let output_to_local_file ?(changeuid = fun f -> f ())
696189
      On_exit.kill pid
696189
 
696189
   | "qcow2" ->
696189
-     let cmd = QemuNBD.create filename in
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
-     QemuNBD.set_format cmd (Some "qcow2");
696189
      let _, pid = QemuNBD.run_unix socket cmd in
696189
      On_exit.kill pid
696189
 
696189
diff --git a/output/output.mli b/output/output.mli
696189
index 8d3d6865..c1f0f53d 100644
696189
--- a/output/output.mli
696189
+++ b/output/output.mli
696189
@@ -84,6 +84,7 @@ val error_if_disk_count_gt : string -> int -> unit
696189
     called. *)
696189
 
696189
 val output_to_local_file : ?changeuid:((unit -> unit) -> unit) ->
696189
+                           ?compressed:bool ->
696189
                            Types.output_allocation ->
696189
                            string -> string -> int64 -> string ->
696189
                            unit