[Libguestfs] [PATCH] Install VirtIO storage and network drivers in Windows
Richard W.M. Jones
rjones at redhat.com
Mon Aug 16 14:16:58 UTC 2010
On Mon, Aug 16, 2010 at 02:53:17PM +0100, Matthew Booth wrote:
> Currently when converting a Windows guest we do a minimum installation of the
> viostor driver, configure the RHEV guest agent and leave RHEV to properly
> install viostor and all remaining drivers. This works well if RHEV is properly
> configured and the installation is not interrupted on first boot.
>
> However, if the target of the conversion is not RHEV, RHEV is not properly
> configured, or the first boot installation process is interrupted, for
> example by the user logging in and interacting with it, this will fail. In this
> case, in the absence of a correct driver Windows can mis-detect the VirtIO 'SCSI
> Controller' and configure the wrong driver for it. This will lead to the guest
> subsequently failing to boot.
>
> This patch complements the RHEV-managed process by additionally copying
> installable versions of the VirtIO storage and network drivers to the guest
> during conversion, and adding the location of the drivers to the default search
> path for drivers. This means that Windows will install correct drivers for
> network and storage if the RHEV process fails, or if the conversion target is
> not RHEV.
> ---
> lib/Sys/VirtV2V/Converter/Windows.pm | 77 ++++++++++++++++++++++++++++++++++
> 1 files changed, 77 insertions(+), 0 deletions(-)
>
> diff --git a/lib/Sys/VirtV2V/Converter/Windows.pm b/lib/Sys/VirtV2V/Converter/Windows.pm
> index 1d4c526..f5bf399 100644
> --- a/lib/Sys/VirtV2V/Converter/Windows.pm
> +++ b/lib/Sys/VirtV2V/Converter/Windows.pm
> @@ -23,6 +23,7 @@ use warnings;
> use Carp qw(carp);
> use File::Temp qw(tempdir);
> use Data::Dumper;
> +use Encode qw(encode decode);
> use IO::String;
> use XML::DOM;
> use XML::DOM::XPath;
> @@ -187,6 +188,7 @@ sub _preconvert
> _upload_files ($g, $tmpdir, $desc, $devices, $config);
> _add_viostor_to_registry ($g, $tmpdir, $desc, $devices, $config);
> _add_service_to_registry ($g, $tmpdir, $desc, $devices, $config);
> + _prepare_virtio_drivers ($g, $tmpdir, $desc, $devices, $config);
> }
>
> # See http://rwmj.wordpress.com/2010/04/30/tip-install-a-device-driver-in-a-windows-vm/
> @@ -345,6 +347,81 @@ sub _add_service_to_registry
> $g->upload ($tmpdir . "/system", $system_filename);
> }
>
> +# We copy the VirtIO drivers to a directory on the guest and add this directory
> +# to HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\DevicePath so that it will
> +# be searched automatically when automatically installing drivers.
> +sub _prepare_virtio_drivers
> +{
> + my $g = shift;
> + my $tmpdir = shift;
> + my $desc = shift;
> + my $devices = shift;
> + my $config = shift;
> +
> + # Copy the target VirtIO drivers to the guest
> + my $driverdir = File::Spec->catdir($g->case_sensitive_path("/windows"), "Drivers/VirtIO");
> +
> + $g->mkdir_p($driverdir);
> +
> + my ($virtio) = $config->match_app ($desc, 'virtio', $desc->{arch});
> + $virtio = $config->get_transfer_path($g, $virtio);
> +
> + foreach my $src ($g->ls($virtio)) {
> + my $name = $src;
> + $src = File::Spec->catfile($virtio);
> + my $dst = File::Spec->catfile($driverdir, $name);
> + $g->cp_a($src, $dst);
> + }
> +
> + # Locate and download the SOFTWARE hive
> + my $sw_local = File::Spec->catfile($tmpdir, 'software');
> + my $sw_guest = $g->case_sensitive_path('/windows/system32/config/software');
> +
> + $g->download($sw_guest, $sw_local);
> +
> + # Open the registry hive.
> + my $h = Win::Hivex->open($sw_local, write => 1)
> + or die "open hive $sw_local: $!";
> +
> + # Find the node \Microsoft\Windows\CurrentVersion
> + my $node = $h->root();
> + foreach ('Microsoft', 'Windows', 'CurrentVersion') {
> + $node = $h->node_get_child($node, $_);
> + }
> +
> + # Update DevicePath, but leave everything else as is
> + my @new;
> + my $append = ';%SystemRoot%\Drivers\VirtIO';
> + foreach my $v ($h->node_values($node)) {
> + my $key = $h->value_key($v);
> + my ($type, $data) = $h->value_value($v);
> +
> + # Decode the string from utf16le to perl native
> + my $value = decode('UTF-16LE', $data);
> +
> + # Append the driver location if it's not there already
> + if ($key eq 'DevicePath' && index($value, $append) == -1) {
> + # Remove the explicit trailing NULL
> + chop($value);
> +
> + # Append the new path and a new explicit trailing NULL
> + $value .= $append."\0";
> +
> + # Re-encode the string back to utf16le
> + $data = encode('UTF-16LE', $value);
> + }
> +
> + push (@new, { key => $key, t => $type, value => $data });
> + }
> + $h->node_set_values($node, \@new);
> +
> + $h->commit(undef);
> + undef $h;
> +
> + # Upload the new registry.
> + $g->upload($sw_local, $sw_guest);
> +}
> +
> sub _upload_files
> {
> my $g = shift;
As discussed on list, ACK.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-df lists disk usage of guests without needing to install any
software inside the virtual machine. Supports Linux and Windows.
http://et.redhat.com/~rjones/virt-df/
More information about the Libguestfs
mailing list