1 #include "kvm/kvm-ipc.h" 2 #include "kvm/rwsem.h" 3 #include "kvm/read-write.h" 4 #include "kvm/util.h" 5 6 #include <sys/epoll.h> 7 #include <sys/un.h> 8 #include <sys/types.h> 9 #include <sys/socket.h> 10 #include <sys/eventfd.h> 11 12 #define KVM_IPC_MAX_MSGS 16 13 14 static void (*msgs[KVM_IPC_MAX_MSGS])(int fd, u32 type, u32 len, u8 *msg); 15 static DECLARE_RWSEM(msgs_rwlock); 16 static int epoll_fd, server_fd, stop_fd; 17 static pthread_t thread; 18 19 int kvm_ipc__register_handler(u32 type, void (*cb)(int fd, u32 type, u32 len, u8 *msg)) 20 { 21 if (type >= KVM_IPC_MAX_MSGS) 22 return -ENOSPC; 23 24 down_write(&msgs_rwlock); 25 msgs[type] = cb; 26 up_write(&msgs_rwlock); 27 28 return 0; 29 } 30 31 int kvm_ipc__handle(int fd, struct kvm_ipc_msg *msg) 32 { 33 void (*cb)(int fd, u32 type, u32 len, u8 *msg); 34 35 if (msg->type >= KVM_IPC_MAX_MSGS) 36 return -ENOSPC; 37 38 down_read(&msgs_rwlock); 39 cb = msgs[msg->type]; 40 up_read(&msgs_rwlock); 41 42 if (cb == NULL) { 43 pr_warning("No device handles type %u\n", msg->type); 44 return -ENODEV; 45 } 46 47 cb(fd, msg->type, msg->len, msg->data); 48 49 return 0; 50 } 51 52 static int kvm_ipc__new_conn(int fd) 53 { 54 int client; 55 struct epoll_event ev; 56 57 client = accept(fd, NULL, NULL); 58 if (client < 0) 59 return -1; 60 61 ev.events = EPOLLIN | EPOLLRDHUP; 62 ev.data.fd = client; 63 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client, &ev) < 0) { 64 close(client); 65 return -1; 66 } 67 68 return client; 69 } 70 71 static void kvm_ipc__close_conn(int fd) 72 { 73 epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL); 74 close(fd); 75 } 76 77 static void kvm_ipc__new_data(int fd) 78 { 79 struct kvm_ipc_msg *msg; 80 u32 n; 81 82 msg = malloc(sizeof(*msg)); 83 if (msg == NULL) 84 goto done; 85 86 n = read(fd, msg, sizeof(*msg)); 87 if (n != sizeof(*msg)) 88 goto done; 89 90 msg = realloc(msg, sizeof(*msg) + msg->len); 91 if (msg == NULL) 92 goto done; 93 94 n = read_in_full(fd, msg->data, msg->len); 95 if (n != msg->len) 96 goto done; 97 98 kvm_ipc__handle(fd, msg); 99 100 done: 101 free(msg); 102 } 103 104 static void *kvm_ipc__thread(void *param) 105 { 106 struct epoll_event event; 107 108 for (;;) { 109 int nfds; 110 111 nfds = epoll_wait(epoll_fd, &event, 1, -1); 112 if (nfds > 0) { 113 int fd = event.data.fd; 114 115 if (fd == stop_fd && event.events & EPOLLIN) { 116 break; 117 } else if (fd == server_fd) { 118 int client; 119 120 client = kvm_ipc__new_conn(fd); 121 kvm_ipc__new_data(client); 122 } else if (event.events && (EPOLLERR | EPOLLRDHUP | EPOLLHUP)) { 123 kvm_ipc__close_conn(fd); 124 } else { 125 kvm_ipc__new_data(fd); 126 } 127 } 128 } 129 130 return NULL; 131 } 132 133 int kvm_ipc__start(int sock) 134 { 135 struct epoll_event ev = {0}; 136 137 server_fd = sock; 138 139 epoll_fd = epoll_create(KVM_IPC_MAX_MSGS); 140 141 ev.events = EPOLLIN | EPOLLET; 142 ev.data.fd = sock; 143 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev) < 0) 144 die("Failed starting IPC thread"); 145 146 stop_fd = eventfd(0, 0); 147 ev.events = EPOLLIN | EPOLLET; 148 ev.data.fd = stop_fd; 149 if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, stop_fd, &ev) < 0) 150 die("Failed adding stop event to epoll"); 151 152 if (pthread_create(&thread, NULL, kvm_ipc__thread, NULL) != 0) 153 die("Failed starting IPC thread"); 154 155 return 0; 156 } 157 158 int kvm_ipc__stop(void) 159 { 160 u64 val = 1; 161 int ret; 162 163 ret = write(stop_fd, &val, sizeof(val)); 164 if (ret < 0) 165 return ret; 166 167 close(server_fd); 168 close(epoll_fd); 169 170 return ret; 171 } 172