mirror of
https://github.com/clearlinux/kvmtool.git
synced 2026-06-16 02:15:47 +00:00
kvm tools: Split custom rootfs init into two stages
Currently custom rootfs init is built along with the main KVM tools executable and is copied into custom rootfs directories when they are created with 'kvm setup'. The problem there is that if the init code changes, they have to be manually copied to custom rootfs directories. Instead, this patch splits init process into two parts. One part that simply handles mounts, and passes it to stage 2 of the init. Stage 2 really sits along in the code tree, and does all the heavy lifting. This allows us to make init changes in the code tree and have it automatically be updated in custom rootfs guests without having to copy files over manua Signed-off-by: Sasha Levin <levinsasha928@gmail.com> [ penberg@kernel.org: fix 'make check' breakage in Makefile ] Signed-off-by: Pekka Enberg <penberg@kernel.org>
This commit is contained in:
@@ -26,6 +26,7 @@ TAGS := ctags
|
||||
PROGRAM := kvm
|
||||
|
||||
GUEST_INIT := guest/init
|
||||
GUEST_INIT_S2 := guest/init_stage2
|
||||
|
||||
OBJS += builtin-balloon.o
|
||||
OBJS += builtin-debug.o
|
||||
@@ -207,7 +208,7 @@ WARNINGS += -Wwrite-strings
|
||||
|
||||
CFLAGS += $(WARNINGS)
|
||||
|
||||
all: arch_support_check $(PROGRAM) $(GUEST_INIT)
|
||||
all: arch_support_check $(PROGRAM) $(GUEST_INIT) $(GUEST_INIT_S2)
|
||||
|
||||
arch_support_check:
|
||||
$(UNSUPP_ERR)
|
||||
@@ -224,6 +225,10 @@ $(GUEST_INIT): guest/init.c
|
||||
$(E) " LINK " $@
|
||||
$(Q) $(CC) -static guest/init.c -o $@
|
||||
|
||||
$(GUEST_INIT_S2): guest/init_stage2.c
|
||||
$(E) " LINK " $@
|
||||
$(Q) $(CC) -static guest/init_stage2.c -o $@
|
||||
|
||||
$(DEPS):
|
||||
|
||||
%.d: %.c
|
||||
@@ -286,7 +291,7 @@ x86/bios/bios-rom.h: x86/bios/bios.bin.elf
|
||||
$(E) " NM " $@
|
||||
$(Q) cd x86/bios && sh gen-offsets.sh > bios-rom.h && cd ..
|
||||
|
||||
check: $(PROGRAM)
|
||||
check: all
|
||||
$(MAKE) -C tests
|
||||
./$(PROGRAM) run tests/pit/tick.bin
|
||||
./$(PROGRAM) run -d tests/boot/boot_test.iso -p "init=init"
|
||||
@@ -300,7 +305,7 @@ clean:
|
||||
$(Q) rm -f x86/bios/bios-rom.h
|
||||
$(Q) rm -f tests/boot/boot_test.iso
|
||||
$(Q) rm -rf tests/boot/rootfs/
|
||||
$(Q) rm -f $(DEPS) $(OBJS) $(PROGRAM) $(GUEST_INIT)
|
||||
$(Q) rm -f $(DEPS) $(OBJS) $(PROGRAM) $(GUEST_INIT) $(GUEST_INIT_S2)
|
||||
$(Q) rm -f cscope.*
|
||||
$(Q) rm -f $(KVM_INCLUDE)/common-cmds.h
|
||||
$(Q) rm -f KVMTOOLS-VERSION-FILE
|
||||
|
||||
@@ -703,6 +703,31 @@ void kvm_run_help(void)
|
||||
usage_with_options(run_usage, options);
|
||||
}
|
||||
|
||||
static int kvm_custom_stage2(void)
|
||||
{
|
||||
char tmp[PATH_MAX], dst[PATH_MAX], *src;
|
||||
const char *rootfs;
|
||||
int r;
|
||||
|
||||
src = realpath("guest/init_stage2", NULL);
|
||||
if (src == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (image_filename[0] == NULL)
|
||||
rootfs = "default";
|
||||
else
|
||||
rootfs = image_filename[0];
|
||||
|
||||
snprintf(tmp, PATH_MAX, "%s%s/virt/init_stage2", kvm__get_dir(), rootfs);
|
||||
remove(tmp);
|
||||
|
||||
snprintf(dst, PATH_MAX, "/host/%s", src);
|
||||
r = symlink(dst, tmp);
|
||||
free(src);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int kvm_cmd_run(int argc, const char **argv, const char *prefix)
|
||||
{
|
||||
static char real_cmdline[2048], default_name[20];
|
||||
@@ -869,6 +894,8 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix)
|
||||
strcat(real_cmdline, " init=/virt/init");
|
||||
if (!no_dhcp)
|
||||
strcat(real_cmdline, " ip=dhcp");
|
||||
if (kvm_custom_stage2())
|
||||
die("Failed linking stage 2 of init.");
|
||||
}
|
||||
} else if (!strstr(real_cmdline, "root=")) {
|
||||
strlcat(real_cmdline, " root=/dev/vda rw ", sizeof(real_cmdline));
|
||||
|
||||
+3
-11
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This is a simple init for shared rootfs guests. It brings up critical
|
||||
* mountpoints and then launches /bin/sh.
|
||||
* This is a simple init for shared rootfs guests. This part should be limited
|
||||
* to doing mounts and running stage 2 of the init process.
|
||||
*/
|
||||
#include <sys/mount.h>
|
||||
#include <string.h>
|
||||
@@ -30,15 +30,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
do_mounts();
|
||||
|
||||
/* get session leader */
|
||||
setsid();
|
||||
|
||||
/* set controlling terminal */
|
||||
ioctl (0, TIOCSCTTY, 1);
|
||||
|
||||
puts("Starting '/bin/sh'...");
|
||||
|
||||
run_process("/bin/sh");
|
||||
run_process("/virt/init_stage2");
|
||||
|
||||
printf("Init failed: %s\n", strerror(errno));
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This is a stage 2 of the init. This part should do all the heavy
|
||||
* lifting such as setting up the console and calling /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[] = { "TERM=linux", NULL };
|
||||
|
||||
return execve(filename, new_argv, new_env);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* get session leader */
|
||||
setsid();
|
||||
|
||||
/* set controlling terminal */
|
||||
ioctl(0, TIOCSCTTY, 1);
|
||||
|
||||
puts("Starting '/bin/sh'...");
|
||||
|
||||
run_process("/bin/sh");
|
||||
|
||||
printf("Init failed: %s\n", strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user