]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
kvm tools: Split custom rootfs init into two stages
authorSasha Levin <levinsasha928@gmail.com>
Mon, 5 Dec 2011 14:16:32 +0000 (16:16 +0200)
committerPekka Enberg <penberg@kernel.org>
Sun, 11 Dec 2011 09:15:08 +0000 (11:15 +0200)
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>
tools/kvm/Makefile
tools/kvm/builtin-run.c
tools/kvm/guest/init.c
tools/kvm/guest/init_stage2.c [new file with mode: 0644]

index bb5f6b0f812707c67a16301e371e3f135f0adbe1..0325be9c0ed38fac76eda63d30e59d27aa32efa1 100644 (file)
@@ -21,6 +21,7 @@ TAGS  := ctags
 PROGRAM        := kvm
 
 GUEST_INIT := guest/init
+GUEST_INIT_S2 := guest/init_stage2
 
 OBJS   += builtin-balloon.o
 OBJS   += builtin-debug.o
@@ -179,7 +180,7 @@ WARNINGS += -Wwrite-strings
 
 CFLAGS += $(WARNINGS)
 
-all: $(PROGRAM) $(GUEST_INIT)
+all: $(PROGRAM) $(GUEST_INIT) $(GUEST_INIT_S2)
 
 KVMTOOLS-VERSION-FILE:
        @$(SHELL_PATH) util/KVMTOOLS-VERSION-GEN $(OUTPUT)
@@ -193,6 +194,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
@@ -255,7 +260,7 @@ bios/bios-rom.h: bios/bios.bin.elf
        $(E) "  NM      " $@
        $(Q) cd 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"
@@ -269,7 +274,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) $(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
index 33de4f6ef9276015865c56957658bf0d8e49df59..de3001ed1aef96cabb4f232de4285d7ac2a8717e 100644 (file)
@@ -702,6 +702,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];
@@ -864,6 +889,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));
index 8975023cc89961c744437bdfb1d3fd2c321704e1..032a261bb36d9f81ad196a0ed36d98d053f6aab6 100644 (file)
@@ -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));
 
diff --git a/tools/kvm/guest/init_stage2.c b/tools/kvm/guest/init_stage2.c
new file mode 100644 (file)
index 0000000..af615a0
--- /dev/null
@@ -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;
+}