kvm tools: Introduce 'kvm setup' command

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>
This commit is contained in:
Pekka Enberg
2011-08-24 16:23:38 +03:00
committed by Will Deacon
parent 06f4810348
commit 282113fd51
8 changed files with 260 additions and 2 deletions
+1
View File
@@ -6,4 +6,5 @@ tags
include/common-cmds.h
tests/boot/boot_test.iso
tests/boot/rootfs/
guest/init
KVMTOOLS-VERSION-FILE
+15
View File
@@ -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.
+9 -2
View File
@@ -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
+185
View File
@@ -0,0 +1,185 @@
#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",
"/var/lib",
"/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);
}
+1
View File
@@ -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
+40
View File
@@ -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;
}
+7
View File
@@ -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
+2
View File
@@ -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 },
};