From b4bb49ffd123e36d6319281dcc2080b30e23e447 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Wed, 5 Oct 2011 15:06:10 +0100 Subject: [PATCH] New tool: virt-alignment-scan to check alignment of partitions. --- .gitignore | 4 + Makefile.am | 3 +- align/Makefile.am | 79 ++++++++++++ align/scan.c | 287 ++++++++++++++++++++++++++++++++++++++++++ align/virt-alignment-scan.pod | 234 ++++++++++++++++++++++++++++++++++ configure.ac | 1 + fish/guestfish.pod | 1 + po-docs/ja/Makefile.am | 1 + po-docs/podfiles | 1 + po-docs/uk/Makefile.am | 1 + po/POTFILES.in | 1 + src/guestfs.pod | 5 + 12 files changed, 617 insertions(+), 1 deletion(-) create mode 100644 align/Makefile.am create mode 100644 align/scan.c create mode 100755 align/virt-alignment-scan.pod diff --git a/.gitignore b/.gitignore index da066d4..4f1438f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,9 @@ *.a ABOUT-NLS aclocal.m4 +align/stamp-virt-alignment-scan.pod +align/virt-alignment-scan +align/virt-alignment-scan.1 appliance/excludelist appliance/make.sh appliance/packagelist @@ -133,6 +136,7 @@ html/guestfs-python.3.html html/guestfs-recipes.1.html html/guestfs-ruby.3.html html/guestmount.1.html +html/virt-alignment-scan.1.html html/virt-cat.1.html html/virt-copy-in.1.html html/virt-copy-out.1.html diff --git a/Makefile.am b/Makefile.am index 6138052..548d1fa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,7 +36,7 @@ SUBDIRS += gnulib/tests capitests caution regressions test-tool SUBDIRS += fish # virt-tools in C. -SUBDIRS += cat df edit inspector rescue +SUBDIRS += align cat df edit inspector rescue # Language bindings. if HAVE_PERL @@ -144,6 +144,7 @@ HTMLFILES = \ html/guestfs-ruby.3.html \ html/guestfish.1.html \ html/guestmount.1.html \ + html/virt-alignment-scan.1.html \ html/virt-cat.1.html \ html/virt-copy-in.1.html \ html/virt-copy-out.1.html \ diff --git a/align/Makefile.am b/align/Makefile.am new file mode 100644 index 0000000..5692fd4 --- /dev/null +++ b/align/Makefile.am @@ -0,0 +1,79 @@ +# libguestfs virt alignment tools +# Copyright (C) 2011 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +include $(top_srcdir)/subdir-rules.mk + +EXTRA_DIST = \ + virt-alignment-scan.pod + +CLEANFILES = stamp-virt-alignment-scan.pod + +bin_PROGRAMS = virt-alignment-scan + +SHARED_SOURCE_FILES = \ + ../fish/config.c \ + ../fish/inspect.c \ + ../fish/keys.c \ + ../fish/options.h \ + ../fish/options.c \ + ../fish/virt.c + +virt_alignment_scan_SOURCES = \ + $(SHARED_SOURCE_FILES) \ + scan.c + +virt_alignment_scan_CFLAGS = \ + -DGUESTFS_WARN_DEPRECATED=1 \ + -I$(top_srcdir)/src -I$(top_builddir)/src \ + -I$(top_srcdir)/fish \ + -I$(srcdir)/../gnulib/lib -I../gnulib/lib \ + -DLOCALEBASEDIR=\""$(datadir)/locale"\" \ + $(WARN_CFLAGS) $(WERROR_CFLAGS) \ + $(LIBCONFIG_CFLAGS) \ + $(LIBVIRT_CFLAGS) + +virt_alignment_scan_LDADD = \ + $(LIBCONFIG_LIBS) \ + $(top_builddir)/src/libguestfs.la \ + ../gnulib/lib/libgnu.la \ + $(LIBVIRT_LIBS) \ + -lm + +# Manual pages and HTML files for the website. +man_MANS = virt-alignment-scan.1 +noinst_DATA = $(top_builddir)/html/virt-alignment-scan.1.html + +virt-alignment-scan.1 $(top_builddir)/html/virt-alignment-scan.1.html: stamp-virt-alignment-scan.pod + +stamp-virt-alignment-scan.pod: virt-alignment-scan.pod + $(top_builddir)/podwrapper.sh \ + --man virt-alignment-scan.1 \ + --html $(top_builddir)/html/virt-alignment-scan.1.html \ + $< + touch $@ + +# Tests. + +# random_val := $(shell awk 'BEGIN{srand(); print 1+int(255*rand())}' < /dev/null) + +# TESTS_ENVIRONMENT = \ +# MALLOC_PERTURB_=$(random_val) \ +# LD_LIBRARY_PATH=$(top_builddir)/src/.libs \ +# LIBGUESTFS_PATH=$(top_builddir)/appliance \ +# TMPDIR=$(top_builddir) + +# TESTS = test-virt-alignment-scan.sh diff --git a/align/scan.c b/align/scan.c new file mode 100644 index 0000000..a409654 --- /dev/null +++ b/align/scan.c @@ -0,0 +1,287 @@ +/* virt-alignment-scan + * Copyright (C) 2011 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBVIRT +#include +#include +#endif + +#include "progname.h" +#include "c-ctype.h" + +#include "guestfs.h" +#include "options.h" + +/* These globals are shared with options.c. */ +guestfs_h *g; + +int read_only = 1; +int live = 0; +int verbose = 0; +int keys_from_stdin = 0; +int echo_keys = 0; +const char *libvirt_uri = NULL; +int inspector = 0; + +static int quiet = 0; /* --quiet */ + +static int scan (void); + +static inline char * +bad_cast (char const *s) +{ + return (char *) s; +} + +static void __attribute__((noreturn)) +usage (int status) +{ + if (status != EXIT_SUCCESS) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else { + fprintf (stdout, + _("%s: check alignment of virtual machine partitions\n" + "Copyright (C) 2011 Red Hat Inc.\n" + "Usage:\n" + " %s [--options] -d domname\n" + " %s [--options] -a disk.img [-a disk.img ...]\n" + "Options:\n" + " -a|--add image Add image\n" + " -c|--connect uri Specify libvirt URI for -d option\n" + " -d|--domain guest Add disks from libvirt guest\n" + " --format[=raw|..] Force disk format for -a option\n" + " --help Display brief help\n" + " -q|--quiet No output, just exit code\n" + " -v|--verbose Verbose messages\n" + " -V|--version Display version and exit\n" + " -x Trace libguestfs API calls\n" + "For more information, see the manpage %s(1).\n"), + program_name, program_name, program_name, + program_name); + } + exit (status); +} + +int +main (int argc, char *argv[]) +{ + /* Set global program name that is not polluted with libtool artifacts. */ + set_program_name (argv[0]); + + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEBASEDIR); + textdomain (PACKAGE); + + enum { HELP_OPTION = CHAR_MAX + 1 }; + + static const char *options = "a:c:d:qvVx"; + static const struct option long_options[] = { + { "add", 1, 0, 'a' }, + { "connect", 1, 0, 'c' }, + { "domain", 1, 0, 'd' }, + { "format", 2, 0, 0 }, + { "help", 0, 0, HELP_OPTION }, + { "quiet", 0, 0, 'q' }, + { "verbose", 0, 0, 'v' }, + { "version", 0, 0, 'V' }, + { 0, 0, 0, 0 } + }; + struct drv *drvs = NULL; + struct drv *drv; + const char *format = NULL; + int c; + int option_index; + int exit_code; + + g = guestfs_create (); + if (g == NULL) { + fprintf (stderr, _("guestfs_create: failed to create handle\n")); + exit (EXIT_FAILURE); + } + + argv[0] = bad_cast (program_name); + + for (;;) { + c = getopt_long (argc, argv, options, long_options, &option_index); + if (c == -1) break; + + switch (c) { + case 0: /* options which are long only */ + if (STREQ (long_options[option_index].name, "format")) { + if (!optarg || STREQ (optarg, "")) + format = NULL; + else + format = optarg; + } else { + fprintf (stderr, _("%s: unknown long option: %s (%d)\n"), + program_name, long_options[option_index].name, option_index); + exit (EXIT_FAILURE); + } + break; + + case 'a': + OPTION_a; + break; + + case 'c': + OPTION_c; + break; + + case 'd': + OPTION_d; + break; + + case 'q': + quiet = 1; + break; + + case 'v': + OPTION_v; + break; + + case 'V': + OPTION_V; + break; + + case 'x': + OPTION_x; + break; + + case HELP_OPTION: + usage (EXIT_SUCCESS); + + default: + usage (EXIT_FAILURE); + } + } + + /* These are really constants, but they have to be variables for the + * options parsing code. Assert here that they have known-good + * values. + */ + assert (read_only == 1); + assert (inspector == 0); + assert (live == 0); + + /* Must be no extra arguments on the command line. */ + if (optind != argc) + usage (EXIT_FAILURE); + + /* The user didn't specify any drives to scan. */ + if (drvs == NULL) + usage (EXIT_FAILURE); + + /* Add domains/drives from the command line (for a single guest). */ + add_drives (drvs, 'a'); + + if (guestfs_launch (g) == -1) + exit (EXIT_FAILURE); + + /* Free up data structures, no longer needed after this point. */ + free_drives (drvs); + + /* Perform the scan. */ + exit_code = scan (); + + guestfs_close (g); + + exit (exit_code); +} + +static int +scan (void) +{ + int exit_code = 0; + char **devices; + size_t i, j; + size_t alignment; + uint64_t start; + struct guestfs_partition_list *parts; + + devices = guestfs_list_devices (g); + + for (i = 0; devices[i] != NULL; ++i) { + parts = guestfs_part_list (g, devices[i]); + + /* Canonicalize the name of the device for printing. */ + if (STRPREFIX (devices[i], "/dev/") && + (devices[i][5] == 'h' || devices[i][5] == 'v') && + devices[i][6] == 'd' && + c_isalpha (devices[i][7])) + devices[i][5] = 's'; + + for (j = 0; j < parts->len; ++j) { + /* Start offset of the partition in bytes. */ + start = parts->val[j].part_start; + + if (!quiet) + printf ("%s%d %12" PRIu64 " ", + devices[i], (int) parts->val[j].part_num, start); + + /* What's the alignment? */ + if (start == 0) /* Probably not possible, but anyway. */ + alignment = 64; + else + for (alignment = 0; (start & 1) == 0; alignment++, start /= 2) + ; + + if (!quiet) { + if (alignment < 10) + printf ("%12" PRIu64 " ", UINT64_C(1) << alignment); + else if (alignment < 64) + printf ("%12" PRIu64 "K ", UINT64_C(1) << (alignment - 10)); + else + printf ("- "); + } + + if (alignment < 12) { /* Bad in general: < 4K alignment */ + exit_code = 3; + if (!quiet) + printf ("bad (%s)\n", _("alignment < 4K")); + } else if (alignment < 16) { /* Bad on NetApps: < 64K alignment */ + if (exit_code < 2) + exit_code = 2; + if (!quiet) + printf ("bad (%s)\n", _("alignment < 64K")); + } else { + if (!quiet) + printf ("ok\n"); + } + } + + guestfs_free_partition_list (parts); + free (devices[i]); + } + free (devices); + + return exit_code; +} diff --git a/align/virt-alignment-scan.pod b/align/virt-alignment-scan.pod new file mode 100755 index 0000000..dff587b --- /dev/null +++ b/align/virt-alignment-scan.pod @@ -0,0 +1,234 @@ +=encoding utf8 + +=head1 NAME + +virt-alignment-scan - Check alignment of virtual machine partitions + +=head1 SYNOPSIS + + virt-alignment-scan [--options] + + virt-alignment-scan [--options] -d domname + + virt-alignment-scan [--options] -a disk.img [-a disk.img ...] + +=head1 DESCRIPTION + +When older operating systems install themselves, the partitioning +tools place partitions at a sector misaligned with the underlying +storage (commonly the first partition starts on sector C<63>). +Misaligned partitions can result in an operating system issuing more +I/O than should be necessary. + +The virt-alignment-scan tool checks the alignment of partitions in +virtual machines and disk images and warns you if there are alignment +problems. + +Currently there is no virt tool for fixing alignment problems, except +to reinstall the operating system. The following NetApp document +summarises the problem and possible solutions: +L + +=head1 OUTPUT + +To run this tool on a disk image directly, use the I<-a> option: + + $ virt-alignment-scan -a winxp.img + /dev/sda1 32256 512 bad (alignment < 4K) + + $ virt-alignment-scan -a fedora16.img + /dev/sda1 1048576 1024K ok + /dev/sda2 2097152 2048K ok + /dev/sda3 526385152 2048K ok + +To run the tool on a guest known to libvirt, use the I<-d> option and +possibly the I<-c> option: + + # virt-alignment-scan -d RHEL5 + /dev/sda1 32256 512 bad (alignment < 4K) + /dev/sda2 106928640 512 bad (alignment < 4K) + + $ virt-alignment-scan -c qemu:///system -d Win7TwoDisks + /dev/sda1 1048576 1024K ok + /dev/sda2 105906176 1024K ok + /dev/sdb1 65536 64K ok + +The output consists of 4 or more whitespace-separated columns. Only +the first 4 columns are signficant if you want to parse this from a +program. The columns are: + +=over 4 + +=item col 1 + +the device and partition name (eg. C meaning the +first partition on the first block device) + +=item col 2 + +the start of the partition in bytes + +=item col 3 + +the alignment in bytes or Kbytes (eg. C<512> or C<4K>) + +=item col 4 + +C if the alignment is best for performance, or C if the +alignment can cause performance problems + +=item cols 5+ + +optional free-text explanation. + +=back + +The exit code from the program changes depending on whether poorly +aligned partitions were found. See L below. + +If you just want the exit code with no output, use the I<-q> option. + +=head1 OPTIONS + +=over 4 + +=item B<--help> + +Display brief help. + +=item B<-a> file + +=item B<--add> file + +Add I which should be a disk image from a virtual machine. + +The format of the disk image is auto-detected. To override this and +force a particular format use the I<--format=..> option. + +=item B<-c> URI + +=item B<--connect> URI + +If using libvirt, connect to the given I. If omitted, then we +connect to the default libvirt hypervisor. + +If you specify guest block devices directly (I<-a>), then libvirt is +not used at all. + +=item B<-d> guest + +=item B<--domain> guest + +Add all the disks from the named libvirt guest. Domain UUIDs can be +used instead of names. + +=item B<--format=raw|qcow2|..> + +=item B<--format> + +The default for the I<-a> option is to auto-detect the format of the +disk image. Using this forces the disk format for I<-a> options which +follow on the command line. Using I<--format> with no argument +switches back to auto-detection for subsequent I<-a> options. + +For example: + + virt-alignment-scan --format=raw -a disk.img + +forces raw format (no auto-detection) for C. + + virt-alignment-scan --format=raw -a disk.img --format -a another.img + +forces raw format (no auto-detection) for C and reverts to +auto-detection for C. + +If you have untrusted raw-format guest disk images, you should use +this option to specify the disk format. This avoids a possible +security problem with malicious guests (CVE-2010-3851). + +=item B<-q> + +=item B<--quiet> + +Don't produce any output. Just set the exit code +(see L below). + +=item B<-v> + +=item B<--verbose> + +Enable verbose messages for debugging. + +=item B<-V> + +=item B<--version> + +Display version number and exit. + +=item B<-x> + +Enable tracing of libguestfs API calls. + +=back + +=head1 SHELL QUOTING + +Libvirt guest names can contain arbitrary characters, some of which +have meaning to the shell such as C<#> and space. You may need to +quote or escape these characters on the command line. See the shell +manual page L for details. + +=head1 EXIT STATUS + +This program returns: + +=over 4 + +=item code 0 + +successful exit, all partitions are aligned E 64K for best performance + +=item code 1 + +an error scanning the disk image or guest + +=item code 2 + +successful exit, some partitions have alignment E 64K which can result +in poor performance on high end network storage + +=item code 3 + +successful exit, some partitions have alignment E 4K which can result +in poor performance on most hypervisors + +=back + +=head1 SEE ALSO + +L, +L, +L, +L. + +=head1 AUTHOR + +Richard W.M. Jones L + +=head1 COPYRIGHT + +Copyright (C) 2011 Red Hat Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. diff --git a/configure.ac b/configure.ac index c15af17..104a81e 100644 --- a/configure.ac +++ b/configure.ac @@ -941,6 +941,7 @@ AC_CONFIG_FILES([podwrapper.sh], AC_CONFIG_FILES([run], [chmod +x run]) AC_CONFIG_FILES([Makefile + align/Makefile appliance/Makefile capitests/Makefile cat/Makefile diff --git a/fish/guestfish.pod b/fish/guestfish.pod index 17e0da0..032e644 100644 --- a/fish/guestfish.pod +++ b/fish/guestfish.pod @@ -1236,6 +1236,7 @@ Any existing file with the same name will be overwritten. L, L, +L, L, L, L, diff --git a/po-docs/ja/Makefile.am b/po-docs/ja/Makefile.am index baf4992..d03fdb3 100644 --- a/po-docs/ja/Makefile.am +++ b/po-docs/ja/Makefile.am @@ -26,6 +26,7 @@ CLEANFILES = *.1 *.3 MANPAGES = \ guestfs.3 \ guestfish.1 \ + virt-alignment-scan.1 \ virt-copy-in.1 \ virt-copy-out.1 \ virt-tar-in.1 \ diff --git a/po-docs/podfiles b/po-docs/podfiles index daf28de..48732e7 100644 --- a/po-docs/podfiles +++ b/po-docs/podfiles @@ -1,3 +1,4 @@ +../align/virt-alignment-scan.pod ../cat/virt-cat.pod ../cat/virt-filesystems.pod ../cat/virt-ls.pod diff --git a/po-docs/uk/Makefile.am b/po-docs/uk/Makefile.am index baf4992..d03fdb3 100644 --- a/po-docs/uk/Makefile.am +++ b/po-docs/uk/Makefile.am @@ -26,6 +26,7 @@ CLEANFILES = *.1 *.3 MANPAGES = \ guestfs.3 \ guestfish.1 \ + virt-alignment-scan.1 \ virt-copy-in.1 \ virt-copy-out.1 \ virt-tar-in.1 \ diff --git a/po/POTFILES.in b/po/POTFILES.in index 634fe19..8a061d7 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,3 +1,4 @@ +align/scan.c cat/virt-cat.c cat/virt-filesystems.c cat/virt-ls.c diff --git a/src/guestfs.pod b/src/guestfs.pod index 331945d..25ca56d 100644 --- a/src/guestfs.pod +++ b/src/guestfs.pod @@ -2823,6 +2823,10 @@ the programmers. =over 4 +=item C + +L command and documentation. + =item C The libguestfs appliance, build scripts and so on. @@ -3183,6 +3187,7 @@ L, L, L, L, +L, L, L, L, -- 1.8.3.1