From: Sasha Levin Date: Sun, 18 Dec 2011 17:49:41 +0000 (+0200) Subject: kvm tools: Fixes for ioeventfd module X-Git-Tag: next-20120402~5^2~44 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=d3923126a24212f1e746a84a575dadbd9f259418;p=karo-tx-linux.git kvm tools: Fixes for ioeventfd module Fixes include: - Error handling - Cleanup - Standard init/uninit Signed-off-by: Sasha Levin --- diff --git a/tools/kvm/builtin-run.c b/tools/kvm/builtin-run.c index 99e81b27728c..73ca754f1968 100644 --- a/tools/kvm/builtin-run.c +++ b/tools/kvm/builtin-run.c @@ -1000,7 +1000,11 @@ static int kvm_cmd_run_init(int argc, const char **argv) kvm->single_step = single_step; - ioeventfd__init(kvm); + r = ioeventfd__init(kvm); + if (r < 0) { + pr_err("ioeventfd__init() failed with error %d\n", r); + goto fail; + } max_cpus = kvm__max_cpus(kvm); recommended_cpus = kvm__recommended_cpus(kvm); @@ -1201,8 +1205,6 @@ static int kvm_cmd_run_init(int argc, const char **argv) } thread_pool__init(nr_online_cpus); - ioeventfd__start(); - fail: return r; } @@ -1263,6 +1265,10 @@ static void kvm_cmd_run_exit(int guest_ret) if (r < 0) pr_warning("ioport__exit() failed with error %d\n", r); + r = ioeventfd__exit(kvm); + if (r < 0) + pr_warning("ioeventfd__exit() failed with error %d\n", r); + kvm__delete(kvm); if (guest_ret == 0) diff --git a/tools/kvm/include/kvm/ioeventfd.h b/tools/kvm/include/kvm/ioeventfd.h index 3a95788a515b..ec70aa547a5a 100644 --- a/tools/kvm/include/kvm/ioeventfd.h +++ b/tools/kvm/include/kvm/ioeventfd.h @@ -19,9 +19,9 @@ struct ioevent { struct list_head list; }; -void ioeventfd__init(struct kvm *kvm); -void ioeventfd__start(void); -void ioeventfd__add_event(struct ioevent *ioevent); -void ioeventfd__del_event(u64 addr, u64 datamatch); +int ioeventfd__init(struct kvm *kvm); +int ioeventfd__exit(struct kvm *kvm); +int ioeventfd__add_event(struct ioevent *ioevent); +int ioeventfd__del_event(u64 addr, u64 datamatch); #endif diff --git a/tools/kvm/ioeventfd.c b/tools/kvm/ioeventfd.c index 1d6a7accb0d2..9133101ebb02 100644 --- a/tools/kvm/ioeventfd.c +++ b/tools/kvm/ioeventfd.c @@ -16,34 +16,117 @@ #define IOEVENTFD_MAX_EVENTS 20 static struct epoll_event events[IOEVENTFD_MAX_EVENTS]; -static int epoll_fd; +static int epoll_fd, epoll_stop_fd; static LIST_HEAD(used_ioevents); static bool ioeventfd_avail; -void ioeventfd__init(struct kvm *kvm) +static void *ioeventfd__thread(void *param) { + u64 tmp = 1; + + for (;;) { + int nfds, i; + + nfds = epoll_wait(epoll_fd, events, IOEVENTFD_MAX_EVENTS, -1); + for (i = 0; i < nfds; i++) { + struct ioevent *ioevent; + + if (events[i].data.fd == epoll_stop_fd) + goto done; + + ioevent = events[i].data.ptr; + + if (read(ioevent->fd, &tmp, sizeof(tmp)) < 0) + die("Failed reading event"); + + ioevent->fn(ioevent->fn_kvm, ioevent->fn_ptr); + } + } + +done: + tmp = 1; + tmp = write(epoll_stop_fd, &tmp, sizeof(tmp)); + + return NULL; +} + +static int ioeventfd__start(void) +{ + pthread_t thread; + + if (!ioeventfd_avail) + return -ENOSYS; + + return pthread_create(&thread, NULL, ioeventfd__thread, NULL); +} + +int ioeventfd__init(struct kvm *kvm) +{ + struct epoll_event epoll_event = {.events = EPOLLIN}; + int r; + ioeventfd_avail = kvm__supports_extension(kvm, KVM_CAP_IOEVENTFD); if (!ioeventfd_avail) - return; + return -ENOSYS; epoll_fd = epoll_create(IOEVENTFD_MAX_EVENTS); if (epoll_fd < 0) - die("Failed creating epoll fd"); + return -errno; + + epoll_stop_fd = eventfd(0, 0); + epoll_event.data.fd = epoll_stop_fd; + + r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, epoll_stop_fd, &epoll_event); + if (r < 0) + goto cleanup; + + r = ioeventfd__start(); + if (r < 0) + goto cleanup; + + r = 0; + + return r; + +cleanup: + close(epoll_stop_fd); + close(epoll_fd); + + return r; } -void ioeventfd__add_event(struct ioevent *ioevent) +int ioeventfd__exit(struct kvm *kvm) +{ + u64 tmp = 1; + int r; + + r = write(epoll_stop_fd, &tmp, sizeof(tmp)); + if (r < 0) + return r; + + r = read(epoll_stop_fd, &tmp, sizeof(tmp)); + if (r < 0) + return r; + + close(epoll_fd); + close(epoll_stop_fd); + + return 0; +} + +int ioeventfd__add_event(struct ioevent *ioevent) { struct kvm_ioeventfd kvm_ioevent; struct epoll_event epoll_event; struct ioevent *new_ioevent; - int event; + int event, r; if (!ioeventfd_avail) - return; + return -ENOSYS; new_ioevent = malloc(sizeof(*new_ioevent)); if (new_ioevent == NULL) - die("Failed allocating memory for new ioevent"); + return -ENOMEM; *new_ioevent = *ioevent; event = new_ioevent->fd; @@ -56,28 +139,40 @@ void ioeventfd__add_event(struct ioevent *ioevent) .flags = KVM_IOEVENTFD_FLAG_PIO | KVM_IOEVENTFD_FLAG_DATAMATCH, }; - if (ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent) != 0) - die("Failed creating new ioeventfd"); + r = ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent); + if (r) { + r = -errno; + goto cleanup; + } epoll_event = (struct epoll_event) { .events = EPOLLIN, .data.ptr = new_ioevent, }; - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, event, &epoll_event) != 0) - die("Failed assigning new event to the epoll fd"); + r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, event, &epoll_event); + if (r) { + r = -errno; + goto cleanup; + } list_add_tail(&new_ioevent->list, &used_ioevents); + + return 0; + +cleanup: + free(new_ioevent); + return r; } -void ioeventfd__del_event(u64 addr, u64 datamatch) +int ioeventfd__del_event(u64 addr, u64 datamatch) { struct kvm_ioeventfd kvm_ioevent; struct ioevent *ioevent; u8 found = 0; if (!ioeventfd_avail) - return; + return -ENOSYS; list_for_each_entry(ioevent, &used_ioevents, list) { if (ioevent->io_addr == addr) { @@ -87,7 +182,7 @@ void ioeventfd__del_event(u64 addr, u64 datamatch) } if (found == 0 || ioevent == NULL) - return; + return -ENOENT; kvm_ioevent = (struct kvm_ioeventfd) { .addr = ioevent->io_addr, @@ -106,37 +201,6 @@ void ioeventfd__del_event(u64 addr, u64 datamatch) close(ioevent->fd); free(ioevent); -} - -static void *ioeventfd__thread(void *param) -{ - for (;;) { - int nfds, i; - - nfds = epoll_wait(epoll_fd, events, IOEVENTFD_MAX_EVENTS, -1); - for (i = 0; i < nfds; i++) { - u64 tmp; - struct ioevent *ioevent; - - ioevent = events[i].data.ptr; - - if (read(ioevent->fd, &tmp, sizeof(tmp)) < 0) - die("Failed reading event"); - - ioevent->fn(ioevent->fn_kvm, ioevent->fn_ptr); - } - } - - return NULL; -} - -void ioeventfd__start(void) -{ - pthread_t thread; - - if (!ioeventfd_avail) - return; - if (pthread_create(&thread, NULL, ioeventfd__thread, NULL) != 0) - die("Failed starting ioeventfd thread"); + return 0; } diff --git a/tools/kvm/virtio/pci.c b/tools/kvm/virtio/pci.c index 2643d8a77873..7cc014e10e32 100644 --- a/tools/kvm/virtio/pci.c +++ b/tools/kvm/virtio/pci.c @@ -34,6 +34,7 @@ static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_trans *vtra { struct ioevent ioevent; struct virtio_pci *vpci = vtrans->virtio; + int r; vpci->ioeventfds[vq] = (struct virtio_pci_ioevent_param) { .vtrans = vtrans, @@ -50,7 +51,9 @@ static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_trans *vtra .fd = eventfd(0, 0), }; - ioeventfd__add_event(&ioevent); + r = ioeventfd__add_event(&ioevent); + if (r) + return r; if (vtrans->virtio_ops->notify_vq_eventfd) vtrans->virtio_ops->notify_vq_eventfd(kvm, vpci->dev, vq, ioevent.fd);