From 96ce8e8d0c9e88fe8abd48576645c8d2e2da9af6 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Wed, 5 Sep 2012 10:31:56 +0200 Subject: [PATCH] kvm tools: kvm-ipc cleanup Move all the kvm-ipc specific code into the relevant file, and modify the ipc callback to pass a ptr to struct kvm as well. Signed-off-by: Sasha Levin Signed-off-by: Pekka Enberg --- tools/kvm/builtin-run.c | 122 ------------- tools/kvm/include/kvm/kvm-ipc.h | 8 +- tools/kvm/kvm-ipc.c | 299 ++++++++++++++++++++++++++++++-- tools/kvm/kvm.c | 147 ---------------- tools/kvm/virtio/balloon.c | 4 +- 5 files changed, 289 insertions(+), 291 deletions(-) diff --git a/tools/kvm/builtin-run.c b/tools/kvm/builtin-run.c index 903f5233d8f6..3d89b75d46ec 100644 --- a/tools/kvm/builtin-run.c +++ b/tools/kvm/builtin-run.c @@ -218,127 +218,11 @@ static int virtio_9p_rootdir_parser(const struct option *opt, const char *arg, i OPT_END() \ }; -/* - * Serialize debug printout so that the output of multiple vcpus does not - * get mixed up: - */ -static int printout_done; - -static void handle_sigusr1(int sig) -{ - struct kvm_cpu *cpu = current_kvm_cpu; - int fd = kvm_cpu__get_debug_fd(); - - if (!cpu || cpu->needs_nmi) - return; - - dprintf(fd, "\n #\n # vCPU #%ld's dump:\n #\n", cpu->cpu_id); - kvm_cpu__show_registers(cpu); - kvm_cpu__show_code(cpu); - kvm_cpu__show_page_tables(cpu); - fflush(stdout); - printout_done = 1; - mb(); -} - -/* Pause/resume the guest using SIGUSR2 */ -static int is_paused; - -static void handle_pause(int fd, u32 type, u32 len, u8 *msg) -{ - if (WARN_ON(len)) - return; - - if (type == KVM_IPC_RESUME && is_paused) { - kvm->vm_state = KVM_VMSTATE_RUNNING; - kvm__continue(); - } else if (type == KVM_IPC_PAUSE && !is_paused) { - kvm->vm_state = KVM_VMSTATE_PAUSED; - ioctl(kvm->vm_fd, KVM_KVMCLOCK_CTRL); - kvm__pause(); - } else { - return; - } - - is_paused = !is_paused; -} - -static void handle_vmstate(int fd, u32 type, u32 len, u8 *msg) -{ - int r = 0; - - if (type == KVM_IPC_VMSTATE) - r = write(fd, &kvm->vm_state, sizeof(kvm->vm_state)); - - if (r < 0) - pr_warning("Failed sending VMSTATE"); -} - -static void handle_debug(int fd, u32 type, u32 len, u8 *msg) -{ - int i; - struct debug_cmd_params *params; - u32 dbg_type; - u32 vcpu; - - if (WARN_ON(type != KVM_IPC_DEBUG || len != sizeof(*params))) - return; - - params = (void *)msg; - dbg_type = params->dbg_type; - vcpu = params->cpu; - - if (dbg_type & KVM_DEBUG_CMD_TYPE_SYSRQ) - serial8250__inject_sysrq(kvm, params->sysrq); - - if (dbg_type & KVM_DEBUG_CMD_TYPE_NMI) { - if ((int)vcpu >= kvm->nrcpus) - return; - - kvm->cpus[vcpu]->needs_nmi = 1; - pthread_kill(kvm->cpus[vcpu]->thread, SIGUSR1); - } - - if (!(dbg_type & KVM_DEBUG_CMD_TYPE_DUMP)) - return; - - for (i = 0; i < kvm->nrcpus; i++) { - struct kvm_cpu *cpu = kvm->cpus[i]; - - if (!cpu) - continue; - - printout_done = 0; - - kvm_cpu__set_debug_fd(fd); - pthread_kill(cpu->thread, SIGUSR1); - /* - * Wait for the vCPU to dump state before signalling - * the next thread. Since this is debug code it does - * not matter that we are burning CPU time a bit: - */ - while (!printout_done) - mb(); - } - - close(fd); - - serial8250__inject_sysrq(kvm, 'p'); -} - static void handle_sigalrm(int sig) { kvm__arch_periodic_poll(kvm); } -static void handle_stop(int fd, u32 type, u32 len, u8 *msg) -{ - if (WARN_ON(type != KVM_IPC_STOP || len)) - return; - - kvm_cpu__reboot(kvm); -} - static void *kvm_cpu_thread(void *arg) { current_kvm_cpu = arg; @@ -655,12 +539,6 @@ static int kvm_cmd_run_init(int argc, const char **argv) return PTR_ERR(kvm); signal(SIGALRM, handle_sigalrm); - kvm_ipc__register_handler(KVM_IPC_DEBUG, handle_debug); - signal(SIGUSR1, handle_sigusr1); - 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); - kvm_ipc__register_handler(KVM_IPC_VMSTATE, handle_vmstate); nr_online_cpus = sysconf(_SC_NPROCESSORS_ONLN); kvm->cfg.custom_rootfs_name = "default"; diff --git a/tools/kvm/include/kvm/kvm-ipc.h b/tools/kvm/include/kvm/kvm-ipc.h index aefffa4dd444..5494da4c52a7 100644 --- a/tools/kvm/include/kvm/kvm-ipc.h +++ b/tools/kvm/include/kvm/kvm-ipc.h @@ -2,6 +2,7 @@ #define KVM__IPC_H_ #include +#include "kvm/kvm.h" enum { KVM_IPC_BALLOON = 1, @@ -14,9 +15,10 @@ enum { KVM_IPC_VMSTATE = 8, }; -int kvm_ipc__register_handler(u32 type, void (*cb)(int fd, u32 type, u32 len, u8 *msg)); -int kvm_ipc__start(int sock); -int kvm_ipc__stop(void); +int kvm_ipc__register_handler(u32 type, void (*cb)(struct kvm *kvm, + int fd, u32 type, u32 len, u8 *msg)); +int kvm_ipc__init(struct kvm *kvm); +int kvm_ipc__exit(struct kvm *kvm); int kvm_ipc__send(int fd, u32 type); int kvm_ipc__send_msg(int fd, u32 type, u32 len, u8 *msg); diff --git a/tools/kvm/kvm-ipc.c b/tools/kvm/kvm-ipc.c index 70831b835976..70273c211a11 100644 --- a/tools/kvm/kvm-ipc.c +++ b/tools/kvm/kvm-ipc.c @@ -1,13 +1,19 @@ -#include "kvm/kvm-ipc.h" -#include "kvm/rwsem.h" -#include "kvm/read-write.h" -#include "kvm/util.h" - #include #include #include #include #include +#include + +#include "kvm/kvm-ipc.h" +#include "kvm/rwsem.h" +#include "kvm/read-write.h" +#include "kvm/util.h" +#include "kvm/kvm.h" +#include "kvm/builtin-debug.h" +#include "kvm/strbuf.h" +#include "kvm/kvm-cpu.h" +#include "kvm/8250-serial.h" struct kvm_ipc_head { u32 type; @@ -16,12 +22,132 @@ struct kvm_ipc_head { #define KVM_IPC_MAX_MSGS 16 -static void (*msgs[KVM_IPC_MAX_MSGS])(int fd, u32 type, u32 len, u8 *msg); +#define KVM_SOCK_SUFFIX ".sock" +#define KVM_SOCK_SUFFIX_LEN ((ssize_t)sizeof(KVM_SOCK_SUFFIX) - 1) + +extern __thread struct kvm_cpu *current_kvm_cpu; +static void (*msgs[KVM_IPC_MAX_MSGS])(struct kvm *kvm, int fd, u32 type, u32 len, u8 *msg); static DECLARE_RWSEM(msgs_rwlock); static int epoll_fd, server_fd, stop_fd; static pthread_t thread; -int kvm_ipc__register_handler(u32 type, void (*cb)(int fd, u32 type, u32 len, u8 *msg)) +static int kvm__create_socket(struct kvm *kvm) +{ + char full_name[PATH_MAX]; + unsigned int s; + struct sockaddr_un local; + int len, r; + + /* This usually 108 bytes long */ + BUILD_BUG_ON(sizeof(local.sun_path) < 32); + + snprintf(full_name, sizeof(full_name), "%s/%s%s", + kvm__get_dir(), kvm->cfg.guest_name, KVM_SOCK_SUFFIX); + if (access(full_name, F_OK) == 0) { + pr_err("Socket file %s already exist", full_name); + return -EEXIST; + } + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) + return s; + local.sun_family = AF_UNIX; + strlcpy(local.sun_path, full_name, sizeof(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 r; +} + +void kvm__remove_socket(const char *name) +{ + char full_name[PATH_MAX]; + + snprintf(full_name, sizeof(full_name), "%s/%s%s", + kvm__get_dir(), name, KVM_SOCK_SUFFIX); + unlink(full_name); +} + +int kvm__get_sock_by_instance(const char *name) +{ + int s, len, r; + char sock_file[PATH_MAX]; + struct sockaddr_un local; + + snprintf(sock_file, sizeof(sock_file), "%s/%s%s", + kvm__get_dir(), name, KVM_SOCK_SUFFIX); + s = socket(AF_UNIX, SOCK_STREAM, 0); + + local.sun_family = AF_UNIX; + strlcpy(local.sun_path, sock_file, sizeof(local.sun_path)); + len = strlen(local.sun_path) + sizeof(local.sun_family); + + r = connect(s, &local, len); + if (r < 0 && errno == ECONNREFUSED) { + /* Tell the user clean ghost socket file */ + pr_err("\"%s\" could be a ghost socket file, please remove it", + sock_file); + return r; + } else if (r < 0) { + return r; + } + + return s; +} + +int kvm__enumerate_instances(int (*callback)(const char *name, int fd)) +{ + int sock; + DIR *dir; + struct dirent entry, *result; + int ret = 0; + + dir = opendir(kvm__get_dir()); + if (!dir) + return -errno; + + for (;;) { + readdir_r(dir, &entry, &result); + if (result == NULL) + break; + if (entry.d_type == DT_SOCK) { + ssize_t name_len = strlen(entry.d_name); + char *p; + + if (name_len <= KVM_SOCK_SUFFIX_LEN) + continue; + + p = &entry.d_name[name_len - KVM_SOCK_SUFFIX_LEN]; + if (memcmp(KVM_SOCK_SUFFIX, p, KVM_SOCK_SUFFIX_LEN)) + continue; + + *p = 0; + sock = kvm__get_sock_by_instance(entry.d_name); + if (sock < 0) + continue; + ret = callback(entry.d_name, sock); + close(sock); + if (ret < 0) + break; + } + } + + closedir(dir); + + return ret; +} + +int kvm_ipc__register_handler(u32 type, void (*cb)(struct kvm *kvm, int fd, u32 type, u32 len, u8 *msg)) { if (type >= KVM_IPC_MAX_MSGS) return -ENOSPC; @@ -56,9 +182,9 @@ int kvm_ipc__send_msg(int fd, u32 type, u32 len, u8 *msg) return 0; } -static int kvm_ipc__handle(int fd, u32 type, u32 len, u8 *data) +static int kvm_ipc__handle(struct kvm *kvm, int fd, u32 type, u32 len, u8 *data) { - void (*cb)(int fd, u32 type, u32 len, u8 *msg); + void (*cb)(struct kvm *kvm, int fd, u32 type, u32 len, u8 *msg); if (type >= KVM_IPC_MAX_MSGS) return -ENOSPC; @@ -72,7 +198,7 @@ static int kvm_ipc__handle(int fd, u32 type, u32 len, u8 *data) return -ENODEV; } - cb(fd, type, len, data); + cb(kvm, fd, type, len, data); return 0; } @@ -102,7 +228,7 @@ static void kvm_ipc__close_conn(int fd) close(fd); } -static int kvm_ipc__receive(int fd) +static int kvm_ipc__receive(struct kvm *kvm, int fd) { struct kvm_ipc_head head; u8 *msg = NULL; @@ -120,7 +246,7 @@ static int kvm_ipc__receive(int fd) if (n != head.len) goto done; - kvm_ipc__handle(fd, head.type, head.len, msg); + kvm_ipc__handle(kvm, fd, head.type, head.len, msg); return 0; @@ -132,6 +258,7 @@ done: static void *kvm_ipc__thread(void *param) { struct epoll_event event; + struct kvm *kvm = param; for (;;) { int nfds; @@ -150,13 +277,13 @@ static void *kvm_ipc__thread(void *param) * Handle multiple IPC cmd at a time */ do { - r = kvm_ipc__receive(client); + r = kvm_ipc__receive(kvm, client); } while (r == 0); } else if (event.events & (EPOLLERR | EPOLLRDHUP | EPOLLHUP)) { kvm_ipc__close_conn(fd); } else { - kvm_ipc__receive(fd); + kvm_ipc__receive(kvm, fd); } } } @@ -164,9 +291,137 @@ static void *kvm_ipc__thread(void *param) return NULL; } -int kvm_ipc__start(int sock) +static void kvm__pid(struct kvm *kvm, 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"); +} + +static void handle_stop(struct kvm *kvm, int fd, u32 type, u32 len, u8 *msg) +{ + if (WARN_ON(type != KVM_IPC_STOP || len)) + return; + + kvm_cpu__reboot(kvm); +} + +/* Pause/resume the guest using SIGUSR2 */ +static int is_paused; + +static void handle_pause(struct kvm *kvm, int fd, u32 type, u32 len, u8 *msg) +{ + if (WARN_ON(len)) + return; + + if (type == KVM_IPC_RESUME && is_paused) { + kvm->vm_state = KVM_VMSTATE_RUNNING; + kvm__continue(); + } else if (type == KVM_IPC_PAUSE && !is_paused) { + kvm->vm_state = KVM_VMSTATE_PAUSED; + ioctl(kvm->vm_fd, KVM_KVMCLOCK_CTRL); + kvm__pause(); + } else { + return; + } + + is_paused = !is_paused; +} + +static void handle_vmstate(struct kvm *kvm, int fd, u32 type, u32 len, u8 *msg) +{ + int r = 0; + + if (type == KVM_IPC_VMSTATE) + r = write(fd, &kvm->vm_state, sizeof(kvm->vm_state)); + + if (r < 0) + pr_warning("Failed sending VMSTATE"); +} + +/* + * Serialize debug printout so that the output of multiple vcpus does not + * get mixed up: + */ +static int printout_done; + +static void handle_sigusr1(int sig) +{ + struct kvm_cpu *cpu = current_kvm_cpu; + int fd = kvm_cpu__get_debug_fd(); + + if (!cpu || cpu->needs_nmi) + return; + + dprintf(fd, "\n #\n # vCPU #%ld's dump:\n #\n", cpu->cpu_id); + kvm_cpu__show_registers(cpu); + kvm_cpu__show_code(cpu); + kvm_cpu__show_page_tables(cpu); + fflush(stdout); + printout_done = 1; +} + +static void handle_debug(struct kvm *kvm, int fd, u32 type, u32 len, u8 *msg) +{ + int i; + struct debug_cmd_params *params; + u32 dbg_type; + u32 vcpu; + + if (WARN_ON(type != KVM_IPC_DEBUG || len != sizeof(*params))) + return; + + params = (void *)msg; + dbg_type = params->dbg_type; + vcpu = params->cpu; + + if (dbg_type & KVM_DEBUG_CMD_TYPE_SYSRQ) + serial8250__inject_sysrq(kvm, params->sysrq); + + if (dbg_type & KVM_DEBUG_CMD_TYPE_NMI) { + if ((int)vcpu >= kvm->nrcpus) + return; + + kvm->cpus[vcpu]->needs_nmi = 1; + pthread_kill(kvm->cpus[vcpu]->thread, SIGUSR1); + } + + if (!(dbg_type & KVM_DEBUG_CMD_TYPE_DUMP)) + return; + + for (i = 0; i < kvm->nrcpus; i++) { + struct kvm_cpu *cpu = kvm->cpus[i]; + + if (!cpu) + continue; + + printout_done = 0; + + kvm_cpu__set_debug_fd(fd); + pthread_kill(cpu->thread, SIGUSR1); + /* + * Wait for the vCPU to dump state before signalling + * the next thread. Since this is debug code it does + * not matter that we are burning CPU time a bit: + */ + while (!printout_done) + sleep(0); + } + + close(fd); + + serial8250__inject_sysrq(kvm, 'p'); +} + +int kvm_ipc__init(struct kvm *kvm) { int ret; + int sock = kvm__create_socket(kvm); struct epoll_event ev = {0}; server_fd = sock; @@ -199,12 +454,20 @@ int kvm_ipc__start(int sock) goto err_stop; } - if (pthread_create(&thread, NULL, kvm_ipc__thread, NULL) != 0) { + if (pthread_create(&thread, NULL, kvm_ipc__thread, kvm) != 0) { pr_err("Failed starting IPC thread"); ret = -EFAULT; goto err_stop; } + kvm_ipc__register_handler(KVM_IPC_PID, kvm__pid); + kvm_ipc__register_handler(KVM_IPC_DEBUG, handle_debug); + 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); + kvm_ipc__register_handler(KVM_IPC_VMSTATE, handle_vmstate); + signal(SIGUSR1, handle_sigusr1); + return 0; err_stop: @@ -215,7 +478,7 @@ err: return ret; } -int kvm_ipc__stop(void) +int kvm_ipc__exit(struct kvm *kvm) { u64 val = 1; int ret; @@ -227,5 +490,7 @@ int kvm_ipc__stop(void) close(server_fd); close(epoll_fd); + kvm__remove_socket(kvm->cfg.guest_name); + return ret; } diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c index 42a0f06f41a9..b950c0854df7 100644 --- a/tools/kvm/kvm.c +++ b/tools/kvm/kvm.c @@ -133,130 +133,9 @@ struct kvm *kvm__new(void) return kvm; } -#define KVM_SOCK_SUFFIX ".sock" -#define KVM_SOCK_SUFFIX_LEN ((ssize_t)sizeof(KVM_SOCK_SUFFIX) - 1) - -static int kvm__create_socket(struct kvm *kvm) -{ - char full_name[PATH_MAX]; - unsigned int s; - struct sockaddr_un local; - int len, r; - - /* This usually 108 bytes long */ - BUILD_BUG_ON(sizeof(local.sun_path) < 32); - - snprintf(full_name, sizeof(full_name), "%s/%s%s", - kvm__get_dir(), kvm->cfg.guest_name, KVM_SOCK_SUFFIX); - if (access(full_name, F_OK) == 0) { - pr_err("Socket file %s already exist", full_name); - return -EEXIST; - } - - s = socket(AF_UNIX, SOCK_STREAM, 0); - if (s < 0) - return s; - local.sun_family = AF_UNIX; - strlcpy(local.sun_path, full_name, sizeof(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 r; -} - -void kvm__remove_socket(const char *name) -{ - char full_name[PATH_MAX]; - - snprintf(full_name, sizeof(full_name), "%s/%s%s", - kvm__get_dir(), name, KVM_SOCK_SUFFIX); - unlink(full_name); -} - -int kvm__get_sock_by_instance(const char *name) -{ - int s, len, r; - char sock_file[PATH_MAX]; - struct sockaddr_un local; - - snprintf(sock_file, sizeof(sock_file), "%s/%s%s", - kvm__get_dir(), name, KVM_SOCK_SUFFIX); - s = socket(AF_UNIX, SOCK_STREAM, 0); - - local.sun_family = AF_UNIX; - strlcpy(local.sun_path, sock_file, sizeof(local.sun_path)); - len = strlen(local.sun_path) + sizeof(local.sun_family); - - r = connect(s, &local, len); - if (r < 0 && errno == ECONNREFUSED) { - /* Tell the user clean ghost socket file */ - pr_err("\"%s\" could be a ghost socket file, please remove it", - sock_file); - return r; - } else if (r < 0) { - return r; - } - - return s; -} - -int kvm__enumerate_instances(int (*callback)(const char *name, int fd)) -{ - int sock; - DIR *dir; - struct dirent entry, *result; - int ret = 0; - - dir = opendir(kvm__get_dir()); - if (!dir) - return -errno; - - for (;;) { - readdir_r(dir, &entry, &result); - if (result == NULL) - break; - if (entry.d_type == DT_SOCK) { - ssize_t name_len = strlen(entry.d_name); - char *p; - - if (name_len <= KVM_SOCK_SUFFIX_LEN) - continue; - - p = &entry.d_name[name_len - KVM_SOCK_SUFFIX_LEN]; - if (memcmp(KVM_SOCK_SUFFIX, p, KVM_SOCK_SUFFIX_LEN)) - continue; - - *p = 0; - sock = kvm__get_sock_by_instance(entry.d_name); - if (sock < 0) - continue; - ret = callback(entry.d_name, sock); - close(sock); - if (ret < 0) - break; - } - } - - closedir(dir); - - return ret; -} - int kvm__exit(struct kvm *kvm) { kvm__arch_delete_ram(kvm); - kvm_ipc__stop(); - kvm__remove_socket(kvm->cfg.guest_name); free(kvm); return 0; @@ -301,18 +180,6 @@ 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. @@ -379,22 +246,8 @@ int kvm__init(struct kvm *kvm) kvm__arch_init(kvm, kvm->cfg.hugetlbfs_path, kvm->cfg.ram_size); - ret = kvm_ipc__start(kvm__create_socket(kvm)); - if (ret < 0) { - pr_err("Starting ipc failed."); - goto err_vm_fd; - } - - ret = kvm_ipc__register_handler(KVM_IPC_PID, kvm__pid); - if (ret < 0) { - pr_err("Register ipc handler failed."); - goto err_ipc; - } - return 0; -err_ipc: - kvm_ipc__stop(); err_vm_fd: close(kvm->vm_fd); err_sys_fd: diff --git a/tools/kvm/virtio/balloon.c b/tools/kvm/virtio/balloon.c index 07852d7c2142..b8192b5122cc 100644 --- a/tools/kvm/virtio/balloon.c +++ b/tools/kvm/virtio/balloon.c @@ -139,7 +139,7 @@ static int virtio_bln__collect_stats(void) return 0; } -static void virtio_bln__print_stats(int fd, u32 type, u32 len, u8 *msg) +static void virtio_bln__print_stats(struct kvm *kvm, int fd, u32 type, u32 len, u8 *msg) { int r; @@ -154,7 +154,7 @@ static void virtio_bln__print_stats(int fd, u32 type, u32 len, u8 *msg) pr_warning("Failed sending memory stats"); } -static void handle_mem(int fd, u32 type, u32 len, u8 *msg) +static void handle_mem(struct kvm *kvm, int fd, u32 type, u32 len, u8 *msg) { int mem; -- 2.39.5