Blame SOURCES/0193-v2v-Support-loading-virtio-win-drivers-from-virtio-w.patch

ffd6ed
From e2a2ea5637b1689c904fe45838d3d58d556b54ea Mon Sep 17 00:00:00 2001
ffd6ed
From: "Richard W.M. Jones" <rjones@redhat.com>
ffd6ed
Date: Mon, 22 Jun 2015 15:13:36 +0100
ffd6ed
Subject: [PATCH] v2v: Support loading virtio-win drivers from virtio-win.iso
ffd6ed
 (RHBZ#1234351).
ffd6ed
ffd6ed
This makes several changes to the handling of virtio-win drivers:
ffd6ed
ffd6ed
The VIRTIO_WIN_DIR environment variable has been renamed
ffd6ed
VIRTIO_WIN (but you can still use the old name).
ffd6ed
ffd6ed
You can point the VIRTIO_WIN either at a RHEL virtio-win directory
ffd6ed
(ie. /usr/share/virtio-win), OR at a loopback-mounted virtio-win ISO,
ffd6ed
OR at the virtio-win.iso file itself.  In the latter case, libguestfs
ffd6ed
is used to open the ISO file and read drivers from it.
ffd6ed
ffd6ed
The code is more flexible about the pathnames of drivers, because the
ffd6ed
paths in the ISO are completely different from the paths in RHEL
ffd6ed
/usr/share/virtio-win.
ffd6ed
ffd6ed
(cherry picked from commit 47b5f245bec908f803f0a89c3b1e3166cfe33aad)
ffd6ed
ffd6ed
Various fixes to make the code compile on RHEL 7.2.
ffd6ed
---
ffd6ed
 v2v/convert_windows.ml | 167 ++++++++++++++++++++++---------------------------
ffd6ed
 v2v/utils.ml           | 154 +++++++++++++++++++++++++++++++++++++++++++++
ffd6ed
 v2v/v2v.ml             |   8 +++
ffd6ed
 v2v/virt-v2v.pod       |   9 ++-
ffd6ed
 4 files changed, 244 insertions(+), 94 deletions(-)
ffd6ed
ffd6ed
diff --git a/v2v/convert_windows.ml b/v2v/convert_windows.ml
ffd6ed
index 1e77369..c11e838 100644
ffd6ed
--- a/v2v/convert_windows.ml
ffd6ed
+++ b/v2v/convert_windows.ml
ffd6ed
@@ -47,9 +47,12 @@ let convert ~verbose ~keep_serial_console (g : G.guestfs) inspect source =
ffd6ed
     try Sys.getenv "VIRT_TOOLS_DATA_DIR"
ffd6ed
     with Not_found -> Config.datadir // "virt-tools" in
ffd6ed
 
ffd6ed
-  let virtio_win_dir =
ffd6ed
-    try Sys.getenv "VIRTIO_WIN_DIR"
ffd6ed
-    with Not_found -> Config.datadir // "virtio-win" in
ffd6ed
+  let virtio_win =
ffd6ed
+    try Sys.getenv "VIRTIO_WIN"
ffd6ed
+    with Not_found ->
ffd6ed
+      try Sys.getenv "VIRTIO_WIN_DIR" (* old name for VIRTIO_WIN *)
ffd6ed
+      with Not_found ->
ffd6ed
+        Config.datadir // "virtio-win" in
ffd6ed
 
ffd6ed
   (* Check if RHEV-APT exists.  This is optional. *)
ffd6ed
   let rhev_apt_exe = virt_tools_data_dir // "rhev-apt.exe" in
ffd6ed
@@ -231,101 +234,83 @@ echo uninstalling Xen PV driver
ffd6ed
     let driverdir = sprintf "%s/Drivers/VirtIO" systemroot in
ffd6ed
     g#mkdir_p driverdir;
ffd6ed
 
ffd6ed
-    (* See if the drivers for this guest are available in virtio_win_dir. *)
ffd6ed
-    let path =
ffd6ed
-      match inspect.i_arch,
ffd6ed
-      inspect.i_major_version, inspect.i_minor_version,
ffd6ed
-      inspect.i_product_variant with
ffd6ed
-      | "i386", 5, 1, _ ->
ffd6ed
-        Some (virtio_win_dir // "drivers/i386/WinXP")
ffd6ed
-      | "i386", 5, 2, _ ->
ffd6ed
-        Some (virtio_win_dir // "drivers/i386/Win2003")
ffd6ed
-      | "i386", 6, 0, _ ->
ffd6ed
-        Some (virtio_win_dir // "drivers/i386/Win2008")
ffd6ed
-      | "i386", 6, 1, _ ->
ffd6ed
-        Some (virtio_win_dir // "drivers/i386/Win7")
ffd6ed
-      | "i386", 6, 2, _ ->
ffd6ed
-        Some (virtio_win_dir // "drivers/i386/Win8")
ffd6ed
-      | "i386", 6, 3, _ ->
ffd6ed
-        Some (virtio_win_dir // "drivers/i386/Win8.1")
ffd6ed
+    (* Load the list of drivers available. *)
ffd6ed
+    let drivers = find_virtio_win_drivers ~verbose virtio_win in
ffd6ed
 
ffd6ed
-      | "x86_64", 5, 2, _ ->
ffd6ed
-        Some (virtio_win_dir // "drivers/amd64/Win2003")
ffd6ed
-      | "x86_64", 6, 0, _ ->
ffd6ed
-        Some (virtio_win_dir // "drivers/amd64/Win2008")
ffd6ed
-      | "x86_64", 6, 1, "Client" ->
ffd6ed
-        Some (virtio_win_dir // "drivers/amd64/Win7")
ffd6ed
-      | "x86_64", 6, 1, "Server" ->
ffd6ed
-        Some (virtio_win_dir // "drivers/amd64/Win2008R2")
ffd6ed
-      | "x86_64", 6, 2, "Client" ->
ffd6ed
-        Some (virtio_win_dir // "drivers/amd64/Win8")
ffd6ed
-      | "x86_64", 6, 2, "Server" ->
ffd6ed
-        Some (virtio_win_dir // "drivers/amd64/Win2012")
ffd6ed
-      | "x86_64", 6, 3, "Client" ->
ffd6ed
-        Some (virtio_win_dir // "drivers/amd64/Win8.1")
ffd6ed
-      | "x86_64", 6, 3, "Server" ->
ffd6ed
-        Some (virtio_win_dir // "drivers/amd64/Win2012R2")
ffd6ed
+    (* Filter out only drivers matching the current guest. *)
ffd6ed
+    let drivers =
ffd6ed
+      List.filter (
ffd6ed
+        fun { vwd_os_arch = arch;
ffd6ed
+              vwd_os_major = os_major; vwd_os_minor = os_minor;
ffd6ed
+              vwd_os_variant = os_variant } ->
ffd6ed
+        arch = inspect.i_arch &&
ffd6ed
+        os_major = inspect.i_major_version &&
ffd6ed
+        os_minor = inspect.i_minor_version &&
ffd6ed
+        (match os_variant with
ffd6ed
+         | Vwd_client -> inspect.i_product_variant = "Client"
ffd6ed
+         | Vwd_server -> inspect.i_product_variant = "Server"
ffd6ed
+         | Vwd_any_variant -> true)
ffd6ed
+      ) drivers in
ffd6ed
 
ffd6ed
-      | _ ->
ffd6ed
-        None in
ffd6ed
+    if verbose then (
ffd6ed
+      printf "virtio-win driver files matching this guest:\n";
ffd6ed
+      List.iter print_virtio_win_driver_file drivers;
ffd6ed
+      flush stdout
ffd6ed
+    );
ffd6ed
 
ffd6ed
-    let path =
ffd6ed
-      match path with
ffd6ed
-      | None -> None
ffd6ed
-      | Some path ->
ffd6ed
-        if is_directory path then Some path else None in
ffd6ed
+    match drivers with
ffd6ed
+    | [] ->
ffd6ed
+       warning ~prog (f_"there are no virtio drivers available for this version of Windows (%d.%d %s %s).  virt-v2v looks for drivers in %s\n\nThe guest will be configured to use slower emulated devices.")
ffd6ed
+               inspect.i_major_version inspect.i_minor_version
ffd6ed
+               inspect.i_arch inspect.i_product_variant
ffd6ed
+               virtio_win;
ffd6ed
+       ( IDE, RTL8139 )
ffd6ed
 
ffd6ed
-    match path with
ffd6ed
-    | None ->
ffd6ed
-      warning ~prog (f_"there are no virtio drivers available for this version of Windows (%d.%d %s %s).  virt-v2v looks for drivers in %s\n\nThe guest will be configured to use slower emulated devices.")
ffd6ed
-        inspect.i_major_version inspect.i_minor_version
ffd6ed
-        inspect.i_arch inspect.i_product_variant
ffd6ed
-        virtio_win_dir;
ffd6ed
-      ( IDE, RTL8139 )
ffd6ed
+    | drivers ->
ffd6ed
+       (* Can we install the block driver? *)
ffd6ed
+       let block : guestcaps_block_type =
ffd6ed
+         try
ffd6ed
+           let viostor_sys_file =
ffd6ed
+             List.find
ffd6ed
+               (fun { vwd_filename = filename } -> filename = "viostor.sys")
ffd6ed
+               drivers in
ffd6ed
+           (* Get the actual file contents of the .sys file. *)
ffd6ed
+           let content = viostor_sys_file.vwd_get_contents () in
ffd6ed
+           let target = sprintf "%s/system32/drivers/viostor.sys" systemroot in
ffd6ed
+           let target = g#case_sensitive_path target in
ffd6ed
+           g#write target content;
ffd6ed
+           add_viostor_to_critical_device_database root current_cs;
ffd6ed
+           Virtio_blk
ffd6ed
+         with Not_found ->
ffd6ed
+           warning ~prog (f_"there is no viostor (virtio block device) driver for this version of Windows (%d.%d %s).  virt-v2v looks for this driver in %s\n\nThe guest will be configured to use a slower emulated device.")
ffd6ed
+                   inspect.i_major_version inspect.i_minor_version
ffd6ed
+                   inspect.i_arch virtio_win;
ffd6ed
+           IDE in
ffd6ed
 
ffd6ed
-    | Some path ->
ffd6ed
-      (* Can we install the block driver? *)
ffd6ed
-      let block : guestcaps_block_type =
ffd6ed
-        let block_path = path // "viostor.sys" in
ffd6ed
-        if not (Sys.file_exists block_path) then (
ffd6ed
-          warning ~prog (f_"there is no viostor (virtio block device) driver for this version of Windows (%d.%d %s).  virt-v2v looks for this driver here: %s\n\nThe guest will be configured to use a slower emulated device.")
ffd6ed
-            inspect.i_major_version inspect.i_minor_version
ffd6ed
-            inspect.i_arch block_path;
ffd6ed
-          IDE
ffd6ed
-        )
ffd6ed
-        else (
ffd6ed
-          let target = sprintf "%s/system32/drivers/viostor.sys" systemroot in
ffd6ed
-          let target = g#case_sensitive_path target in
ffd6ed
-          g#upload block_path target;
ffd6ed
-          add_viostor_to_critical_device_database root current_cs;
ffd6ed
-          Virtio_blk
ffd6ed
-        ) in
ffd6ed
+       (* Can we install the virtio-net driver? *)
ffd6ed
+       let net : guestcaps_net_type =
ffd6ed
+         if not (List.exists
ffd6ed
+                   (fun { vwd_filename = filename } -> filename = "netkvm.inf")
ffd6ed
+                   drivers) then (
ffd6ed
+           warning ~prog (f_"there is no virtio network driver for this version of Windows (%d.%d %s).  virt-v2v looks for this driver in %s\n\nThe guest will be configured to use a slower emulated device.")
ffd6ed
+                   inspect.i_major_version inspect.i_minor_version
ffd6ed
+                   inspect.i_arch virtio_win;
ffd6ed
+           RTL8139
ffd6ed
+         )
ffd6ed
+         else
ffd6ed
+           (* It will be installed at firstboot. *)
ffd6ed
+           Virtio_net in
ffd6ed
 
ffd6ed
-      (* Can we install the virtio-net driver? *)
ffd6ed
-      let net : guestcaps_net_type =
ffd6ed
-        let net_path = path // "netkvm.inf" in
ffd6ed
-        if not (Sys.file_exists net_path) then (
ffd6ed
-          warning ~prog (f_"there is no virtio network driver for this version of Windows (%d.%d %s).  virt-v2v looks for this driver here: %s\n\nThe guest will be configured to use a slower emulated device.")
ffd6ed
-            inspect.i_major_version inspect.i_minor_version
ffd6ed
-            inspect.i_arch net_path;
ffd6ed
-          RTL8139
ffd6ed
-        )
ffd6ed
-        else
ffd6ed
-          (* It will be installed at firstboot. *)
ffd6ed
-          Virtio_net in
ffd6ed
+       (* Copy all the drivers to the driverdir.  They will be
ffd6ed
+        * installed at firstboot.
ffd6ed
+        *)
ffd6ed
+       List.iter (
ffd6ed
+         fun driver ->
ffd6ed
+           let content = driver.vwd_get_contents () in
ffd6ed
+           g#write (driverdir // driver.vwd_filename) content
ffd6ed
+       ) drivers;
ffd6ed
 
ffd6ed
-      (* Copy the drivers to the driverdir.  They will be installed at
ffd6ed
-       * firstboot.
ffd6ed
-       *)
ffd6ed
-      let files = Sys.readdir path in
ffd6ed
-      let files = Array.to_list files in
ffd6ed
-      let files = List.sort compare files in
ffd6ed
-      List.iter (
ffd6ed
-        fun file ->
ffd6ed
-          g#upload (path // file) (driverdir // file)
ffd6ed
-      ) files;
ffd6ed
-
ffd6ed
-      (block, net)
ffd6ed
+       (block, net)
ffd6ed
 
ffd6ed
   and add_viostor_to_critical_device_database root current_cs =
ffd6ed
     (* See http://rwmj.wordpress.com/2010/04/30/tip-install-a-device-driver-in-a-windows-vm/
ffd6ed
diff --git a/v2v/utils.ml b/v2v/utils.ml
ffd6ed
index ebf799f..a301c56 100644
ffd6ed
--- a/v2v/utils.ml
ffd6ed
+++ b/v2v/utils.ml
ffd6ed
@@ -106,6 +106,160 @@ let find_uefi_firmware guest_arch =
ffd6ed
   in
ffd6ed
   loop files
ffd6ed
 
ffd6ed
+(* Find virtio-win driver files from an unpacked or mounted virtio-win
ffd6ed
+ * directory, or from a virtio-win.iso file. The location of drivers
ffd6ed
+  varies between releases of virtio-win and also across Fedora and
ffd6ed
+  RHEL so try to be robust to changes.
ffd6ed
+ *)
ffd6ed
+type virtio_win_driver_file = {
ffd6ed
+  (* Base filename, eg. "netkvm.sys".  Always lowercase. *)
ffd6ed
+  vwd_filename : string;
ffd6ed
+  (* Return the contents of this file. *)
ffd6ed
+  vwd_get_contents : unit -> string;
ffd6ed
+
ffd6ed
+  (* Various fields that classify this driver: *)
ffd6ed
+
ffd6ed
+  vwd_os_major : int;           (* Windows version. *)
ffd6ed
+  vwd_os_minor : int;
ffd6ed
+  vwd_os_variant : vwd_os_variant;
ffd6ed
+  vwd_os_arch : string;         (* Architecture, eg "i386", "x86_64". *)
ffd6ed
+  vwd_extension : string;       (* File extension (lowercase), eg. "sys" "inf"*)
ffd6ed
+
ffd6ed
+  (* Original source of file (for debugging only). *)
ffd6ed
+  vwd_original_source : string;
ffd6ed
+}
ffd6ed
+and vwd_os_variant = Vwd_client | Vwd_server | Vwd_any_variant
ffd6ed
+
ffd6ed
+let print_virtio_win_driver_file vwd =
ffd6ed
+  printf "%s [%d,%d,%s,%s,%s] from %s\n"
ffd6ed
+         vwd.vwd_filename
ffd6ed
+         vwd.vwd_os_major vwd.vwd_os_minor
ffd6ed
+         (match vwd.vwd_os_variant with
ffd6ed
+          | Vwd_client -> "client" | Vwd_server -> "server"
ffd6ed
+          | Vwd_any_variant -> "any")
ffd6ed
+         vwd.vwd_os_arch
ffd6ed
+         vwd.vwd_extension
ffd6ed
+         vwd.vwd_original_source
ffd6ed
+
ffd6ed
+let find_virtio_win_drivers ~verbose virtio_win =
ffd6ed
+  let is_regular_file path = (* NB: follows symlinks. *)
ffd6ed
+    try (Unix.stat path).Unix.st_kind = Unix.S_REG
ffd6ed
+    with Unix.Unix_error _ -> false
ffd6ed
+  in
ffd6ed
+
ffd6ed
+  let files =
ffd6ed
+    if is_directory virtio_win then (
ffd6ed
+      let cmd = sprintf "cd %s && find -type f" (quote virtio_win) in
ffd6ed
+      let paths = external_command ~prog cmd in
ffd6ed
+      List.map (
ffd6ed
+        fun path ->
ffd6ed
+          let abs_path = virtio_win // path in
ffd6ed
+          (path, abs_path,
ffd6ed
+           Filename.basename path,
ffd6ed
+           fun () -> read_whole_file abs_path)
ffd6ed
+      ) paths
ffd6ed
+    )
ffd6ed
+    else if is_regular_file virtio_win then (
ffd6ed
+      try
ffd6ed
+        let g = new Guestfs.guestfs () in
ffd6ed
+        if verbose then (
ffd6ed
+          g#set_trace true;
ffd6ed
+          g#set_verbose true;
ffd6ed
+        );
ffd6ed
+        g#add_drive_opts virtio_win ~readonly:true;
ffd6ed
+        g#launch ();
ffd6ed
+        g#mount_ro "/dev/sda" "/";
ffd6ed
+        let paths = g#find "/" in
ffd6ed
+        let paths = Array.to_list paths in
ffd6ed
+        let paths = List.map ((^) "/") paths in
ffd6ed
+        let paths = List.filter (g#is_file ~followsymlinks:false) paths in
ffd6ed
+        List.map (
ffd6ed
+          fun path ->
ffd6ed
+            let i = String.rindex path '/' in
ffd6ed
+            let len = String.length path in
ffd6ed
+            let basename = String.sub path (i+1) (len - (i+1)) in
ffd6ed
+            (path, sprintf "%s:%s" virtio_win path,
ffd6ed
+             basename,
ffd6ed
+             fun () -> g#read_file path)
ffd6ed
+        ) paths
ffd6ed
+      with Guestfs.Error msg ->
ffd6ed
+        error (f_"%s: cannot open virtio-win ISO file: %s") virtio_win msg
ffd6ed
+    )
ffd6ed
+    else [] in
ffd6ed
+
ffd6ed
+  let files =
ffd6ed
+    filter_map (
ffd6ed
+      fun (path, original_source, basename, get_contents) ->
ffd6ed
+        try
ffd6ed
+          (* Lowercased path, since the ISO may contain upper or lowercase
ffd6ed
+           * path elements.  XXX This won't work if paths contain non-ASCII.
ffd6ed
+           *)
ffd6ed
+          let lc_path = String.lowercase path in
ffd6ed
+          let lc_basename = String.lowercase basename in
ffd6ed
+
ffd6ed
+          let extension =
ffd6ed
+            let i = String.rindex lc_basename '.' in
ffd6ed
+            let len = String.length lc_basename in
ffd6ed
+            String.sub lc_basename (i+1) (len - (i+1)) in
ffd6ed
+
ffd6ed
+          (* Skip files without specific extensions. *)
ffd6ed
+          if extension <> "cat" && extension <> "inf" &&
ffd6ed
+               extension <> "pdb" && extension <> "sys" then
ffd6ed
+            raise Not_found;
ffd6ed
+
ffd6ed
+          (* Using the full path, work out what version of Windows
ffd6ed
+           * this driver is for.  Paths can be things like:
ffd6ed
+           * "NetKVM/2k12R2/amd64/netkvm.sys" or
ffd6ed
+           * "./drivers/amd64/Win2012R2/netkvm.sys".
ffd6ed
+           * Note we check lowercase paths.
ffd6ed
+           *)
ffd6ed
+          let pathelem elem = string_find lc_path ("/" ^ elem ^ "/") >= 0 in
ffd6ed
+          let arch =
ffd6ed
+            if pathelem "x86" || pathelem "i386" then "i386"
ffd6ed
+            else if pathelem "amd64" then "x86_64"
ffd6ed
+            else raise Not_found in
ffd6ed
+          let os_major, os_minor, os_variant =
ffd6ed
+            if pathelem "xp" || pathelem "winxp" then
ffd6ed
+              (5, 1, Vwd_any_variant)
ffd6ed
+            else if pathelem "2k3" || pathelem "win2003" then
ffd6ed
+              (5, 2, Vwd_any_variant)
ffd6ed
+            else if pathelem "vista" then
ffd6ed
+              (6, 0, Vwd_client)
ffd6ed
+            else if pathelem "2k8" || pathelem "win2008" then
ffd6ed
+              (6, 0, Vwd_server)
ffd6ed
+            else if pathelem "w7" || pathelem "win7" then
ffd6ed
+              (6, 1, Vwd_client)
ffd6ed
+            else if pathelem "2k8r2" || pathelem "win2008" then
ffd6ed
+              (6, 1, Vwd_server)
ffd6ed
+            else if pathelem "w8" || pathelem "win8" then
ffd6ed
+              (6, 2, Vwd_client)
ffd6ed
+            else if pathelem "2k12" || pathelem "win2012" then
ffd6ed
+              (6, 2, Vwd_server)
ffd6ed
+            else if pathelem "w8.1" || pathelem "win8.1" then
ffd6ed
+              (6, 3, Vwd_client)
ffd6ed
+            else if pathelem "2k12r2" || pathelem "win2012r2" then
ffd6ed
+              (6, 3, Vwd_server)
ffd6ed
+            else if pathelem "w10" || pathelem "win10" then
ffd6ed
+              (10, 0, Vwd_client)
ffd6ed
+            else
ffd6ed
+              raise Not_found in
ffd6ed
+
ffd6ed
+          Some {
ffd6ed
+            vwd_filename = lc_basename;
ffd6ed
+            vwd_get_contents = get_contents;
ffd6ed
+            vwd_os_major = os_major;
ffd6ed
+            vwd_os_minor = os_minor;
ffd6ed
+            vwd_os_variant = os_variant;
ffd6ed
+            vwd_os_arch = arch;
ffd6ed
+            vwd_extension = extension;
ffd6ed
+            vwd_original_source = original_source;
ffd6ed
+          }
ffd6ed
+
ffd6ed
+        with Not_found -> None
ffd6ed
+    ) files in
ffd6ed
+
ffd6ed
+  files
ffd6ed
+
ffd6ed
 let compare_app2_versions app1 app2 =
ffd6ed
   let i = compare app1.Guestfs.app2_epoch app2.Guestfs.app2_epoch in
ffd6ed
   if i <> 0 then i
ffd6ed
diff --git a/v2v/v2v.ml b/v2v/v2v.ml
ffd6ed
index 033d75b..d509a4c 100644
ffd6ed
--- a/v2v/v2v.ml
ffd6ed
+++ b/v2v/v2v.ml
ffd6ed
@@ -308,6 +308,14 @@ let rec main () =
ffd6ed
   g#shutdown ();
ffd6ed
   g#close ();
ffd6ed
 
ffd6ed
+  (* Force a GC here, to ensure that we're using the minimum resources
ffd6ed
+   * as we go into the copy stage.  The particular reason is that
ffd6ed
+   * Windows conversion may have opened a second libguestfs handle
ffd6ed
+   * pointing to the virtio-win ISO, which is only closed when the
ffd6ed
+   * handle is GC'd.
ffd6ed
+   *)
ffd6ed
+  Gc.compact ();
ffd6ed
+
ffd6ed
   let delete_target_on_exit = ref true in
ffd6ed
 
ffd6ed
   let targets =
ffd6ed
diff --git a/v2v/virt-v2v.pod b/v2v/virt-v2v.pod
ffd6ed
index 7d24ceb..e841a43 100644
ffd6ed
--- a/v2v/virt-v2v.pod
ffd6ed
+++ b/v2v/virt-v2v.pod
ffd6ed
@@ -621,7 +621,7 @@ below.
ffd6ed
  OpenSUSE 10    kernel >= 2.6.25.5-1.1
ffd6ed
 
ffd6ed
  Windows        Drivers are installed from the directory pointed to by
ffd6ed
-                "VIRTIO_WIN_DIR" environment variable
ffd6ed
+                "VIRTIO_WIN" environment variable
ffd6ed
                 (/usr/share/virtio-win by default) if present
ffd6ed
 
ffd6ed
 =head1 RHEL 4
ffd6ed
@@ -1472,10 +1472,13 @@ not distributed with virt-v2v.
ffd6ed
 
ffd6ed
 =back
ffd6ed
 
ffd6ed
-=item C<VIRTIO_WIN_DIR>
ffd6ed
+=item C<VIRTIO_WIN>
ffd6ed
 
ffd6ed
 This is where VirtIO drivers for Windows are searched for
ffd6ed
-(F</usr/share/virtio-win> if unset).  See L<ENABLING VIRTIO>.
ffd6ed
+(F</usr/share/virtio-win> if unset).  It can be a directory I<or>
ffd6ed
+point to F<virtio-win.iso> (CD ROM image containing drivers).
ffd6ed
+
ffd6ed
+See L<ENABLING VIRTIO>.
ffd6ed
 
ffd6ed
 =back
ffd6ed
 
ffd6ed
-- 
ffd6ed
1.8.3.1
ffd6ed