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)
922926static 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+
10221058virCHMonitorPtr
10231059virCHMonitorOpen (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 );
0 commit comments