All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC/PATCH] kvm tools: Introduce 'kvm setup' command
@ 2011-08-24 14:43 Pekka Enberg
  0 siblings, 0 replies; only message in thread
From: Pekka Enberg @ 2011-08-24 14:43 UTC (permalink / raw)
  To: kvm; +Cc: Pekka Enberg, Asias He, Cyrill Gorcunov, Ingo Molnar, Sasha Levin

This patch implements 'kvm setup' command that can be used to setup a guest
filesystem that shares system libraries and binaries from host filesystem in
read-only mode.

You can setup a new shared rootfs guest with:

  ./kvm setup -n default

and launch it with:

  ./kvm run --9p /,hostfs -p "init=virt/init" -d ~/.kvm-tools/default/

We want to teach 'kvm run' to be able to launch guest filesystems by name in
the future. Furthermore, 'kvm run' should setup a 'default' filesystem and use
it by default unless the user specifies otherwise.

Cc: Asias He <asias.hejun@gmail.com>
Cc: Cyrill Gorcunov <gorcunov@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Sasha Levin <levinsasha928@gmail.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
---
 tools/kvm/.gitignore                  |    1 +
 tools/kvm/Documentation/kvm-setup.txt |   15 +++
 tools/kvm/Makefile                    |   11 ++-
 tools/kvm/builtin-setup.c             |  184 +++++++++++++++++++++++++++++++++
 tools/kvm/command-list.txt            |    1 +
 tools/kvm/guest/init.c                |   40 +++++++
 tools/kvm/include/kvm/builtin-setup.h |    7 ++
 tools/kvm/kvm-cmd.c                   |    2 +
 8 files changed, 259 insertions(+), 2 deletions(-)
 create mode 100644 tools/kvm/Documentation/kvm-setup.txt
 create mode 100644 tools/kvm/builtin-setup.c
 create mode 100644 tools/kvm/guest/init.c
 create mode 100644 tools/kvm/include/kvm/builtin-setup.h

diff --git a/tools/kvm/.gitignore b/tools/kvm/.gitignore
index 852d052..6ace4ec 100644
--- a/tools/kvm/.gitignore
+++ b/tools/kvm/.gitignore
@@ -6,4 +6,5 @@ tags
 include/common-cmds.h
 tests/boot/boot_test.iso
 tests/boot/rootfs/
+guest/init
 KVMTOOLS-VERSION-FILE
diff --git a/tools/kvm/Documentation/kvm-setup.txt b/tools/kvm/Documentation/kvm-setup.txt
new file mode 100644
index 0000000..c845d17
--- /dev/null
+++ b/tools/kvm/Documentation/kvm-setup.txt
@@ -0,0 +1,15 @@
+kvm-setup(1)
+================
+
+NAME
+----
+kvm-setup - Setup a new virtual machine
+
+SYNOPSIS
+--------
+[verse]
+'kvm setup <name>'
+
+DESCRIPTION
+-----------
+The command setups a virtual machine.
diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile
index 669386f..25cbd7e 100644
--- a/tools/kvm/Makefile
+++ b/tools/kvm/Makefile
@@ -20,6 +20,8 @@ TAGS	:= ctags
 
 PROGRAM	:= kvm
 
+GUEST_INIT := guest/init
+
 OBJS	+= builtin-balloon.o
 OBJS	+= builtin-debug.o
 OBJS	+= builtin-help.o
@@ -28,6 +30,7 @@ OBJS	+= builtin-stat.o
 OBJS	+= builtin-pause.o
 OBJS	+= builtin-resume.o
 OBJS	+= builtin-run.o
+OBJS	+= builtin-setup.o
 OBJS	+= builtin-stop.o
 OBJS	+= builtin-version.o
 OBJS	+= cpuid.o
@@ -159,7 +162,7 @@ WARNINGS += -Wunused-result
 
 CFLAGS	+= $(WARNINGS)
 
-all: $(PROGRAM)
+all: $(PROGRAM) $(GUEST_INIT)
 
 KVMTOOLS-VERSION-FILE:
 	@$(SHELL_PATH) util/KVMTOOLS-VERSION-GEN $(OUTPUT)
@@ -169,6 +172,10 @@ $(PROGRAM): $(DEPS) $(OBJS)
 	$(E) "  LINK    " $@
 	$(Q) $(CC) $(OBJS) $(LIBS) -o $@
 
+$(GUEST_INIT): guest/init.c
+	$(E) "  LINK    " $@
+	$(Q) $(CC) -static guest/init.c -o $@
+
 $(DEPS):
 
 %.d: %.c
@@ -240,7 +247,7 @@ clean:
 	$(Q) rm -f bios/bios-rom.h
 	$(Q) rm -f tests/boot/boot_test.iso
 	$(Q) rm -rf tests/boot/rootfs/
-	$(Q) rm -f $(DEPS) $(OBJS) $(PROGRAM)
+	$(Q) rm -f $(DEPS) $(OBJS) $(PROGRAM) $(GUEST_INIT)
 	$(Q) rm -f cscope.*
 	$(Q) rm -f $(KVM_INCLUDE)/common-cmds.h
 	$(Q) rm -f KVMTOOLS-VERSION-FILE
diff --git a/tools/kvm/builtin-setup.c b/tools/kvm/builtin-setup.c
new file mode 100644
index 0000000..4280fe0
--- /dev/null
+++ b/tools/kvm/builtin-setup.c
@@ -0,0 +1,184 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-setup.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define KVM_PID_FILE_PATH	"/.kvm-tools/"
+#define HOME_DIR		getenv("HOME")
+
+static const char *instance_name;
+
+static const char * const setup_usage[] = {
+	"kvm setup [-n name]",
+	NULL
+};
+
+static const struct option setup_options[] = {
+	OPT_GROUP("General options:"),
+	OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+	OPT_END()
+};
+
+static void parse_setup_options(int argc, const char **argv)
+{
+	while (argc != 0) {
+		argc = parse_options(argc, argv, setup_options, setup_usage,
+				PARSE_OPT_STOP_AT_NON_OPTION);
+		if (argc != 0)
+			kvm_setup_help();
+	}
+}
+
+void kvm_setup_help(void)
+{
+	usage_with_options(setup_usage, setup_options);
+}
+
+static int copy_file(const char *from, const char *to)
+{
+	int in_fd, out_fd;
+	void *src, *dst;
+	struct stat st;
+	int err = -1;
+
+	in_fd = open(from, O_RDONLY);
+	if (in_fd < 0)
+		return err;
+
+	if (fstat(in_fd, &st) < 0)
+		goto error_close_in;
+
+	out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
+	if (out_fd < 0)
+		goto error_close_in;
+
+	src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0);
+	if (src == MAP_FAILED)
+		goto error_close_out;
+
+	if (ftruncate(out_fd, st.st_size) < 0)
+		goto error_munmap_src;
+
+	dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0);
+	if (dst == MAP_FAILED)
+		goto error_munmap_src;
+
+	memcpy(dst, src, st.st_size);
+
+	if (fsync(out_fd) < 0)
+		goto error_munmap_dst;
+
+	err = 0;
+
+error_munmap_dst:
+	munmap(dst, st.st_size);
+error_munmap_src:
+	munmap(src, st.st_size);
+error_close_out:
+	close(out_fd);
+error_close_in:
+	close(in_fd);
+
+	return err;
+}
+
+static const char *guestfs_dirs[] = {
+	"/dev",
+	"/etc",
+	"/home",
+	"/host",
+	"/proc",
+	"/root",
+	"/sys",
+	"/var",
+	"/virt",
+};
+
+static const char *guestfs_symlinks[] = {
+	"/bin",
+	"/lib",
+	"/lib64",
+	"/sbin",
+	"/usr",
+};
+
+static int copy_init(const char *guestfs_name)
+{
+	char path[PATH_MAX];
+
+	snprintf(path, PATH_MAX, "%s%s%s/virt/init", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name);
+
+	return copy_file("guest/init", path);
+}
+
+static int make_guestfs_symlink(const char *guestfs_name, const char *path)
+{
+	char target[PATH_MAX];
+	char name[PATH_MAX];
+
+	snprintf(name, PATH_MAX, "%s%s%s%s", HOME_DIR, KVM_PID_FILE_PATH, guestfs_name, path);
+
+	snprintf(target, PATH_MAX, "/host%s", path);
+
+	return symlink(target, name);
+}
+
+static void make_dir(const char *dir)
+{
+	char name[PATH_MAX];
+
+	snprintf(name, PATH_MAX, "%s%s%s", HOME_DIR, KVM_PID_FILE_PATH, dir);
+
+	mkdir(name, 0777);
+}
+
+static void make_guestfs_dir(const char *guestfs_name, const char *dir)
+{
+	char name[PATH_MAX];
+
+	snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir);
+
+	make_dir(name);
+}
+
+static int do_setup(const char *guestfs_name)
+{
+	unsigned int i;
+
+	make_dir(guestfs_name);
+
+	for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++)
+		make_guestfs_dir(guestfs_name, guestfs_dirs[i]);
+
+	for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) {
+		make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]);
+	}
+
+	return copy_init(guestfs_name);
+}
+
+int kvm_cmd_setup(int argc, const char **argv, const char *prefix)
+{
+	parse_setup_options(argc, argv);
+
+	if (instance_name == NULL)
+		kvm_setup_help();
+
+	return do_setup(instance_name);
+}
diff --git a/tools/kvm/command-list.txt b/tools/kvm/command-list.txt
index f201d75..0d16c62 100644
--- a/tools/kvm/command-list.txt
+++ b/tools/kvm/command-list.txt
@@ -3,6 +3,7 @@
 # command name			category [deprecated] [common]
 #
 kvm-run				mainporcelain common
+kvm-setup			mainporcelain common
 kvm-pause			common
 kvm-resume			common
 kvm-version			common
diff --git a/tools/kvm/guest/init.c b/tools/kvm/guest/init.c
new file mode 100644
index 0000000..837acfb
--- /dev/null
+++ b/tools/kvm/guest/init.c
@@ -0,0 +1,40 @@
+/*
+ * This is a simple init for shared rootfs guests. It brings up critical
+ * mountpoints and then launches /bin/sh.
+ */
+#include <sys/mount.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+static int run_process(char *filename)
+{
+	char *new_argv[] = { filename, NULL };
+	char *new_env[] = { NULL };
+
+	return execve(filename, new_argv, new_env);
+}
+
+static void do_mounts(void)
+{
+	mount("hostfs", "/host", "9p", MS_RDONLY, "trans=virtio,version=9p2000.L");
+	mount("", "/sys", "sysfs", 0, NULL);
+	mount("proc", "/proc", "proc", 0, NULL);
+	mount("devtmpfs", "/dev", "devtmpfs", 0, NULL);
+}
+
+int main(int argc, char *argv[])
+{
+	puts("Mounting...");
+
+	do_mounts();
+
+	puts("Starting '/bin/sh'...");
+
+	run_process("/bin/sh");
+
+	printf("Init failed: %s\n", strerror(errno));
+
+	return 0;
+}
diff --git a/tools/kvm/include/kvm/builtin-setup.h b/tools/kvm/include/kvm/builtin-setup.h
new file mode 100644
index 0000000..b0eb345
--- /dev/null
+++ b/tools/kvm/include/kvm/builtin-setup.h
@@ -0,0 +1,7 @@
+#ifndef KVM__SETUP_H
+#define KVM__SETUP_H
+
+int kvm_cmd_setup(int argc, const char **argv, const char *prefix);
+void kvm_setup_help(void);
+
+#endif
diff --git a/tools/kvm/kvm-cmd.c b/tools/kvm/kvm-cmd.c
index 8fc6d22..96108a8 100644
--- a/tools/kvm/kvm-cmd.c
+++ b/tools/kvm/kvm-cmd.c
@@ -11,6 +11,7 @@
 #include "kvm/builtin-balloon.h"
 #include "kvm/builtin-list.h"
 #include "kvm/builtin-version.h"
+#include "kvm/builtin-setup.h"
 #include "kvm/builtin-stop.h"
 #include "kvm/builtin-stat.h"
 #include "kvm/builtin-help.h"
@@ -29,6 +30,7 @@ struct cmd_struct kvm_commands[] = {
 	{ "stop",	kvm_cmd_stop,		kvm_stop_help,		0 },
 	{ "stat",	kvm_cmd_stat,		kvm_stat_help,		0 },
 	{ "help",	kvm_cmd_help,		NULL,			0 },
+	{ "setup",	kvm_cmd_setup,		kvm_setup_help,		0 },
 	{ "run",	kvm_cmd_run,		kvm_run_help,		0 },
 	{ NULL,		NULL,			NULL,			0 },
 };
-- 
1.7.1


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2011-08-24 14:43 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-24 14:43 [RFC/PATCH] kvm tools: Introduce 'kvm setup' command Pekka Enberg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.