summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--po/POTFILES1
-rw-r--r--src/Makefile.am1
-rw-r--r--src/guestfs-internal.h6
-rw-r--r--src/launch-appliance.c2
-rw-r--r--src/launch-libvirt.c6
-rw-r--r--src/launch.c21
-rw-r--r--src/lpj.c139
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;
+}