From 913e54c544b981070bf7c9a8ebc688a8de4b0385 Mon Sep 17 00:00:00 2001 From: Yevheniy Demchenko Date: Mon, 25 Apr 2016 20:03:05 +0200 Subject: [PATCH] Current implementation of event listener in virt-serial does not support keepalive, it does not generate nor capable to answer to keepalive requests, which causes libvirt connection to disconnect every 30 seconds (interval*timeout in libvirtd.conf). Furthermore, it does not clean up filehandlers and leaves hanging sockets. Also, if other thread opens its own connection to libvirt (i.e. checkpoint.c), event function in virt-serial.c just updates event listener file handler with a wrong one, what causes checkpoint.c malfunctions, fence_virtd hangs and so on. This patch uses default event listener implementation from libvirt and resolves theese problems. --- server/virt-serial.c | 206 ++++++++----------------------------------- 1 file changed, 37 insertions(+), 169 deletions(-) diff --git a/server/virt-serial.c b/server/virt-serial.c index fff38ef..2528153 100644 --- a/server/virt-serial.c +++ b/server/virt-serial.c @@ -27,20 +27,6 @@ #define STREQ(a,b) (strcmp((a),(b)) == 0) -/* handle globals */ -static int h_fd = -1; -static virEventHandleType h_event = 0; -static virEventHandleCallback h_cb = NULL; -static virFreeCallback h_ff = NULL; -static void *h_opaque = NULL; - -/* timeout globals */ -#define TIMEOUT_MS 1000 -static int t_active = 0; -static int t_timeout = -1; -static virEventTimeoutCallback t_cb = NULL; -static virFreeCallback t_ff = NULL; -static void *t_opaque = NULL; static pthread_t event_tid = 0; static int run = 0; @@ -48,20 +34,6 @@ static int run = 0; const char *eventToString(int event); int myDomainEventCallback1(virConnectPtr conn, virDomainPtr dom, int event, int detail, void *opaque); -int myEventAddHandleFunc(int fd, int event, - virEventHandleCallback cb, - void *opaque, virFreeCallback ff); -void myEventUpdateHandleFunc(int watch, int event); -int myEventRemoveHandleFunc(int watch); - -int myEventAddTimeoutFunc(int timeout, - virEventTimeoutCallback cb, - void *opaque, virFreeCallback ff); -void myEventUpdateTimeoutFunc(int timer, int timout); -int myEventRemoveTimeoutFunc(int timer); - -int myEventHandleTypeToPollEvent(virEventHandleType events); -virEventHandleType myPollEventToEventHandleType(int events); void usage(const char *pname); @@ -70,103 +42,6 @@ struct domain_info { virDomainEventType event; }; - -/* EventImpl Functions */ -int -myEventHandleTypeToPollEvent(virEventHandleType events) -{ - int ret = 0; - if (events & VIR_EVENT_HANDLE_READABLE) - ret |= POLLIN; - if (events & VIR_EVENT_HANDLE_WRITABLE) - ret |= POLLOUT; - if (events & VIR_EVENT_HANDLE_ERROR) - ret |= POLLERR; - if (events & VIR_EVENT_HANDLE_HANGUP) - ret |= POLLHUP; - return ret; -} - -virEventHandleType -myPollEventToEventHandleType(int events) -{ - virEventHandleType ret = 0; - if (events & POLLIN) - ret |= VIR_EVENT_HANDLE_READABLE; - if (events & POLLOUT) - ret |= VIR_EVENT_HANDLE_WRITABLE; - if (events & POLLERR) - ret |= VIR_EVENT_HANDLE_ERROR; - if (events & POLLHUP) - ret |= VIR_EVENT_HANDLE_HANGUP; - - return ret; -} - -int -myEventAddHandleFunc(int fd, int event, - virEventHandleCallback cb, - void *opaque, virFreeCallback ff) -{ - DEBUG1("Add handle %d %d %p %p %p", fd, event, cb, opaque, ff); - h_fd = fd; - h_event = myEventHandleTypeToPollEvent(event); - h_cb = cb; - h_opaque = opaque; - h_ff = ff; - return 0; -} - -void -myEventUpdateHandleFunc(int fd, int event) -{ - DEBUG1("Updated Handle %d %d", fd, event); - h_event = myEventHandleTypeToPollEvent(event); - return; -} - -int -myEventRemoveHandleFunc(int fd) -{ - DEBUG1("Removed Handle %d", fd); - h_fd = 0; - if (h_ff) - (h_ff) (h_opaque); - return 0; -} - -int -myEventAddTimeoutFunc(int timeout, - virEventTimeoutCallback cb, - void *opaque, virFreeCallback ff) -{ - DEBUG1("Adding Timeout %d %p %p", timeout, cb, opaque); - t_active = 1; - t_timeout = timeout; - t_cb = cb; - t_ff = ff; - t_opaque = opaque; - return 0; -} - -void -myEventUpdateTimeoutFunc(int timer, int timeout) -{ - /*DEBUG1("Timeout updated %d %d", timer, timeout); */ - t_timeout = timeout; -} - -int -myEventRemoveTimeoutFunc(int timer) -{ - DEBUG1("Timeout removed %d", timer); - t_active = 0; - if (t_ff) - (t_ff) (t_opaque); - return 0; -} - - static int is_in_directory(const char *dir, const char *pathspec) { @@ -395,6 +270,30 @@ struct event_args { int wake_fd; }; +void +connectClose(virConnectPtr conn ATTRIBUTE_UNUSED, + int reason, + void *opaque ATTRIBUTE_UNUSED) +{ + switch (reason) { + case VIR_CONNECT_CLOSE_REASON_ERROR: + dbg_printf(2, "Connection closed due to I/O error\n"); + break; + case VIR_CONNECT_CLOSE_REASON_EOF: + dbg_printf(2, "Connection closed due to end of file\n"); + break; + case VIR_CONNECT_CLOSE_REASON_KEEPALIVE: + dbg_printf(2, "Connection closed due to keepalive timeout\n"); + break; + case VIR_CONNECT_CLOSE_REASON_CLIENT: + dbg_printf(2, "Connection closed due to client request\n"); + break; + default: + dbg_printf(2, "Connection closed due to unknown reason\n"); + break; + }; + run = 0; +} int myDomainEventCallback1(virConnectPtr conn, @@ -425,7 +324,6 @@ event_thread(void *arg) struct event_args *args = (struct event_args *)arg; virConnectPtr dconn = NULL; int callback1ret = -1; - int sts; dbg_printf(3, "Libvirt event listener starting\n"); if (args->uri) @@ -434,13 +332,10 @@ event_thread(void *arg) dbg_printf(3," * Socket path: %s\n", args->path); dbg_printf(3," * Mode: %s\n", args->mode ? "VMChannel" : "Serial"); -top: - virEventRegisterImpl(myEventAddHandleFunc, - myEventUpdateHandleFunc, - myEventRemoveHandleFunc, - myEventAddTimeoutFunc, - myEventUpdateTimeoutFunc, - myEventRemoveTimeoutFunc); + if (virEventRegisterDefaultImpl() < 0) { + dbg_printf(1, "Failed to register default event impl\n"); + goto out; + } dconn = virConnectOpen(args->uri); if (!dconn) { @@ -448,6 +343,8 @@ top: goto out; } + virConnectRegisterCloseCallback(dconn, connectClose, NULL, NULL); + DEBUG0("Registering domain event cbs"); registerExisting(dconn, args->path, args->mode); @@ -455,43 +352,14 @@ top: callback1ret = virConnectDomainEventRegister(dconn, myDomainEventCallback1, arg, NULL); - if (callback1ret == 0) { + if (callback1ret != -1) { + if (virConnectSetKeepAlive(dconn, 5, 5) < 0) { + dbg_printf(1, "Failed to start keepalive protocol\n"); + run = 0; + } while (run) { - struct pollfd pfd = { - .fd = h_fd, - .events = h_event, - .revents = 0 - }; - - sts = poll(&pfd, 1, TIMEOUT_MS); - /* We are assuming timeout of 0 here - so execute every time */ - if (t_cb && t_active) { - t_cb(t_timeout, t_opaque); - } - - if (sts == 0) { - /* DEBUG0("Poll timeout"); */ - continue; - } - - if (sts < 0) { - DEBUG0("Poll failed"); - continue; - } - - if (pfd.revents & POLLHUP) { - DEBUG0("Reset by peer"); - virConnectDomainEventDeregister(dconn, myDomainEventCallback1); - if (dconn && virConnectClose(dconn) < 0) - dbg_printf(1, "error closing libvirt connection\n"); - DEBUG0("Attempting to reinitialize libvirt connection"); - goto top; - } - - if (h_cb) { - h_cb(0, h_fd, - myPollEventToEventHandleType(pfd.revents & h_event), - h_opaque); + if (virEventRunDefaultImpl() < 0) { + dbg_printf(1, "RunDefaultImpl Failed\n"); } }