Commit ea6eeb1c authored by Sasha Levin's avatar Sasha Levin Committed by Will Deacon
Browse files

kvm tools: Fixes for ioeventfd module



Fixes include:
 - Error handling
 - Cleanup
 - Standard init/uninit

Signed-off-by: default avatarSasha Levin <levinsasha928@gmail.com>
parent 7af40b91
......@@ -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)
......
......@@ -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
......@@ -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;
}
......@@ -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);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment