提交 3ecebf07 编写于 作者: P Peter Krempa

qemu: process: Refactor reconnecting to qemu processes

Move entering the job into the thread to simplify the program flow. Also
as the code holds a separate reference to the domain object some
conditions can be simplified.

After this patch qemuDomainObjTransferJob is no longer needed so this
patch removes it.
上级 a2a35d01
...@@ -185,16 +185,6 @@ qemuDomainObjRestoreJob(virDomainObjPtr obj, ...@@ -185,16 +185,6 @@ qemuDomainObjRestoreJob(virDomainObjPtr obj,
qemuDomainObjResetAsyncJob(priv); qemuDomainObjResetAsyncJob(priv);
} }
void
qemuDomainObjTransferJob(virDomainObjPtr obj)
{
qemuDomainObjPrivatePtr priv = obj->privateData;
VIR_DEBUG("Changing job owner from %llu to %llu",
priv->job.owner, virThreadSelfID());
priv->job.owner = virThreadSelfID();
}
static void static void
qemuDomainObjFreeJob(qemuDomainObjPrivatePtr priv) qemuDomainObjFreeJob(qemuDomainObjPrivatePtr priv)
{ {
......
...@@ -239,7 +239,6 @@ void qemuDomainObjSetAsyncJobMask(virDomainObjPtr obj, ...@@ -239,7 +239,6 @@ void qemuDomainObjSetAsyncJobMask(virDomainObjPtr obj,
unsigned long long allowedJobs); unsigned long long allowedJobs);
void qemuDomainObjRestoreJob(virDomainObjPtr obj, void qemuDomainObjRestoreJob(virDomainObjPtr obj,
struct qemuDomainJobObj *job); struct qemuDomainJobObj *job);
void qemuDomainObjTransferJob(virDomainObjPtr obj);
void qemuDomainObjDiscardAsyncJob(virQEMUDriverPtr driver, void qemuDomainObjDiscardAsyncJob(virQEMUDriverPtr driver,
virDomainObjPtr obj); virDomainObjPtr obj);
void qemuDomainObjReleaseAsyncJob(virDomainObjPtr obj); void qemuDomainObjReleaseAsyncJob(virDomainObjPtr obj);
......
...@@ -3524,8 +3524,7 @@ qemuProcessUpdateDevices(virQEMUDriverPtr driver, ...@@ -3524,8 +3524,7 @@ qemuProcessUpdateDevices(virQEMUDriverPtr driver,
struct qemuProcessReconnectData { struct qemuProcessReconnectData {
virConnectPtr conn; virConnectPtr conn;
virQEMUDriverPtr driver; virQEMUDriverPtr driver;
void *payload; virDomainObjPtr obj;
struct qemuDomainJobObj oldjob;
}; };
/* /*
* Open an existing VM's monitor, re-detect VCPU threads * Open an existing VM's monitor, re-detect VCPU threads
...@@ -3534,13 +3533,27 @@ struct qemuProcessReconnectData { ...@@ -3534,13 +3533,27 @@ struct qemuProcessReconnectData {
* We own the virConnectPtr we are passed here - whoever started * We own the virConnectPtr we are passed here - whoever started
* this thread function has increased the reference counter to it * this thread function has increased the reference counter to it
* so that we now have to close it. * so that we now have to close it.
*
* This function also inherits a locked domain object.
*
* This function needs to:
* 1. Enter job
* 1. just before monitor reconnect do lightweight MonitorEnter
* (increase VM refcount and unlock VM)
* 2. reconnect to monitor
* 3. do lightweight MonitorExit (lock VM)
* 4. continue reconnect process
* 5. EndJob
*
* We can't do normal MonitorEnter & MonitorExit because these two lock the
* monitor lock, which does not exists in this early phase.
*/ */
static void static void
qemuProcessReconnect(void *opaque) qemuProcessReconnect(void *opaque)
{ {
struct qemuProcessReconnectData *data = opaque; struct qemuProcessReconnectData *data = opaque;
virQEMUDriverPtr driver = data->driver; virQEMUDriverPtr driver = data->driver;
virDomainObjPtr obj = data->payload; virDomainObjPtr obj = data->obj;
qemuDomainObjPrivatePtr priv; qemuDomainObjPrivatePtr priv;
virConnectPtr conn = data->conn; virConnectPtr conn = data->conn;
struct qemuDomainJobObj oldjob; struct qemuDomainJobObj oldjob;
...@@ -3550,26 +3563,24 @@ qemuProcessReconnect(void *opaque) ...@@ -3550,26 +3563,24 @@ qemuProcessReconnect(void *opaque)
size_t i; size_t i;
int ret; int ret;
memcpy(&oldjob, &data->oldjob, sizeof(oldjob));
VIR_FREE(data); VIR_FREE(data);
virNWFilterReadLockFilterUpdates(); qemuDomainObjRestoreJob(obj, &oldjob);
virObjectLock(obj); /* Hold an extra reference because we can't allow 'vm' to be
* deleted if qemuConnectMonitor() failed */
virObjectRef(obj);
if (qemuDomainObjBeginJob(driver, obj, QEMU_JOB_MODIFY) < 0)
goto killvm;
virNWFilterReadLockFilterUpdates();
cfg = virQEMUDriverGetConfig(driver); cfg = virQEMUDriverGetConfig(driver);
VIR_DEBUG("Reconnect monitor to %p '%s'", obj, obj->def->name); VIR_DEBUG("Reconnect monitor to %p '%s'", obj, obj->def->name);
priv = obj->privateData; priv = obj->privateData;
/* Job was started by the caller for us */
qemuDomainObjTransferJob(obj);
/* Hold an extra reference because we can't allow 'vm' to be
* deleted if qemuConnectMonitor() failed */
virObjectRef(obj);
/* XXX check PID liveliness & EXE path */ /* XXX check PID liveliness & EXE path */
if (qemuConnectMonitor(driver, obj, QEMU_ASYNC_JOB_NONE, -1) < 0) if (qemuConnectMonitor(driver, obj, QEMU_ASYNC_JOB_NONE, -1) < 0)
goto error; goto error;
...@@ -3701,10 +3712,10 @@ qemuProcessReconnect(void *opaque) ...@@ -3701,10 +3712,10 @@ qemuProcessReconnect(void *opaque)
driver->inhibitCallback(true, driver->inhibitOpaque); driver->inhibitCallback(true, driver->inhibitOpaque);
endjob: endjob:
if (!qemuDomainObjEndJob(driver, obj)) /* we hold an extra reference, so this will never fail */
obj = NULL; ignore_value(qemuDomainObjEndJob(driver, obj));
if (obj && virObjectUnref(obj)) if (virObjectUnref(obj))
virObjectUnlock(obj); virObjectUnlock(obj);
virObjectUnref(conn); virObjectUnref(conn);
...@@ -3714,35 +3725,35 @@ qemuProcessReconnect(void *opaque) ...@@ -3714,35 +3725,35 @@ qemuProcessReconnect(void *opaque)
return; return;
error: error:
if (!qemuDomainObjEndJob(driver, obj)) /* we hold an extra reference, so this will never fail */
obj = NULL; ignore_value(qemuDomainObjEndJob(driver, obj));
if (obj) { killvm:
if (!virDomainObjIsActive(obj)) { if (virDomainObjIsActive(obj)) {
if (virObjectUnref(obj)) /* We can't get the monitor back, so must kill the VM
virObjectUnlock(obj); * to remove danger of it ending up running twice if
} else if (virObjectUnref(obj)) { * user tries to start it again later
/* We can't get the monitor back, so must kill the VM */
* to remove danger of it ending up running twice if if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NO_SHUTDOWN)) {
* user tries to start it again later /* If we couldn't get the monitor and qemu supports
*/ * no-shutdown, we can safely say that the domain
if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NO_SHUTDOWN)) { * crashed ... */
/* If we couldn't get the monitor and qemu supports state = VIR_DOMAIN_SHUTOFF_CRASHED;
* no-shutdown, we can safely say that the domain } else {
* crashed ... */ /* ... but if it doesn't we can't say what the state
state = VIR_DOMAIN_SHUTOFF_CRASHED; * really is and FAILED means "failed to start" */
} else { state = VIR_DOMAIN_SHUTOFF_UNKNOWN;
/* ... but if it doesn't we can't say what the state
* really is and FAILED means "failed to start" */
state = VIR_DOMAIN_SHUTOFF_UNKNOWN;
}
qemuProcessStop(driver, obj, state, 0);
if (!obj->persistent)
qemuDomainRemoveInactive(driver, obj);
else
virObjectUnlock(obj);
} }
qemuProcessStop(driver, obj, state, 0);
} }
if (virObjectUnref(obj)) {
if (!obj->persistent)
qemuDomainRemoveInactive(driver, obj);
else
virObjectUnlock(obj);
}
virObjectUnref(conn); virObjectUnref(conn);
virObjectUnref(cfg); virObjectUnref(cfg);
virNWFilterUnlockFilterUpdates(); virNWFilterUnlockFilterUpdates();
...@@ -3756,6 +3767,7 @@ qemuProcessReconnectHelper(virDomainObjPtr obj, ...@@ -3756,6 +3767,7 @@ qemuProcessReconnectHelper(virDomainObjPtr obj,
struct qemuProcessReconnectData *src = opaque; struct qemuProcessReconnectData *src = opaque;
struct qemuProcessReconnectData *data; struct qemuProcessReconnectData *data;
/* If the VM was inactive, we don't need to reconnect */
if (!obj->pid) if (!obj->pid)
return 0; return 0;
...@@ -3763,64 +3775,35 @@ qemuProcessReconnectHelper(virDomainObjPtr obj, ...@@ -3763,64 +3775,35 @@ qemuProcessReconnectHelper(virDomainObjPtr obj,
return -1; return -1;
memcpy(data, src, sizeof(*data)); memcpy(data, src, sizeof(*data));
data->payload = obj; data->obj = obj;
/*
* We create a separate thread to run qemuProcessReconnect in it.
* However, qemuProcessReconnect needs to:
* 1. just before monitor reconnect do lightweight MonitorEnter
* (increase VM refcount, unlock VM & driver)
* 2. reconnect to monitor
* 3. do lightweight MonitorExit (lock VM)
* 4. continue reconnect process
* 5. EndJob
*
* NB, we can't do normal MonitorEnter & MonitorExit because
* these two lock the monitor lock, which does not exists in
* this early phase.
*/
/* this lock will be eventually transferred to the thread that handles the
* reconnect */
virObjectLock(obj); virObjectLock(obj);
qemuDomainObjRestoreJob(obj, &data->oldjob); /* Since we close the connection later on, we have to make sure that the
* threads we start see a valid connection throughout their lifetime. We
if (qemuDomainObjBeginJob(src->driver, obj, QEMU_JOB_MODIFY) < 0) * simply increase the reference counter here.
goto error;
/* Since we close the connection later on, we have to make sure
* that the threads we start see a valid connection throughout their
* lifetime. We simply increase the reference counter here.
*/ */
virObjectRef(data->conn); virObjectRef(data->conn);
if (virThreadCreate(&thread, false, qemuProcessReconnect, data) < 0) { if (virThreadCreate(&thread, false, qemuProcessReconnect, data) < 0) {
virObjectUnref(data->conn);
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
_("Could not create thread. QEMU initialization " _("Could not create thread. QEMU initialization "
"might be incomplete")); "might be incomplete"));
if (!qemuDomainObjEndJob(src->driver, obj)) { /* We can't spawn a thread and thus connect to monitor. Kill qemu. */
obj = NULL; qemuProcessStop(src->driver, obj, VIR_DOMAIN_SHUTOFF_FAILED, 0);
} else if (virObjectUnref(obj)) { if (!obj->persistent)
/* We can't spawn a thread and thus connect to monitor. qemuDomainRemoveInactive(src->driver, obj);
* Kill qemu */ else
qemuProcessStop(src->driver, obj, VIR_DOMAIN_SHUTOFF_FAILED, 0); virObjectUnlock(obj);
if (!obj->persistent)
qemuDomainRemoveInactive(src->driver, obj);
else
virObjectUnlock(obj);
}
goto error;
}
virObjectUnlock(obj); virObjectUnref(data->conn);
VIR_FREE(data);
return -1;
}
return 0; return 0;
error:
VIR_FREE(data);
return -1;
} }
/** /**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册