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