[Libguestfs] [PATCH] Fix: virt-inspector takes ages to run on RHEL 3 guests

Richard W.M. Jones rjones at redhat.com
Mon Jul 13 17:23:45 UTC 2009


Currently virt-inspector takes ages to run on RHEL 3 guests.

I tracked this down to processing the old-style initrd images in these
guests.  These initrd images are compressed ext2 filesystems.  'cpio'
tries to parse them as cpio files, and takes a very long time to fail
(and spews out a lot of errors in the process).

These two patches fix the problem: Firstly we introduce a new command
'zfile' for doing the 'file' operation inside compressed files.  eg:

  guestfs_zfile (g, "gzip", "/boot/initrd.img")
  ==> "Linux rev 1.0 ext2 filesystem data"

Second patch updates Sys::Guestfs::Lib to ignore such files.

Rich.

-- 
Richard Jones, Emerging Technologies, Red Hat  http://et.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/
-------------- next part --------------
>From 7d41d75c1d4e6dbe61f6cd353bc104663340483f Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones at trick.home.annexia.org>
Date: Mon, 13 Jul 2009 18:00:07 +0100
Subject: [PATCH 1/2] Implement new 'zfile' command, to show file type inside compressed files.

---
 daemon/file.c    |   60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/MAX_PROC_NR  |    2 +-
 src/generator.ml |   51 +++++++++++++++++++++++++++------------------
 3 files changed, 92 insertions(+), 21 deletions(-)

diff --git a/daemon/file.c b/daemon/file.c
index 3ef7441..98c356d 100644
--- a/daemon/file.c
+++ b/daemon/file.c
@@ -376,3 +376,63 @@ do_file (char *path)
 
   return out;			/* caller frees */
 }
+
+/* zcat | file */
+char *
+do_zfile (char *method, char *path)
+{
+  int len;
+  char *cmd;
+  FILE *fp;
+  char line[256];
+
+  NEED_ROOT (NULL);
+  ABS_PATH (path, NULL);
+
+  len = 2 * strlen (path) + 64;
+  cmd = malloc (len);
+  if (!cmd) {
+    reply_with_perror ("malloc");
+    return NULL;
+  }
+
+  if (strcmp (method, "gzip") == 0 || strcmp (method, "compress") == 0)
+    strcpy (cmd, "zcat");
+  else if (strcmp (method, "bzip2") == 0)
+    strcpy (cmd, "bzcat");
+  else {
+    free (cmd);
+    reply_with_error ("zfile: unknown method");
+    return NULL;
+  }
+
+  strcat (cmd, " /sysroot");
+  shell_quote (cmd + strlen (cmd), len - strlen (cmd), path);
+  strcat (cmd, " | file -bsL -");
+
+  fp = popen (cmd, "r");
+  if (fp == NULL) {
+    reply_with_perror ("%s", cmd);
+    free (cmd);
+    return NULL;
+  }
+
+  free (cmd);
+
+  if (fgets (line, sizeof line, fp) == NULL) {
+    reply_with_perror ("zfile: fgets");
+    fclose (fp);
+    return NULL;
+  }
+
+  if (fclose (fp) == -1) {
+    reply_with_perror ("zfile: fclose");
+    return NULL;
+  }
+
+  len = strlen (line);
+  if (len > 0 && line[len-1] == '\n')
+    line[len-1] = '\0';
+
+  return strdup (line);
+}
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index 897bdc8..dee261d 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-139
+140
diff --git a/src/generator.ml b/src/generator.ml
index 8c864f0..e3293d1 100755
--- a/src/generator.ml
+++ b/src/generator.ml
@@ -1718,8 +1718,8 @@ This uses the L<blockdev(8)> command.");
   ("upload", (RErr, [FileIn "filename"; String "remotefilename"]), 66, [],
    [InitBasicFS, Always, TestOutput (
       (* Pick a file from cwd which isn't likely to change. *)
-    [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
-     ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
+      [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
+       ["checksum"; "md5"; "/COPYING.LIB"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
    "upload a file from the local machine",
    "\
 Upload local file C<filename> to C<remotefilename> on the
@@ -1732,10 +1732,10 @@ See also C<guestfs_download>.");
   ("download", (RErr, [String "remotefilename"; FileOut "filename"]), 67, [],
    [InitBasicFS, Always, TestOutput (
       (* Pick a file from cwd which isn't likely to change. *)
-    [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
-     ["download"; "/COPYING.LIB"; "testdownload.tmp"];
-     ["upload"; "testdownload.tmp"; "/upload"];
-     ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
+      [["upload"; "../COPYING.LIB"; "/COPYING.LIB"];
+       ["download"; "/COPYING.LIB"; "testdownload.tmp"];
+       ["upload"; "testdownload.tmp"; "/upload"];
+       ["checksum"; "md5"; "/upload"]], "e3eda01d9815f8d24aae2dbd89b68b06")],
    "download a file to the local machine",
    "\
 Download file C<remotefilename> and save it as C<filename>
@@ -2357,19 +2357,19 @@ are activated or deactivated.");
 
   ("lvresize", (RErr, [String "device"; Int "mbytes"]), 105, [],
    [InitNone, Always, TestOutput (
-    [["sfdiskM"; "/dev/sda"; ","];
-     ["pvcreate"; "/dev/sda1"];
-     ["vgcreate"; "VG"; "/dev/sda1"];
-     ["lvcreate"; "LV"; "VG"; "10"];
-     ["mkfs"; "ext2"; "/dev/VG/LV"];
-     ["mount"; "/dev/VG/LV"; "/"];
-     ["write_file"; "/new"; "test content"; "0"];
-     ["umount"; "/"];
-     ["lvresize"; "/dev/VG/LV"; "20"];
-     ["e2fsck_f"; "/dev/VG/LV"];
-     ["resize2fs"; "/dev/VG/LV"];
-     ["mount"; "/dev/VG/LV"; "/"];
-     ["cat"; "/new"]], "test content")],
+      [["sfdiskM"; "/dev/sda"; ","];
+       ["pvcreate"; "/dev/sda1"];
+       ["vgcreate"; "VG"; "/dev/sda1"];
+       ["lvcreate"; "LV"; "VG"; "10"];
+       ["mkfs"; "ext2"; "/dev/VG/LV"];
+       ["mount"; "/dev/VG/LV"; "/"];
+       ["write_file"; "/new"; "test content"; "0"];
+       ["umount"; "/"];
+       ["lvresize"; "/dev/VG/LV"; "20"];
+       ["e2fsck_f"; "/dev/VG/LV"];
+       ["resize2fs"; "/dev/VG/LV"];
+       ["mount"; "/dev/VG/LV"; "/"];
+       ["cat"; "/new"]], "test content")],
    "resize an LVM logical volume",
    "\
 This resizes (expands or shrinks) an existing LVM logical
@@ -2441,7 +2441,7 @@ This command is only needed because of C<guestfs_resize2fs>
 
   ("sleep", (RErr, [Int "secs"]), 109, [],
    [InitNone, Always, TestRun (
-    [["sleep"; "1"]])],
+      [["sleep"; "1"]])],
    "sleep for some seconds",
    "\
 Sleep for C<secs> seconds.");
@@ -2857,6 +2857,17 @@ were rarely if ever used anyway.
 
 See also C<guestfs_sfdisk> and the L<sfdisk(8)> manpage.");
 
+  ("zfile", (RString "description", [String "method"; String "path"]), 140, [],
+   [],
+   "determine file type inside a compressed file",
+   "\
+This command runs C<file> after first decompressing C<path>
+using C<method>.
+
+C<method> must be one of C<gzip>, C<compress> or C<bzip2>.
+
+See also: C<guestfs_file>");
+
 ]
 
 let all_functions = non_daemon_functions @ daemon_functions
-- 
1.6.2.5

-------------- next part --------------
>From 4e444d5c09d78b0d292d95d1f97de12f26cc139d Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones at trick.home.annexia.org>
Date: Mon, 13 Jul 2009 18:06:10 +0100
Subject: [PATCH 2/2] Ignore old-style initrd which is a compressed ext2 filesystem.

'cpio' chokes on these, taking ages to decide that they are
not cpio files, and producing masses of messages.  This was
causing virt-inspector to be very slow (many minutes) on
RHEL 3 guests.  With this fix, speed is back to normal.
---
 perl/lib/Sys/Guestfs/Lib.pm |   22 ++++++++++++++--------
 1 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/perl/lib/Sys/Guestfs/Lib.pm b/perl/lib/Sys/Guestfs/Lib.pm
index 27a7b9e..d5dfb4e 100644
--- a/perl/lib/Sys/Guestfs/Lib.pm
+++ b/perl/lib/Sys/Guestfs/Lib.pm
@@ -1208,14 +1208,20 @@ sub _check_for_initrd
 	    my $version = $1;
 	    my @modules;
 
-	    eval {
-		@modules = $g->initrd_list ("/boot/$initrd");
-	    };
-	    unless ($@) {
-		@modules = grep { m,([^/]+)\.ko$, || m,([^/]+)\.o$, } @modules;
-		$initrd_modules{$version} = \@modules
-	    } else {
-		warn "/boot/$initrd: could not read initrd format"
+	    # Disregard old-style compressed ext2 files, since cpio
+	    # takes ages to (fail to) process these.
+	    if ($g->file ("/boot/$initrd") !~ /gzip compressed/ ||
+		$g->zfile ("gzip", "/boot/$initrd") !~ /ext2 filesystem/) {
+		eval {
+		    @modules = $g->initrd_list ("/boot/$initrd");
+		};
+		unless ($@) {
+		    @modules = grep { m,([^/]+)\.ko$, || m,([^/]+)\.o$, }
+		    @modules;
+		    $initrd_modules{$version} = \@modules
+		} else {
+		    warn "/boot/$initrd: could not read initrd format";
+	        }
 	    }
 	}
     }
-- 
1.6.2.5



More information about the Libguestfs mailing list