nodedev: Don't join not spawned threads

During the nodedev driver initialization two threads are created:
one for listening on udev events (like device plug/unplug) and
the other for enumerating devices (so that the main thread doing
the driver init is not blocked). If something goes wrong at any
point then nodeStateCleanup() is called which joins those two
threads (possibly) created before. But it tries to join them even
they weren't created which is undefined behaviour (and it just so
happens that it crashes on my system).

If those two virThread variables are turned into pointers then we
can use comparison against NULL to detect whether threads were
created.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
This commit is contained in:
Michal Privoznik 2021-04-12 16:25:13 +02:00
parent 3d3435e395
commit e65d4917a4

View File

@ -63,13 +63,13 @@ struct _udevEventData {
int watch; int watch;
/* Thread data */ /* Thread data */
virThread th; virThread *th;
virCond threadCond; virCond threadCond;
bool threadQuit; bool threadQuit;
bool dataReady; bool dataReady;
/* init thread */ /* init thread */
virThread initThread; virThread *initThread;
GList *mdevctlMonitors; GList *mdevctlMonitors;
virMutex mdevctlLock; virMutex mdevctlLock;
@ -1685,8 +1685,14 @@ nodeStateCleanup(void)
priv->threadQuit = true; priv->threadQuit = true;
virCondSignal(&priv->threadCond); virCondSignal(&priv->threadCond);
virObjectUnlock(priv); virObjectUnlock(priv);
virThreadJoin(&priv->initThread); if (priv->initThread) {
virThreadJoin(&priv->th); virThreadJoin(priv->initThread);
g_clear_pointer(&priv->initThread, g_free);
}
if (priv->th) {
virThreadJoin(priv->th);
g_clear_pointer(&priv->th, g_free);
}
} }
virObjectUnref(priv); virObjectUnref(priv);
@ -2243,10 +2249,12 @@ nodeStateInitialize(bool privileged,
udev_monitor_set_receive_buffer_size(priv->udev_monitor, udev_monitor_set_receive_buffer_size(priv->udev_monitor,
128 * 1024 * 1024); 128 * 1024 * 1024);
if (virThreadCreateFull(&priv->th, true, udevEventHandleThread, priv->th = g_new0(virThread, 1);
if (virThreadCreateFull(priv->th, true, udevEventHandleThread,
"udev-event", false, NULL) < 0) { "udev-event", false, NULL) < 0) {
virReportSystemError(errno, "%s", virReportSystemError(errno, "%s",
_("failed to create udev handler thread")); _("failed to create udev handler thread"));
g_clear_pointer(&priv->th, g_free);
goto unlock; goto unlock;
} }
@ -2284,10 +2292,12 @@ nodeStateInitialize(bool privileged,
if (udevSetupSystemDev() != 0) if (udevSetupSystemDev() != 0)
goto cleanup; goto cleanup;
if (virThreadCreateFull(&priv->initThread, true, nodeStateInitializeEnumerate, priv->initThread = g_new0(virThread, 1);
if (virThreadCreateFull(priv->initThread, true, nodeStateInitializeEnumerate,
"nodedev-init", false, udev) < 0) { "nodedev-init", false, udev) < 0) {
virReportSystemError(errno, "%s", virReportSystemError(errno, "%s",
_("failed to create udev enumerate thread")); _("failed to create udev enumerate thread"));
g_clear_pointer(&priv->initThread, g_free);
goto cleanup; goto cleanup;
} }