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.
This commit is contained in:
Yevheniy Demchenko 2016-04-25 20:03:05 +02:00
parent 6d79ea13dd
commit 913e54c544

View File

@ -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");
}
}