@@ -6,4 +6,5 @@ tags
include/common-cmds.h
tests/boot/boot_test.iso
tests/boot/rootfs/
+guest/init
KVMTOOLS-VERSION-FILE
new file mode 100644
@@ -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.
@@ -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
new file mode 100644
@@ -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);
+}
@@ -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
new file mode 100644
@@ -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;
+}
new file mode 100644
@@ -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
@@ -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 },
};
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