]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
kvm tools: Switch to using UNIX sockets instead of signals
authorSasha Levin <levinsasha928@gmail.com>
Sun, 16 Oct 2011 19:57:54 +0000 (21:57 +0200)
committerPekka Enberg <penberg@kernel.org>
Tue, 18 Oct 2011 16:56:31 +0000 (19:56 +0300)
This patch changes the IPC method to use UNIX sockets instead of
signals.

This allows for more flexibility in moving data between processes, for example
it would allow avoid printing output in the terminal of the guest.

Signed-off-by: Sasha Levin <levinsasha928@gmail.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
14 files changed:
tools/kvm/Makefile
tools/kvm/builtin-balloon.c
tools/kvm/builtin-debug.c
tools/kvm/builtin-list.c
tools/kvm/builtin-pause.c
tools/kvm/builtin-resume.c
tools/kvm/builtin-run.c
tools/kvm/builtin-stat.c
tools/kvm/builtin-stop.c
tools/kvm/include/kvm/kvm-ipc.h [new file with mode: 0644]
tools/kvm/include/kvm/kvm.h
tools/kvm/kvm-ipc.c [new file with mode: 0644]
tools/kvm/kvm.c
tools/kvm/virtio/balloon.c

index 0005b0af790c4253f7aef0db4b70606b1d02c5e3..d9baa69d86f2eb641daff4ae99ce7e85b9170659 100644 (file)
@@ -82,6 +82,7 @@ OBJS  += virtio/9p-pdu.o
 OBJS   += hw/vesa.o
 OBJS   += hw/i8042.o
 OBJS   += hw/pci-shmem.o
+OBJS   += kvm-ipc.o
 
 FLAGS_BFD := $(CFLAGS) -lbfd
 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD))
index 73290635a92a9fd8a9c50a804053ed360f1bda4b..4a42ee8e5492552704f2b1943cb2de2617fb8a11 100644 (file)
@@ -7,12 +7,19 @@
 #include <kvm/builtin-balloon.h>
 #include <kvm/parse-options.h>
 #include <kvm/kvm.h>
+#include <kvm/kvm-ipc.h>
 
-static pid_t instance_pid;
+static int instance;
 static const char *instance_name;
 static u64 inflate;
 static u64 deflate;
 
+struct balloon_cmd {
+       u32 type;
+       u32 len;
+       int amount;
+};
+
 static const char * const balloon_usage[] = {
        "kvm balloon [-n name] [-p pid] [-i amount] [-d amount]",
        NULL
@@ -21,7 +28,6 @@ static const char * const balloon_usage[] = {
 static const struct option balloon_options[] = {
        OPT_GROUP("Instance options:"),
        OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
-       OPT_INTEGER('p', "pid", &instance_pid, "Instance pid"),
        OPT_GROUP("Balloon options:"),
        OPT_U64('i', "inflate", &inflate, "Amount to inflate"),
        OPT_U64('d', "deflate", &deflate, "Amount to deflate"),
@@ -45,7 +51,8 @@ static void parse_balloon_options(int argc, const char **argv)
 
 int kvm_cmd_balloon(int argc, const char **argv, const char *prefix)
 {
-       u64 i;
+       struct balloon_cmd cmd;
+       int r;
 
        parse_balloon_options(argc, argv);
 
@@ -53,23 +60,31 @@ int kvm_cmd_balloon(int argc, const char **argv, const char *prefix)
                kvm_balloon_help();
 
        if (instance_name == NULL &&
-           instance_pid == 0)
+           instance == 0)
                kvm_balloon_help();
 
        if (instance_name)
-               instance_pid = kvm__get_pid_by_instance(instance_name);
+               instance = kvm__get_sock_by_instance(instance_name);
 
-       if (instance_pid <= 0)
+       if (instance <= 0)
                die("Failed locating instance");
 
+       cmd.type = KVM_IPC_BALLOON;
+       cmd.len = sizeof(cmd.amount);
+
        if (inflate)
-               for (i = 0; i < inflate; i++)
-                       kill(instance_pid, SIGKVMADDMEM);
+               cmd.amount = inflate;
        else if (deflate)
-               for (i = 0; i < deflate; i++)
-                       kill(instance_pid, SIGKVMDELMEM);
+               cmd.amount = -deflate;
        else
                kvm_balloon_help();
 
+       r = write(instance, &cmd, sizeof(cmd));
+
+       close(instance);
+
+       if (r < 0)
+               return -1;
+
        return 0;
 }
index 4be12cce6a72f6f3104a0fb3d9969d627d1fef6b..f744a7e5cf09c6e6dba4be12dc60494842a6e5f3 100644 (file)
@@ -3,17 +3,23 @@
 #include <kvm/builtin-debug.h>
 #include <kvm/kvm.h>
 #include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
 
 #include <stdio.h>
 #include <string.h>
 #include <signal.h>
 
 static bool all;
-static pid_t instance_pid;
+static int instance;
 static const char *instance_name;
 
+struct debug_cmd {
+       u32 type;
+       u32 len;
+};
+
 static const char * const debug_usage[] = {
-       "kvm debug [--all] [-n name] [-p pid]",
+       "kvm debug [--all] [-n name]",
        NULL
 };
 
@@ -21,7 +27,6 @@ static const struct option debug_options[] = {
        OPT_GROUP("General options:"),
        OPT_BOOLEAN('a', "all", &all, "Debug all instances"),
        OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
-       OPT_INTEGER('p', "pid", &instance_pid, "Instance pid"),
        OPT_END()
 };
 
@@ -40,9 +45,16 @@ void kvm_debug_help(void)
        usage_with_options(debug_usage, debug_options);
 }
 
-static int do_debug(const char *name, int pid)
+static int do_debug(const char *name, int sock)
 {
-       return kill(pid, SIGQUIT);
+       struct debug_cmd cmd = {KVM_IPC_DEBUG, 0};
+       int r;
+
+       r = write(sock, &cmd, sizeof(cmd));
+       if (r < 0)
+               return r;
+
+       return 0;
 }
 
 int kvm_cmd_debug(int argc, const char **argv, const char *prefix)
@@ -53,14 +65,14 @@ int kvm_cmd_debug(int argc, const char **argv, const char *prefix)
                return kvm__enumerate_instances(do_debug);
 
        if (instance_name == NULL &&
-           instance_pid == 0)
+           instance == 0)
                kvm_debug_help();
 
        if (instance_name)
-               instance_pid = kvm__get_pid_by_instance(instance_name);
+               instance = kvm__get_sock_by_instance(instance_name);
 
-       if (instance_pid <= 0)
+       if (instance <= 0)
                die("Failed locating instance");
 
-       return kill(instance_pid, SIGQUIT);
+       return do_debug(instance_name, instance);
 }
index d80b3fb3f330db65a1e53bb28b4bed0913960f19..12e2537b423580a561e56b9bcaa237012f8e808f 100644 (file)
@@ -3,6 +3,7 @@
 #include <kvm/builtin-list.h>
 #include <kvm/kvm.h>
 #include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
 
 #include <dirent.h>
 #include <stdio.h>
 
 #define PROCESS_NAME "kvm"
 
+struct pid_cmd {
+       u32 type;
+       u32 len;
+};
+
 static bool run;
 static bool rootfs;
 
@@ -32,11 +38,29 @@ void kvm_list_help(void)
        usage_with_options(list_usage, list_options);
 }
 
-static int print_guest(const char *name, int pid)
+static pid_t get_pid(int sock)
+{
+       struct pid_cmd cmd = {KVM_IPC_PID, 0};
+       int r;
+       pid_t pid;
+
+       r = write(sock, &cmd, sizeof(cmd));
+       if (r < 0)
+               return r;
+
+       r = read(sock, &pid, sizeof(pid));
+       if (r < 0)
+               return r;
+
+       return pid;
+}
+
+static int print_guest(const char *name, int sock)
 {
        char proc_name[PATH_MAX];
        char *comm = NULL;
        FILE *fd;
+       pid_t pid = get_pid(sock);
 
        sprintf(proc_name, "/proc/%d/stat", pid);
        fd = fopen(proc_name, "r");
@@ -61,7 +85,7 @@ cleanup:
        if (comm)
                free(comm);
 
-       kvm__remove_pidfile(name);
+       kvm__remove_socket(name);
        return 0;
 }
 
index 7b644ff923853264b915628f3a9930d3b1930085..d16da28ec0bfb36a71ffdd6fdbfac993d2f3376a 100644 (file)
@@ -3,17 +3,23 @@
 #include <kvm/builtin-pause.h>
 #include <kvm/kvm.h>
 #include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
 
 #include <stdio.h>
 #include <string.h>
 #include <signal.h>
 
+struct pause_cmd {
+       u32 type;
+       u32 len;
+};
+
 static bool all;
-static pid_t instance_pid;
+static int instance;
 static const char *instance_name;
 
 static const char * const pause_usage[] = {
-       "kvm pause [--all] [-n name] [-p pid]",
+       "kvm pause [--all] [-n name]",
        NULL
 };
 
@@ -21,7 +27,6 @@ static const struct option pause_options[] = {
        OPT_GROUP("General options:"),
        OPT_BOOLEAN('a', "all", &all, "Pause all instances"),
        OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
-       OPT_INTEGER('p', "pid", &instance_pid, "Instance pid"),
        OPT_END()
 };
 
@@ -40,9 +45,16 @@ void kvm_pause_help(void)
        usage_with_options(pause_usage, pause_options);
 }
 
-static int do_pause(const char *name, int pid)
+static int do_pause(const char *name, int sock)
 {
-       return kill(pid, SIGUSR2);
+       struct pause_cmd cmd = {KVM_IPC_PAUSE, 0};
+       int r;
+
+       r = write(sock, &cmd, sizeof(cmd));
+       if (r < 0)
+               return r;
+
+       return 0;
 }
 
 int kvm_cmd_pause(int argc, const char **argv, const char *prefix)
@@ -53,14 +65,14 @@ int kvm_cmd_pause(int argc, const char **argv, const char *prefix)
                return kvm__enumerate_instances(do_pause);
 
        if (instance_name == NULL &&
-           instance_pid == 0)
+           instance == 0)
                kvm_pause_help();
 
        if (instance_name)
-               instance_pid = kvm__get_pid_by_instance(instance_name);
+               instance = kvm__get_sock_by_instance(instance_name);
 
-       if (instance_pid <= 0)
+       if (instance <= 0)
                die("Failed locating instance");
 
-       return kill(instance_pid, SIGUSR2);
+       return do_pause(instance_name, instance);
 }
index 70de0fc26e1c4c4e8bd47fec71e2e480eebcd7d5..1e76c479e4669c8a13e2ef1dbc9d72105c088709 100644 (file)
@@ -3,17 +3,23 @@
 #include <kvm/builtin-resume.h>
 #include <kvm/kvm.h>
 #include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
 
 #include <stdio.h>
 #include <string.h>
 #include <signal.h>
 
+struct resume_cmd {
+       u32 type;
+       u32 len;
+};
+
 static bool all;
-static pid_t instance_pid;
+static int instance;
 static const char *instance_name;
 
 static const char * const resume_usage[] = {
-       "kvm resume [--all] [-n name] [-p pid]",
+       "kvm resume [--all] [-n name]",
        NULL
 };
 
@@ -21,7 +27,6 @@ static const struct option resume_options[] = {
        OPT_GROUP("General options:"),
        OPT_BOOLEAN('a', "all", &all, "Resume all instances"),
        OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
-       OPT_INTEGER('p', "pid", &instance_pid, "Instance pid"),
        OPT_END()
 };
 
@@ -40,9 +45,16 @@ void kvm_resume_help(void)
        usage_with_options(resume_usage, resume_options);
 }
 
-static int do_resume(const char *name, int pid)
+static int do_resume(const char *name, int sock)
 {
-       return kill(pid, SIGKVMRESUME);
+       struct resume_cmd cmd = {KVM_IPC_RESUME, 0};
+       int r;
+
+       r = write(sock, &cmd, sizeof(cmd));
+       if (r < 0)
+               return r;
+
+       return 0;
 }
 
 int kvm_cmd_resume(int argc, const char **argv, const char *prefix)
@@ -53,14 +65,14 @@ int kvm_cmd_resume(int argc, const char **argv, const char *prefix)
                return kvm__enumerate_instances(do_resume);
 
        if (instance_name == NULL &&
-           instance_pid == 0)
+           instance == 0)
                kvm_resume_help();
 
        if (instance_name)
-               instance_pid = kvm__get_pid_by_instance(instance_name);
+               instance = kvm__get_sock_by_instance(instance_name);
 
-       if (instance_pid <= 0)
+       if (instance <= 0)
                die("Failed locating instance");
 
-       return kill(instance_pid, SIGKVMRESUME);
+       return do_resume(instance_name, instance);
 }
index cb5733a6320ffcbc29bc17ee9d54c64a48b3365d..bbe5a350085ec2cae918865e8bcde319899a307f 100644 (file)
@@ -30,6 +30,7 @@
 #include "kvm/vnc.h"
 #include "kvm/guest_compat.h"
 #include "kvm/pci-shmem.h"
+#include "kvm/kvm-ipc.h"
 
 #include <linux/types.h>
 
@@ -471,11 +472,11 @@ static void handle_sigusr1(int sig)
 /* Pause/resume the guest using SIGUSR2 */
 static int is_paused;
 
-static void handle_sigusr2(int sig)
+static void handle_pause(int fd, u32 type, u32 len, u8 *msg)
 {
-       if (sig == SIGKVMRESUME && is_paused)
+       if (type == KVM_IPC_RESUME && is_paused)
                kvm__continue();
-       else if (sig == SIGUSR2 && !is_paused)
+       else if (type == KVM_IPC_PAUSE && !is_paused)
                kvm__pause();
        else
                return;
@@ -484,7 +485,7 @@ static void handle_sigusr2(int sig)
        pr_info("Guest %s\n", is_paused ? "paused" : "resumed");
 }
 
-static void handle_sigquit(int sig)
+static void handle_debug(int fd, u32 type, u32 len, u8 *msg)
 {
        int i;
 
@@ -514,7 +515,7 @@ static void handle_sigalrm(int sig)
        virtio_console__inject_interrupt(kvm);
 }
 
-static void handle_sigstop(int sig)
+static void handle_stop(int fd, u32 type, u32 len, u8 *msg)
 {
        kvm_cpu__reboot();
 }
@@ -702,14 +703,11 @@ int kvm_cmd_run(int argc, const char **argv, const char *prefix)
        void *ret;
 
        signal(SIGALRM, handle_sigalrm);
-       signal(SIGQUIT, handle_sigquit);
+       kvm_ipc__register_handler(KVM_IPC_DEBUG, handle_debug);
        signal(SIGUSR1, handle_sigusr1);
-       signal(SIGUSR2, handle_sigusr2);
-       signal(SIGKVMSTOP, handle_sigstop);
-       signal(SIGKVMRESUME, handle_sigusr2);
-       /* ignore balloon signal by default if not enable balloon optiion */
-       signal(SIGKVMADDMEM, SIG_IGN);
-       signal(SIGKVMDELMEM, SIG_IGN);
+       kvm_ipc__register_handler(KVM_IPC_PAUSE, handle_pause);
+       kvm_ipc__register_handler(KVM_IPC_RESUME, handle_pause);
+       kvm_ipc__register_handler(KVM_IPC_STOP, handle_stop);
 
        nr_online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
 
index be12d15a16aeeef023a00a38669d9755163e298c..609a6e517db1d40a8e6549bcc5c46ee1f8c63f85 100644 (file)
@@ -3,18 +3,24 @@
 #include <kvm/builtin-stat.h>
 #include <kvm/kvm.h>
 #include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
 
 #include <stdio.h>
 #include <string.h>
 #include <signal.h>
 
+struct stat_cmd {
+       u32 type;
+       u32 len;
+};
+
 static bool mem;
 static bool all;
-static pid_t instance_pid;
+static int instance;
 static const char *instance_name;
 
 static const char * const stat_usage[] = {
-       "kvm stat [command] [--all] [-n name] [-p pid]",
+       "kvm stat [command] [--all] [-n name]",
        NULL
 };
 
@@ -24,7 +30,6 @@ static const struct option stat_options[] = {
        OPT_GROUP("Instance options:"),
        OPT_BOOLEAN('a', "all", &all, "All instances"),
        OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
-       OPT_INTEGER('p', "pid", &instance_pid, "Instance pid"),
        OPT_END()
 };
 
@@ -43,10 +48,18 @@ void kvm_stat_help(void)
        usage_with_options(stat_usage, stat_options);
 }
 
-static int do_memstat(const char *name, int pid)
+static int do_memstat(const char *name, int sock)
 {
+       struct stat_cmd cmd = {KVM_IPC_STAT, 0};
+       int r;
+
        printf("Sending memstat command to %s, output should be on the targets' terminal.\n", name);
-       return kill(pid, SIGKVMMEMSTAT);
+
+       r = write(sock, &cmd, sizeof(cmd));
+       if (r < 0)
+               return r;
+
+       return 0;
 }
 
 int kvm_cmd_stat(int argc, const char **argv, const char *prefix)
@@ -60,20 +73,17 @@ int kvm_cmd_stat(int argc, const char **argv, const char *prefix)
                return kvm__enumerate_instances(do_memstat);
 
        if (instance_name == NULL &&
-           instance_pid == 0)
+           instance == 0)
                kvm_stat_help();
 
        if (instance_name)
-               instance_pid = kvm__get_pid_by_instance(instance_name);
+               instance = kvm__get_sock_by_instance(instance_name);
 
-       if (instance_pid <= 0)
+       if (instance <= 0)
                die("Failed locating instance");
 
-       if (mem) {
-               printf("Sending memstat command to designated instance, output should be on the targets' terminal.\n");
-
-               return kill(instance_pid, SIGKVMMEMSTAT);
-       }
+       if (mem)
+               return do_memstat(instance_name, instance);
 
        return 0;
 }
index fd0500e9c2ede837e6253f8ed0c96354ff383f8d..26a9214edbd878b30e5575ac8edafe58a82da479 100644 (file)
@@ -3,17 +3,23 @@
 #include <kvm/builtin-stop.h>
 #include <kvm/kvm.h>
 #include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
 
 #include <stdio.h>
 #include <string.h>
 #include <signal.h>
 
+struct stop_cmd {
+       u32 type;
+       u32 len;
+};
+
 static bool all;
-static pid_t instance_pid;
+static int instance;
 static const char *instance_name;
 
 static const char * const stop_usage[] = {
-       "kvm stop [--all] [-n name] [-p pid]",
+       "kvm stop [--all] [-n name]",
        NULL
 };
 
@@ -21,7 +27,6 @@ static const struct option stop_options[] = {
        OPT_GROUP("General options:"),
        OPT_BOOLEAN('a', "all", &all, "Stop all instances"),
        OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
-       OPT_INTEGER('p', "pid", &instance_pid, "Instance pid"),
        OPT_END()
 };
 
@@ -40,9 +45,16 @@ void kvm_stop_help(void)
        usage_with_options(stop_usage, stop_options);
 }
 
-static int do_stop(const char *name, int pid)
+static int do_stop(const char *name, int sock)
 {
-       return kill(pid, SIGKVMSTOP);
+       struct stop_cmd cmd = {KVM_IPC_STOP, 0};
+       int r;
+
+       r = write(sock, &cmd, sizeof(cmd));
+       if (r < 0)
+               return r;
+
+       return 0;
 }
 
 int kvm_cmd_stop(int argc, const char **argv, const char *prefix)
@@ -53,14 +65,14 @@ int kvm_cmd_stop(int argc, const char **argv, const char *prefix)
                return kvm__enumerate_instances(do_stop);
 
        if (instance_name == NULL &&
-           instance_pid == 0)
+           instance == 0)
                kvm_stop_help();
 
        if (instance_name)
-               instance_pid = kvm__get_pid_by_instance(instance_name);
+               instance = kvm__get_sock_by_instance(instance_name);
 
-       if (instance_pid <= 0)
+       if (instance <= 0)
                die("Failed locating instance");
 
-       return kill(instance_pid, SIGKVMSTOP);
+       return do_stop(instance_name, instance);
 }
diff --git a/tools/kvm/include/kvm/kvm-ipc.h b/tools/kvm/include/kvm/kvm-ipc.h
new file mode 100644 (file)
index 0000000..c932052
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef KVM__IPC_H_
+#define KVM__IPC_H_
+
+#include <linux/types.h>
+
+struct kvm_ipc_msg {
+       u32 type;
+       u32 len;
+       u8 data[];
+};
+
+enum {
+       KVM_IPC_BALLOON = 1,
+       KVM_IPC_DEBUG   = 2,
+       KVM_IPC_STAT    = 3,
+       KVM_IPC_PAUSE   = 4,
+       KVM_IPC_RESUME  = 5,
+       KVM_IPC_STOP    = 6,
+       KVM_IPC_PID     = 7,
+};
+
+int kvm_ipc__register_handler(u32 type, void (*cb)(int fd, u32 type, u32 len, u8 *msg));
+int kvm_ipc__handle(int fd, struct kvm_ipc_msg *msg);
+int kvm_ipc__start(int sock);
+
+#endif
index eee99591e2968cd586b702c110a4a72277eb995a..2b3024a0d6214a344ec6ac25a39f81020818ad2a 100644 (file)
 
 #define SIGKVMEXIT             (SIGRTMIN + 0)
 #define SIGKVMPAUSE            (SIGRTMIN + 1)
-#define SIGKVMADDMEM           (SIGRTMIN + 2)
-#define SIGKVMDELMEM           (SIGRTMIN + 3)
 #define SIGKVMSTOP             (SIGRTMIN + 4)
 #define SIGKVMRESUME           (SIGRTMIN + 5)
-#define SIGKVMMEMSTAT          (SIGRTMIN + 6)
 
 #define KVM_PID_FILE_PATH      "/.kvm-tools/"
 #define HOME_DIR               getenv("HOME")
@@ -80,9 +77,9 @@ bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr);
 void kvm__pause(void);
 void kvm__continue(void);
 void kvm__notify_paused(void);
-pid_t kvm__get_pid_by_instance(const char *name);
+int kvm__get_sock_by_instance(const char *name);
 int kvm__enumerate_instances(int (*callback)(const char *name, int pid));
-void kvm__remove_pidfile(const char *name);
+void kvm__remove_socket(const char *name);
 
 /*
  * Debugging
diff --git a/tools/kvm/kvm-ipc.c b/tools/kvm/kvm-ipc.c
new file mode 100644 (file)
index 0000000..f05e926
--- /dev/null
@@ -0,0 +1,147 @@
+#include "kvm/kvm-ipc.h"
+#include "kvm/rwsem.h"
+#include "kvm/read-write.h"
+#include "kvm/util.h"
+
+#include <sys/epoll.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#define KVM_IPC_MAX_MSGS 16
+
+static void (*msgs[KVM_IPC_MAX_MSGS])(int fd, u32 type, u32 len, u8 *msg);
+static DECLARE_RWSEM(msgs_rwlock);
+static int epoll_fd, server_fd;
+
+int kvm_ipc__register_handler(u32 type, void (*cb)(int fd, u32 type, u32 len, u8 *msg))
+{
+       if (type >= KVM_IPC_MAX_MSGS)
+               return -ENOSPC;
+
+       down_write(&msgs_rwlock);
+       msgs[type] = cb;
+       up_write(&msgs_rwlock);
+
+       return 0;
+}
+
+int kvm_ipc__handle(int fd, struct kvm_ipc_msg *msg)
+{
+       void (*cb)(int fd, u32 type, u32 len, u8 *msg);
+
+       if (msg->type >= KVM_IPC_MAX_MSGS)
+               return -ENOSPC;
+
+       down_read(&msgs_rwlock);
+       cb = msgs[msg->type];
+       up_read(&msgs_rwlock);
+
+       if (cb == NULL) {
+               pr_warning("No device handles type %u\n", msg->type);
+               return -ENODEV;
+       }
+
+       cb(fd, msg->type, msg->len, msg->data);
+
+       return 0;
+}
+
+static int kvm_ipc__new_conn(int fd)
+{
+       int client;
+       struct epoll_event ev;
+
+       client = accept(fd, NULL, NULL);
+       if (client < 0)
+               return -1;
+
+       ev.events = EPOLLIN | EPOLLRDHUP;
+       ev.data.fd = client;
+       if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client, &ev) < 0) {
+               close(client);
+               return -1;
+       }
+
+       return client;
+}
+
+static void kvm_ipc__close_conn(int fd)
+{
+       epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
+       close(fd);
+}
+
+static void kvm_ipc__new_data(int fd)
+{
+       struct kvm_ipc_msg *msg;
+       u32 n;
+
+       msg = malloc(sizeof(*msg));
+       if (msg == NULL)
+               goto done;
+
+       n = read(fd, msg, sizeof(*msg));
+       if (n != sizeof(*msg))
+               goto done;
+
+       msg = realloc(msg, sizeof(*msg) + msg->len);
+       if (msg == NULL)
+               goto done;
+
+       n = read_in_full(fd, msg->data, msg->len);
+       if (n != msg->len)
+               goto done;
+
+       kvm_ipc__handle(fd, msg);
+
+done:
+       free(msg);
+}
+
+static void *kvm_ipc__thread(void *param)
+{
+       struct epoll_event event;
+
+       for (;;) {
+               int nfds;
+
+               nfds = epoll_wait(epoll_fd, &event, 1, -1);
+               if (nfds > 0) {
+                       int fd = event.data.fd;
+
+                       if (fd == server_fd) {
+                               int client;
+
+                               client = kvm_ipc__new_conn(fd);
+                               kvm_ipc__new_data(client);
+                       } else if (event.events && (EPOLLERR | EPOLLRDHUP | EPOLLHUP)) {
+                               kvm_ipc__close_conn(fd);
+                       } else {
+                               kvm_ipc__new_data(fd);
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+int kvm_ipc__start(int sock)
+{
+       pthread_t thread;
+       struct epoll_event ev;
+
+       server_fd = sock;
+
+       epoll_fd = epoll_create(KVM_IPC_MAX_MSGS);
+
+       ev.events = EPOLLIN | EPOLLOUT | EPOLLPRI;
+       ev.data.fd = sock;
+       if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev) < 0)
+               die("Failed starting IPC thread");
+
+       if (pthread_create(&thread, NULL, kvm_ipc__thread, NULL) != 0)
+               die("Failed starting IPC thread");
+
+       return 0;
+}
index 65feeb7327b298ad1a1c31c7e46e1378e6c2dfd8..40ae6a5cf5a91caa77797ae2e0e7593f168b5f4a 100644 (file)
@@ -8,11 +8,15 @@
 #include "kvm/util.h"
 #include "kvm/mutex.h"
 #include "kvm/kvm-cpu.h"
+#include "kvm/kvm-ipc.h"
 
 #include <linux/kvm.h>
 
 #include <asm/bootparam.h>
 
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
@@ -135,59 +139,73 @@ static struct kvm *kvm__new(void)
        return kvm;
 }
 
-static void kvm__create_pidfile(struct kvm *kvm)
+static int kvm__create_socket(struct kvm *kvm)
 {
-       int fd;
-       char full_name[PATH_MAX], pid[10];
+       char full_name[PATH_MAX];
+       unsigned int s;
+       struct sockaddr_un local;
+       int len, r;
 
        if (!kvm->name)
-               return;
+               return -1;
 
        sprintf(full_name, "%s", kvm__get_dir());
        mkdir(full_name, 0777);
-       sprintf(full_name, "%s/%s.pid", kvm__get_dir(), kvm->name);
-       fd = open(full_name, O_CREAT | O_WRONLY, 0666);
-       sprintf(pid, "%u\n", getpid());
-       if (write(fd, pid, strlen(pid)) <= 0)
-               die("Failed creating PID file");
-       close(fd);
+       sprintf(full_name, "%s/%s.sock", kvm__get_dir(), kvm->name);
+       s = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (s < 0)
+               return s;
+       local.sun_family = AF_UNIX;
+       strcpy(local.sun_path, full_name);
+       unlink(local.sun_path);
+       len = strlen(local.sun_path) + sizeof(local.sun_family);
+       r = bind(s, (struct sockaddr *)&local, len);
+       if (r < 0)
+               goto fail;
+
+       r = listen(s, 5);
+       if (r < 0)
+               goto fail;
+
+       return s;
+
+fail:
+       close(s);
+       return -1;
 }
 
-void kvm__remove_pidfile(const char *name)
+void kvm__remove_socket(const char *name)
 {
        char full_name[PATH_MAX];
 
-       sprintf(full_name, "%s/%s.pid", kvm__get_dir(), name);
+       sprintf(full_name, "%s/%s.sock", kvm__get_dir(), name);
        unlink(full_name);
 }
 
-pid_t kvm__get_pid_by_instance(const char *name)
+int kvm__get_sock_by_instance(const char *name)
 {
-       int fd;
-       pid_t pid;
-       char pid_str[10], pid_file[PATH_MAX];
+       int s, len, r;
+       char sock_file[PATH_MAX];
+       struct sockaddr_un local;
 
-       sprintf(pid_file, "%s/%s.pid", kvm__get_dir(), name);
-       fd = open(pid_file, O_RDONLY);
-       if (fd < 0)
-               return -1;
+       sprintf(sock_file, "%s/%s.sock", kvm__get_dir(), name);
+       s = socket(AF_UNIX, SOCK_STREAM, 0);
 
-       if (read(fd, pid_str, 10) == 0)
-               return -1;
-
-       pid = atoi(pid_str);
-       if (pid < 0)
-               return -1;
+       local.sun_family = AF_UNIX;
+       strcpy(local.sun_path, sock_file);
+       len = strlen(local.sun_path) + sizeof(local.sun_family);
 
-       close(fd);
+       r = connect(s, &local, len);
+       if (r < 0)
+               die("Failed connecting to instance");
 
-       return pid;
+       return s;
 }
 
-int kvm__enumerate_instances(int (*callback)(const char *name, int pid))
+int kvm__enumerate_instances(int (*callback)(const char *name, int fd))
 {
        char full_name[PATH_MAX];
-       int pid;
+       int sock;
        DIR *dir;
        struct dirent entry, *result;
        int ret = 0;
@@ -199,10 +217,11 @@ int kvm__enumerate_instances(int (*callback)(const char *name, int pid))
                readdir_r(dir, &entry, &result);
                if (result == NULL)
                        break;
-               if (entry.d_type == DT_REG) {
-                       entry.d_name[strlen(entry.d_name)-4] = 0;
-                       pid = kvm__get_pid_by_instance(entry.d_name);
-                       ret = callback(entry.d_name, pid);
+               if (entry.d_type == DT_SOCK) {
+                       entry.d_name[strlen(entry.d_name)-5] = 0;
+                       sock = kvm__get_sock_by_instance(entry.d_name);
+                       ret = callback(entry.d_name, sock);
+                       close(sock);
                        if (ret < 0)
                                break;
                }
@@ -218,7 +237,7 @@ void kvm__delete(struct kvm *kvm)
        kvm__stop_timer(kvm);
 
        munmap(kvm->ram_start, kvm->ram_size);
-       kvm__remove_pidfile(kvm->name);
+       kvm__remove_socket(kvm->name);
        free(kvm);
 }
 
@@ -338,6 +357,18 @@ int kvm__recommended_cpus(struct kvm *kvm)
        return ret;
 }
 
+static void kvm__pid(int fd, u32 type, u32 len, u8 *msg)
+{
+       pid_t pid = getpid();
+       int r = 0;
+
+       if (type == KVM_IPC_PID)
+               r = write(fd, &pid, sizeof(pid));
+
+       if (r < 0)
+               pr_warning("Failed sending PID");
+}
+
 /*
  * The following hack should be removed once 'x86: Raise the hard
  * VCPU count limit' makes it's way into the mainline.
@@ -424,8 +455,8 @@ struct kvm *kvm__init(const char *kvm_dev, u64 ram_size, const char *name)
 
        kvm->name = name;
 
-       kvm__create_pidfile(kvm);
-
+       kvm_ipc__start(kvm__create_socket(kvm));
+       kvm_ipc__register_handler(KVM_IPC_PID, kvm__pid);
        return kvm;
 }
 
index 1691b79fa07587fdcc7d56422ff47d2e2e055394..991610f99df8a7b592e26d1468c8604bbcceb820 100644 (file)
@@ -9,6 +9,7 @@
 #include "kvm/threadpool.h"
 #include "kvm/guest_compat.h"
 #include "kvm/virtio-pci.h"
+#include "kvm/kvm-ipc.h"
 
 #include <linux/virtio_ring.h>
 #include <linux/virtio_balloon.h>
@@ -139,12 +140,12 @@ static int virtio_bln__collect_stats(void)
        return 0;
 }
 
-static int virtio_bln__print_stats(void)
+static void virtio_bln__print_stats(int fd, u32 type, u32 len, u8 *msg)
 {
        u16 i;
 
        if (virtio_bln__collect_stats() < 0)
-               return -EFAULT;
+               return;
 
        printf("\n\n\t*** Guest memory statistics ***\n\n");
        for (i = 0; i < bdev.stat_count; i++) {
@@ -171,23 +172,19 @@ static int virtio_bln__print_stats(void)
                printf("%llu\n", bdev.stats[i].val);
        }
        printf("\n");
-
-       return 0;
 }
 
-static void handle_sigmem(int sig)
+static void handle_mem(int fd, u32 type, u32 len, u8 *msg)
 {
-       if (sig == SIGKVMADDMEM) {
-               bdev.config.num_pages += 256;
-       } else if (sig == SIGKVMDELMEM) {
-               if (bdev.config.num_pages < 256)
-                       return;
+       int mem = *(int *)msg;
 
-               bdev.config.num_pages -= 256;
-       } else if (sig == SIGKVMMEMSTAT) {
-               virtio_bln__print_stats();
+       if (mem > 0) {
+               bdev.config.num_pages += 256 * mem;
+       } else if (mem < 0) {
+               if (bdev.config.num_pages < (u32)(256 * (-mem)))
+                       return;
 
-               return;
+               bdev.config.num_pages += 256 * mem;
        }
 
        /* Notify that the configuration space has changed */
@@ -261,9 +258,8 @@ static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
 
 void virtio_bln__init(struct kvm *kvm)
 {
-       signal(SIGKVMADDMEM, handle_sigmem);
-       signal(SIGKVMDELMEM, handle_sigmem);
-       signal(SIGKVMMEMSTAT, handle_sigmem);
+       kvm_ipc__register_handler(KVM_IPC_BALLOON, handle_mem);
+       kvm_ipc__register_handler(KVM_IPC_STAT, virtio_bln__print_stats);
 
        bdev.stat_waitfd        = eventfd(0, 0);
        memset(&bdev.config, 0, sizeof(struct virtio_balloon_config));