diff options
-rw-r--r-- | po/POTFILES | 1 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/guestfs-internal.h | 6 | ||||
-rw-r--r-- | src/launch-appliance.c | 2 | ||||
-rw-r--r-- | src/launch-libvirt.c | 6 | ||||
-rw-r--r-- | src/launch.c | 21 | ||||
-rw-r--r-- | src/lpj.c | 139 |
7 files changed, 172 insertions, 4 deletions
diff --git a/po/POTFILES b/po/POTFILES index 9cd667ef..51315b89 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -258,6 +258,7 @@ src/launch.c src/libvirt-auth.c src/libvirt-domain.c src/listfs.c +src/lpj.c src/match.c src/private-data.c src/proto.c diff --git a/src/Makefile.am b/src/Makefile.am index d979e251..14f195c9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -166,6 +166,7 @@ libguestfs_la_SOURCES = \ libvirt-auth.c \ libvirt-domain.c \ listfs.c \ + lpj.c \ match.c \ private-data.c \ proto.c \ diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index 07689ffa..0d383a79 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -567,7 +567,8 @@ extern void guestfs___rollback_drives (guestfs_h *g, size_t); extern void guestfs___launch_failed_error (guestfs_h *g); extern void guestfs___add_dummy_appliance_drive (guestfs_h *g); extern void guestfs___free_drives (guestfs_h *g); -extern char *guestfs___appliance_command_line (guestfs_h *g, const char *appliance_dev); +extern char *guestfs___appliance_command_line (guestfs_h *g, const char *appliance_dev, int flags); +#define APPLIANCE_COMMAND_LINE_IS_TCG 1 /* launch-appliance.c */ extern char *guestfs___drive_name (size_t index, char *ret); @@ -606,6 +607,9 @@ extern int guestfs___check_installer_root (guestfs_h *g, struct inspect_fs *fs); typedef int (*guestfs___db_dump_callback) (guestfs_h *g, const unsigned char *key, size_t keylen, const unsigned char *value, size_t valuelen, void *opaque); extern int guestfs___read_db_dump (guestfs_h *g, const char *dumpfile, void *opaque, guestfs___db_dump_callback callback); +/* lpj.c */ +extern int guestfs___get_lpj (guestfs_h *g); + /* fuse.c */ #if HAVE_FUSE extern void guestfs___free_fuse (guestfs_h *g); diff --git a/src/launch-appliance.c b/src/launch-appliance.c index f5647cfb..95cf1319 100644 --- a/src/launch-appliance.c +++ b/src/launch-appliance.c @@ -427,7 +427,7 @@ launch_appliance (guestfs_h *g, const char *arg) add_cmdline (g, initrd); add_cmdline (g, "-append"); - char *cmdline = guestfs___appliance_command_line (g, appliance_dev); + char *cmdline = guestfs___appliance_command_line (g, appliance_dev, 0); add_cmdline (g, cmdline); free (cmdline); diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c index a858e5c5..8d1cb678 100644 --- a/src/launch-libvirt.c +++ b/src/launch-libvirt.c @@ -642,9 +642,13 @@ construct_libvirt_xml_boot (guestfs_h *g, xmlTextWriterPtr xo) { char *cmdline; + int flags; /* Linux kernel command line. */ - cmdline = guestfs___appliance_command_line (g, params->appliance_dev); + flags = 0; + if (!params->is_kvm) + flags |= APPLIANCE_COMMAND_LINE_IS_TCG; + cmdline = guestfs___appliance_command_line (g, params->appliance_dev, flags); XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "os")); diff --git a/src/launch.c b/src/launch.c index cb1d80b6..d5e12f6e 100644 --- a/src/launch.c +++ b/src/launch.c @@ -21,6 +21,7 @@ #include <stdio.h> #include <stdlib.h> #include <stdint.h> +#include <stdbool.h> #include <inttypes.h> #include <unistd.h> #include <string.h> @@ -794,6 +795,13 @@ guestfs__get_state (guestfs_h *g) * appliance disk and must have already been adjusted to take into * account virtio-blk or virtio-scsi; eg "/dev/sdb". * + * The 'flags' parameter can contain the following flags logically + * or'd together (or 0): + * + * GUESTFS___APPLIANCE_COMMAND_LINE_IS_TCG: If we are launching a qemu + * TCG guest (ie. KVM is known to be disabled or unavailable). If you + * don't know, don't pass this flag. + * * Note that this returns a newly allocated buffer which must be freed * by the caller. */ @@ -804,10 +812,19 @@ guestfs__get_state (guestfs_h *g) #endif char * -guestfs___appliance_command_line (guestfs_h *g, const char *appliance_dev) +guestfs___appliance_command_line (guestfs_h *g, const char *appliance_dev, + int flags) { char *term = getenv ("TERM"); char *ret; + bool tcg = flags & APPLIANCE_COMMAND_LINE_IS_TCG; + char lpj_s[64] = ""; + + if (tcg) { + int lpj = guestfs___get_lpj (g); + if (lpj > 0) + snprintf (lpj_s, sizeof lpj_s, " lpj=%d", lpj); + } ret = safe_asprintf (g, @@ -815,6 +832,7 @@ guestfs___appliance_command_line (guestfs_h *g, const char *appliance_dev) " console=" SERIAL_CONSOLE /* serial console */ " udevtimeout=600" /* good for very slow systems (RHBZ#480319) */ " no_timer_check" /* fix for RHBZ#502058 */ + "%s" /* lpj */ " acpi=off" /* we don't need ACPI, turn it off */ " printk.time=1" /* display timestamp before kernel messages */ " cgroup_disable=memory" /* saves us about 5 MB of RAM */ @@ -823,6 +841,7 @@ guestfs___appliance_command_line (guestfs_h *g, const char *appliance_dev) "%s" /* verbose */ " TERM=%s" /* TERM environment variable */ "%s%s", /* append */ + lpj_s, appliance_dev, g->selinux ? "selinux=1 enforcing=0" : "selinux=0", g->verbose ? " guestfs_verbose=1" : "", diff --git a/src/lpj.c b/src/lpj.c new file mode 100644 index 00000000..9c1acce9 --- /dev/null +++ b/src/lpj.c @@ -0,0 +1,139 @@ +/* libguestfs + * Copyright (C) 2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> + +#include "glthread/lock.h" + +#include "guestfs.h" +#include "guestfs-internal.h" + +/* Calculate host kernel loops_per_jiffy, so that this can be passed + * to TCG guests (only) using the lpj= kernel parameter, which avoids + * have to compute this at kernel boot time in a VM. + * + * Currently this is only available in the boot messages, but I have + * posted a patch asking for this to be added to /proc/cpuinfo too. + * + * Notes: + * - We only try to calculate lpj once. + * - Trying to calculate lpj must not fail. If the return value is + * <= 0, it is ignored by the caller. + * + * (Suggested by Marcelo Tosatti) + */ + +gl_lock_define_initialized (static, lpj_lock); +static int lpj = 0; +static int read_lpj_from_var_log_dmesg (guestfs_h *g); +static int read_lpj_from_dmesg (guestfs_h *g); +static int read_lpj_common (guestfs_h *g, const char *func, const char *command); + +int +guestfs___get_lpj (guestfs_h *g) +{ + int r; + + gl_lock_lock (lpj_lock); + if (lpj != 0) + goto out; + + /* Try reading lpj from these sources: + * - /proc/cpuinfo [in future] + * - dmesg + * - /var/log/dmesg + */ + r = read_lpj_from_dmesg (g); + if (r > 0) { + lpj = r; + goto out; + } + lpj = read_lpj_from_var_log_dmesg (g); + + out: + gl_lock_unlock (lpj_lock); + return lpj; +} + +static int +read_lpj_from_dmesg (guestfs_h *g) +{ + return read_lpj_common (g, __func__, + "dmesg | grep -Eo 'lpj=[[:digit:]]+'"); +} + +static int +read_lpj_from_var_log_dmesg (guestfs_h *g) +{ + return read_lpj_common (g, __func__, + "grep -Eo 'lpj=[[:digit:]]+' /var/log/dmesg"); +} + +static void +read_all (guestfs_h *g, void *retv, const char *buf, size_t len) +{ + char **ret = retv; + + *ret = safe_strndup (g, buf, len); +} + +static int +read_lpj_common (guestfs_h *g, const char *func, const char *command) +{ + struct command *cmd; + int r; + char *buf = NULL; + + cmd = guestfs___new_command (g); + guestfs___cmd_add_string_unquoted (cmd, command); + guestfs___cmd_set_stdout_callback (cmd, read_all, &buf, + CMD_STDOUT_FLAG_WHOLE_BUFFER); + r = guestfs___cmd_run (cmd); + guestfs___cmd_close (cmd); + + if (r == -1 || !WIFEXITED (r) || WEXITSTATUS (r) != 0) { + debug (g, "%s: command failed with code %d: %s", func, r, command); + free (buf); + return -1; + } + + if (buf == NULL) { + debug (g, "%s: callback not called", func); + return -1; + } + + if (strlen (buf) < 4 || sscanf (&buf[4], "%d", &r) != 1) { + debug (g, "%s: invalid buffer returned by grep: %s", func, buf); + free (buf); + return -1; + } + + free (buf); + + debug (g, "%s: calculated lpj=%d", func, r); + + return r; +} |