From patchwork Wed Aug 24 14:43:39 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pekka Enberg X-Patchwork-Id: 1093032 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p7OEhlv8028577 for ; Wed, 24 Aug 2011 14:43:47 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752355Ab1HXOno (ORCPT ); Wed, 24 Aug 2011 10:43:44 -0400 Received: from filtteri6.pp.htv.fi ([213.243.153.189]:45907 "EHLO filtteri6.pp.htv.fi" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751477Ab1HXOno (ORCPT ); Wed, 24 Aug 2011 10:43:44 -0400 Received: from localhost (localhost [127.0.0.1]) by filtteri6.pp.htv.fi (Postfix) with ESMTP id 9248156E33F; Wed, 24 Aug 2011 17:43:42 +0300 (EEST) X-Virus-Scanned: Debian amavisd-new at pp.htv.fi Received: from smtp6.welho.com ([213.243.153.40]) by localhost (filtteri6.pp.htv.fi [213.243.153.189]) (amavisd-new, port 10024) with ESMTP id KtkurMXmycDv; Wed, 24 Aug 2011 17:43:42 +0300 (EEST) Received: from tiger (cs181136138.pp.htv.fi [82.181.136.138]) by smtp6.welho.com (Postfix) with ESMTP id 245E35BC003; Wed, 24 Aug 2011 17:43:42 +0300 (EEST) From: Pekka Enberg To: kvm@vger.kernel.org Cc: Pekka Enberg , Asias He , Cyrill Gorcunov , Ingo Molnar , Sasha Levin Subject: [RFC/PATCH] kvm tools: Introduce 'kvm setup' command Date: Wed, 24 Aug 2011 17:43:39 +0300 Message-Id: <1314197019-10307-1-git-send-email-penberg@kernel.org> X-Mailer: git-send-email 1.7.1 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Wed, 24 Aug 2011 14:43:48 +0000 (UTC) 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 Cc: Cyrill Gorcunov Cc: Ingo Molnar Cc: Sasha Levin Signed-off-by: Pekka Enberg --- 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 ' + +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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +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 }, };