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@xxxxxxxxx> --- tools/kvm/Makefile | 1 + tools/kvm/builtin-balloon.c | 35 +++++++--- tools/kvm/builtin-debug.c | 30 ++++++--- tools/kvm/builtin-list.c | 28 +++++++- tools/kvm/builtin-pause.c | 30 ++++++--- tools/kvm/builtin-resume.c | 30 ++++++--- tools/kvm/builtin-run.c | 22 +++--- tools/kvm/builtin-stat.c | 36 ++++++---- tools/kvm/builtin-stop.c | 30 ++++++--- tools/kvm/include/kvm/kvm-ipc.h | 26 +++++++ tools/kvm/include/kvm/kvm.h | 7 +-- tools/kvm/kvm-ipc.c | 147 +++++++++++++++++++++++++++++++++++++++ tools/kvm/kvm.c | 106 ++++++++++++++++++---------- tools/kvm/virtio/balloon.c | 30 ++++----- 14 files changed, 426 insertions(+), 132 deletions(-) create mode 100644 tools/kvm/include/kvm/kvm-ipc.h create mode 100644 tools/kvm/kvm-ipc.c diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile index 3939c11..5593417 100644 --- a/tools/kvm/Makefile +++ b/tools/kvm/Makefile @@ -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)) diff --git a/tools/kvm/builtin-balloon.c b/tools/kvm/builtin-balloon.c index 7329063..4a42ee8 100644 --- a/tools/kvm/builtin-balloon.c +++ b/tools/kvm/builtin-balloon.c @@ -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; } diff --git a/tools/kvm/builtin-debug.c b/tools/kvm/builtin-debug.c index 4be12cc..f744a7e 100644 --- a/tools/kvm/builtin-debug.c +++ b/tools/kvm/builtin-debug.c @@ -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); } diff --git a/tools/kvm/builtin-list.c b/tools/kvm/builtin-list.c index 3e116d6..529e251 100644 --- a/tools/kvm/builtin-list.c +++ b/tools/kvm/builtin-list.c @@ -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> @@ -12,6 +13,11 @@ #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; } diff --git a/tools/kvm/builtin-pause.c b/tools/kvm/builtin-pause.c index 7b644ff..d16da28 100644 --- a/tools/kvm/builtin-pause.c +++ b/tools/kvm/builtin-pause.c @@ -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); } diff --git a/tools/kvm/builtin-resume.c b/tools/kvm/builtin-resume.c index 70de0fc..1e76c47 100644 --- a/tools/kvm/builtin-resume.c +++ b/tools/kvm/builtin-resume.c @@ -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); } diff --git a/tools/kvm/builtin-run.c b/tools/kvm/builtin-run.c index a88503f..bc4f07b 100644 --- a/tools/kvm/builtin-run.c +++ b/tools/kvm/builtin-run.c @@ -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); diff --git a/tools/kvm/builtin-stat.c b/tools/kvm/builtin-stat.c index be12d15..609a6e5 100644 --- a/tools/kvm/builtin-stat.c +++ b/tools/kvm/builtin-stat.c @@ -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; } diff --git a/tools/kvm/builtin-stop.c b/tools/kvm/builtin-stop.c index fd0500e..26a9214 100644 --- a/tools/kvm/builtin-stop.c +++ b/tools/kvm/builtin-stop.c @@ -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 index 0000000..c932052 --- /dev/null +++ b/tools/kvm/include/kvm/kvm-ipc.h @@ -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 diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h index 79fa97d..a4c60d6 100644 --- a/tools/kvm/include/kvm/kvm.h +++ b/tools/kvm/include/kvm/kvm.h @@ -19,11 +19,8 @@ #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") @@ -77,9 +74,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 index 0000000..f05e926 --- /dev/null +++ b/tools/kvm/kvm-ipc.c @@ -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; +} diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c index 199c9b9..ef89bc8 100644 --- a/tools/kvm/kvm.c +++ b/tools/kvm/kvm.c @@ -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> @@ -114,59 +118,74 @@ 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/%s", HOME_DIR, KVM_PID_FILE_PATH); mkdir(full_name, 0777); - sprintf(full_name, "%s/%s/%s.pid", HOME_DIR, KVM_PID_FILE_PATH, 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/%s.sock", HOME_DIR, KVM_PID_FILE_PATH, 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/%s.pid", HOME_DIR, KVM_PID_FILE_PATH, name); + sprintf(full_name, "%s/%s/%s.sock", HOME_DIR, KVM_PID_FILE_PATH, 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/%s.pid", HOME_DIR, KVM_PID_FILE_PATH, name); - fd = open(pid_file, O_RDONLY); - if (fd < 0) - return -1; + sprintf(sock_file, "%s/%s/%s.sock", HOME_DIR, KVM_PID_FILE_PATH, name); + s = socket(AF_UNIX, SOCK_STREAM, 0); - if (read(fd, pid_str, 10) == 0) - return -1; + local.sun_family = AF_UNIX; + strcpy(local.sun_path, sock_file); + len = strlen(local.sun_path) + sizeof(local.sun_family); - pid = atoi(pid_str); - if (pid < 0) - return -1; - - 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; @@ -178,10 +197,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; } @@ -197,7 +217,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); } @@ -317,6 +337,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. @@ -403,8 +435,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; } diff --git a/tools/kvm/virtio/balloon.c b/tools/kvm/virtio/balloon.c index 1691b79..991610f 100644 --- a/tools/kvm/virtio/balloon.c +++ b/tools/kvm/virtio/balloon.c @@ -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)); -- 1.7.7 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html