Skip to content

Commit 54b9568

Browse files
Vineeth Pillaibryteise
authored andcommitted
ch_monitor: Use FIFO for monitor events handling
cloud-hypervisor has implemented and option to pass in a file path in addition to fd. So now we can use a FIFO(named pipe). This solves the problem of re-attaching to the monitor file in the event of libvirtd restart. Signed-off-by: Vineeth Pillai <[email protected]>
1 parent 9cff3d0 commit 54b9568

File tree

2 files changed

+80
-19
lines changed

2 files changed

+80
-19
lines changed

src/ch/ch_monitor.c

Lines changed: 78 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222

2323
#include <stdio.h>
2424
#include <unistd.h>
25+
#include <sys/types.h>
26+
#include <sys/stat.h>
27+
#include <fcntl.h>
2528
#include <assert.h>
2629

2730
#include <curl/curl.h>
@@ -867,7 +870,8 @@ static int virCHMonitorProcessEvents(virCHMonitorPtr mon, int events)
867870
return ret;
868871
}
869872

870-
static int virCHMonitorReadProcessEvents(virCHMonitorPtr mon)
873+
static int virCHMonitorReadProcessEvents(virCHMonitorPtr mon,
874+
int monitor_fd)
871875
{
872876
size_t max_sz = CH_MONITOR_BUFFER_SZ - mon->buf_offset;
873877
char *buf = mon->buffer + mon->buf_offset;
@@ -880,7 +884,7 @@ static int virCHMonitorReadProcessEvents(virCHMonitorPtr mon)
880884
do {
881885
ssize_t ret;
882886

883-
ret = read(mon->monitor_fd, buf + sz, max_sz - sz);
887+
ret = read(monitor_fd, buf + sz, max_sz - sz);
884888
if (ret == 0 || (ret < 0 && errno == EINTR)) {
885889
g_usleep(G_USEC_PER_SEC);
886890
continue;
@@ -922,15 +926,36 @@ static int virCHMonitorReadProcessEvents(virCHMonitorPtr mon)
922926
static void virCHMonitorEventLoop(void *data)
923927
{
924928
virCHMonitorPtr mon = (virCHMonitorPtr)data;
925-
virDomainObjPtr vm = mon->vm;
929+
virDomainObjPtr vm = NULL;
930+
int monitor_fd;
926931

927932
VIR_DEBUG("Monitor event loop thread starting");
928933

934+
while((monitor_fd = open(mon->monitorpath, O_RDONLY)) < 0) {
935+
if (errno == EINTR) {
936+
g_usleep(100000); // 100 milli seconds
937+
continue;
938+
}
939+
/*
940+
* Any other error should be a BUG(kernel/libc/libvirtd)
941+
* (ENOMEM can happen on exceeding per-user limits)
942+
*/
943+
VIR_ERROR("Failed to open the monitor FIFO(%s) read end!",
944+
mon->monitorpath);
945+
abort();
946+
}
947+
VIR_DEBUG("Opened the monitor FIFO(%s)", mon->monitorpath);
948+
929949
mon->buffer = g_malloc_n(sizeof(char), CH_MONITOR_BUFFER_SZ);
930950
mon->buf_offset = 0;
931951
mon->buf_fill_sz = 0;
932952

933-
virObjectRef(vm);
953+
/*
954+
* We would need to wait until VM is initialized.
955+
*/
956+
while (!(vm = virObjectRef(mon->vm)))
957+
g_usleep(100000); // 100 milli seconds
958+
934959
while (g_atomic_int_get(&mon->event_loop_stop) == 0) {
935960
VIR_DEBUG("Reading events from monitor..");
936961
/*
@@ -939,14 +964,15 @@ static void virCHMonitorEventLoop(void *data)
939964
* in that case is automatically taken care of. We can
940965
* safely continue.
941966
*/
942-
if (virCHMonitorReadProcessEvents(mon) < 0)
967+
if (virCHMonitorReadProcessEvents(mon, monitor_fd) < 0)
943968
VIR_WARN("Failed to process events from monitor!");
944969
}
970+
close(monitor_fd);
971+
945972
virObjectUnref(vm);
973+
virObjectUnref(mon);
946974

947975
VIR_DEBUG("Monitor event loop thread exiting");
948-
949-
virObjectUnref(mon);
950976
return;
951977
}
952978

@@ -997,6 +1023,17 @@ virCHMonitorPostInitialize(virCHMonitorPtr mon, virDomainObjPtr vm,
9971023

9981024
mon->pid = vm->pid;
9991025

1026+
/*
1027+
* Opening FIFO will block until the other end is also opened.
1028+
* This can cause a potential deadlock if done from the main
1029+
* thread. So we defer the opening to monitor thread. The same
1030+
* block can happen on cloud-hypervisor as well. So we start the
1031+
* monitor thread early here and then wait in the thread until
1032+
* cloud-hypervisor also opens the FIFO.
1033+
*/
1034+
if (virCHMonitorStartEventLoop(mon) < 0)
1035+
return -1;
1036+
10001037
/* get a curl handle */
10011038
mon->handle = curl_easy_init();
10021039

@@ -1013,12 +1050,11 @@ virCHMonitorPostInitialize(virCHMonitorPtr mon, virDomainObjPtr vm,
10131050
if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
10141051
return -1;
10151052

1016-
if (virCHMonitorStartEventLoop(mon) < 0)
1017-
return -1;
1018-
10191053
return 0;
10201054
}
10211055

1056+
#define MONITOR_FIFO_PATH_FORMAT "%s/%s-monitor-fifo"
1057+
10221058
virCHMonitorPtr
10231059
virCHMonitorOpen(virDomainObjPtr vm, virCHDriverPtr driver)
10241060
{
@@ -1048,6 +1084,14 @@ virCHMonitorOpen(virDomainObjPtr vm, virCHDriverPtr driver)
10481084
if (!(priv->pidfile = virPidFileBuildPath(cfg->stateDir, vm->def->name)))
10491085
goto error;
10501086

1087+
mon->monitorpath = g_strdup_printf(MONITOR_FIFO_PATH_FORMAT,
1088+
cfg->stateDir, vm->def->name);
1089+
if (!virFileExists(mon->monitorpath) ||
1090+
!virFileIsNamedPipe(mon->monitorpath)) {
1091+
VIR_ERROR("Monitor file do not exist or is not a FIFO");
1092+
goto error;
1093+
}
1094+
10511095
if (virCHMonitorPostInitialize(mon, vm, driver) < 0)
10521096
goto error;
10531097

@@ -1067,7 +1111,6 @@ virCHMonitorNew(virDomainObjPtr vm, virCHDriverPtr driver)
10671111
virCHMonitorPtr ret = NULL;
10681112
virCHMonitorPtr mon = NULL;
10691113
virCommandPtr cmd = NULL;
1070-
int monitor_fds[2];
10711114
int i;
10721115

10731116
if (virCHMonitorInitialize() < 0)
@@ -1096,15 +1139,27 @@ virCHMonitorNew(virDomainObjPtr vm, virCHDriverPtr driver)
10961139
}
10971140

10981141
/* Monitor fd to listen for VM state changes */
1099-
if (pipe(monitor_fds) < 0) {
1142+
mon->monitorpath = g_strdup_printf(MONITOR_FIFO_PATH_FORMAT,
1143+
cfg->stateDir, vm->def->name);
1144+
if (virFileExists(mon->monitorpath) &&
1145+
!virFileIsNamedPipe(mon->monitorpath)) {
1146+
VIR_WARN("Monitor file (%s) is not a FIFO, trying to delete!",
1147+
mon->monitorpath);
1148+
if (virFileRemove(mon->monitorpath, -1, -1) < 0) {
1149+
VIR_ERROR("Failed to remove the file: %s", mon->monitorpath);
1150+
goto cleanup;
1151+
}
1152+
}
1153+
1154+
if (mkfifo(mon->monitorpath, S_IWUSR | S_IRUSR) < 0 &&
1155+
errno != EEXIST) {
11001156
virReportSystemError(errno, "%s",
1101-
_("Cannot create monitor fd pipe"));
1157+
_("Cannot create monitor FIFO"));
11021158
goto cleanup;
11031159
}
1104-
mon->monitor_fd = monitor_fds[0];
1160+
11051161
virCommandAddArg(cmd, "--event-monitor");
1106-
virCommandAddArgFormat(cmd, "fd=%d", monitor_fds[1]);
1107-
virCommandPassFD(cmd, monitor_fds[1], VIR_COMMAND_PASS_FD_CLOSE_PARENT);
1162+
virCommandAddArgFormat(cmd, "path=%s", mon->monitorpath);
11081163

11091164
/* TODO enable */
11101165
virCommandSetPidFile(cmd, priv->pidfile);
@@ -1175,8 +1230,13 @@ void virCHMonitorClose(virCHMonitorPtr mon)
11751230
VIR_FREE(mon->socketpath);
11761231
}
11771232

1178-
if (mon->monitor_fd) {
1179-
close(mon->monitor_fd);
1233+
if (mon->monitorpath) {
1234+
if (virFileExists(mon->monitorpath) &&
1235+
virFileRemove(mon->monitorpath, -1, -1) < 0) {
1236+
VIR_WARN("Unable to remove CH monitor file '%s'",
1237+
mon->monitorpath);
1238+
}
1239+
VIR_FREE(mon->monitorpath);
11801240
}
11811241

11821242
virCHMonitorStopEventLoop(mon);

src/ch/ch_monitor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ struct _virCHMonitor {
133133

134134
char *socketpath;
135135

136-
int monitor_fd;
136+
char *monitorpath;
137+
137138
// Buffer to hold the data read from pipe
138139
char *buffer;
139140
// Offset to which new data from pipe has to be read.

0 commit comments

Comments
 (0)