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