[libvirt] [PATCH v2] libvirt supports Guest Panicked

Chen Fan chen.fan.fnst at cn.fujitsu.com
Tue May 28 06:14:46 UTC 2013


From: ChenFan <chen.fan.fnst at cn.fujitsu.com>

This patch implements qemu_driver supporting guest panicked.
we crashed the guest while libvirt isn't running, then restart libvirtd, we change the domain state to 'crashed'.

---
 examples/domain-events/events-c/event-test.c |  10 +++
 include/libvirt/libvirt.h.in                 |  16 +++++
 src/conf/domain_conf.c                       |  12 ++--
 src/qemu/qemu_monitor.c                      |  14 +++-
 src/qemu/qemu_monitor.h                      |   5 ++
 src/qemu/qemu_monitor_json.c                 |   7 ++
 src/qemu/qemu_process.c                      | 103 ++++++++++++++++++++++++++-
 tools/virsh-domain-monitor.c                 |   8 +++
 8 files changed, 169 insertions(+), 6 deletions(-)

diff --git a/examples/domain-events/events-c/event-test.c b/examples/domain-events/events-c/event-test.c
index eeff50f..1b425fb 100644
--- a/examples/domain-events/events-c/event-test.c
+++ b/examples/domain-events/events-c/event-test.c
@@ -93,6 +93,9 @@ const char *eventToString(int event) {
         case VIR_DOMAIN_EVENT_PMSUSPENDED:
             ret = "PMSuspended";
             break;
+        case VIR_DOMAIN_EVENT_CRASHED:
+            ret = "Crashed";
+            break;
     }
     return ret;
 }
@@ -209,6 +212,13 @@ static const char *eventDetailToString(int event, int detail) {
                 break;
             }
             break;
+        case VIR_DOMAIN_EVENT_CRASHED:
+           switch ((virDomainEventCrashedDetailType) detail) {
+           case VIR_DOMAIN_EVENT_CRASHED_PANICKED:
+               ret = "Panicked";
+               break;
+           }
+           break;
     }
     return ret;
 }
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 1804c93..56c6c5c 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -155,6 +155,7 @@ typedef enum {
     VIR_DOMAIN_RUNNING_SAVE_CANCELED = 7,   /* returned from failed save process */
     VIR_DOMAIN_RUNNING_WAKEUP = 8,          /* returned from pmsuspended due to
                                                wakeup event */
+    VIR_DOMAIN_RUNNING_CRASHED = 9,          /* resumed from crashed */
 
 #ifdef VIR_ENUM_SENTINELS
     VIR_DOMAIN_RUNNING_LAST
@@ -180,6 +181,7 @@ typedef enum {
     VIR_DOMAIN_PAUSED_FROM_SNAPSHOT = 7, /* paused after restoring from snapshot */
     VIR_DOMAIN_PAUSED_SHUTTING_DOWN = 8, /* paused during shutdown process */
     VIR_DOMAIN_PAUSED_SNAPSHOT = 9,      /* paused while creating a snapshot */
+    VIR_DOMAIN_PAUSED_GUEST_PANICKED = 10, /* paused due to a guest panicked event */
 
 #ifdef VIR_ENUM_SENTINELS
     VIR_DOMAIN_PAUSED_LAST
@@ -189,6 +191,7 @@ typedef enum {
 typedef enum {
     VIR_DOMAIN_SHUTDOWN_UNKNOWN = 0,    /* the reason is unknown */
     VIR_DOMAIN_SHUTDOWN_USER = 1,       /* shutting down on user request */
+    VIR_DOMAIN_SHUTDOWN_CRASHED = 2,    /* domain crashed */
 
 #ifdef VIR_ENUM_SENTINELS
     VIR_DOMAIN_SHUTDOWN_LAST
@@ -212,6 +215,7 @@ typedef enum {
 
 typedef enum {
     VIR_DOMAIN_CRASHED_UNKNOWN = 0,     /* crashed for unknown reason */
+    VIR_DOMAIN_CRASHED_PANICKED = 1,     /* domain panicked */
 
 #ifdef VIR_ENUM_SENTINELS
     VIR_DOMAIN_CRASHED_LAST
@@ -3319,6 +3323,7 @@ typedef enum {
     VIR_DOMAIN_EVENT_STOPPED = 5,
     VIR_DOMAIN_EVENT_SHUTDOWN = 6,
     VIR_DOMAIN_EVENT_PMSUSPENDED = 7,
+    VIR_DOMAIN_EVENT_CRASHED = 8,
 
 #ifdef VIR_ENUM_SENTINELS
     VIR_DOMAIN_EVENT_LAST
@@ -3450,6 +3455,17 @@ typedef enum {
 #endif
 } virDomainEventPMSuspendedDetailType;
 
+/*
+ * Details about the 'crashed' lifecycle event
+ */
+typedef enum {
+    VIR_DOMAIN_EVENT_CRASHED_PANICKED = 0, /* Guest was panicked */
+
+#ifdef VIR_ENUM_SENTINELS
+    VIR_DOMAIN_EVENT_CRASHED_LAST
+#endif
+} virDomainEventCrashedDetailType;
+
 /**
  * virConnectDomainEventCallback:
  * @conn: virConnect connection
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index a9656af..f577fd4 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -642,7 +642,8 @@ VIR_ENUM_IMPL(virDomainRunningReason, VIR_DOMAIN_RUNNING_LAST,
               "unpaused",
               "migration canceled",
               "save canceled",
-              "wakeup")
+              "wakeup",
+              "from crashed")
 
 VIR_ENUM_IMPL(virDomainBlockedReason, VIR_DOMAIN_BLOCKED_LAST,
               "unknown")
@@ -657,11 +658,13 @@ VIR_ENUM_IMPL(virDomainPausedReason, VIR_DOMAIN_PAUSED_LAST,
               "watchdog",
               "from snapshot",
               "shutdown",
-              "snapshot")
+              "snapshot",
+              "guest panicked")
 
 VIR_ENUM_IMPL(virDomainShutdownReason, VIR_DOMAIN_SHUTDOWN_LAST,
               "unknown",
-              "user")
+              "user",
+              "crashed")
 
 VIR_ENUM_IMPL(virDomainShutoffReason, VIR_DOMAIN_SHUTOFF_LAST,
               "unknown",
@@ -674,7 +677,8 @@ VIR_ENUM_IMPL(virDomainShutoffReason, VIR_DOMAIN_SHUTOFF_LAST,
               "from snapshot")
 
 VIR_ENUM_IMPL(virDomainCrashedReason, VIR_DOMAIN_CRASHED_LAST,
-              "unknown")
+              "unknown",
+              "panicked")
 
 VIR_ENUM_IMPL(virDomainPMSuspendedReason, VIR_DOMAIN_PMSUSPENDED_LAST,
               "unknown")
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 4e35f79..e0cd62c 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -113,7 +113,7 @@ VIR_ENUM_IMPL(qemuMonitorVMStatus,
               QEMU_MONITOR_VM_STATUS_LAST,
               "debug", "inmigrate", "internal-error", "io-error", "paused",
               "postmigrate", "prelaunch", "finish-migrate", "restore-vm",
-              "running", "save-vm", "shutdown", "watchdog")
+              "running", "save-vm", "shutdown", "watchdog", "guest-panicked")
 
 typedef enum {
     QEMU_MONITOR_BLOCK_IO_STATUS_OK,
@@ -1032,6 +1032,15 @@ int qemuMonitorEmitResume(qemuMonitorPtr mon)
 }
 
 
+int qemuMonitorEmitGUESTPanicked(qemuMonitorPtr mon)
+{
+    int ret = -1;
+    VIR_DEBUG("mon=%p", mon);
+    QEMU_MONITOR_CALLBACK(mon, ret, domainGUESTPanicked, mon->vm);
+    return ret;
+}
+
+
 int qemuMonitorEmitRTCChange(qemuMonitorPtr mon, long long offset)
 {
     int ret = -1;
@@ -3185,6 +3194,9 @@ int qemuMonitorVMStatusToPausedReason(const char *status)
     case QEMU_MONITOR_VM_STATUS_WATCHDOG:
         return VIR_DOMAIN_PAUSED_WATCHDOG;
 
+    case QEMU_MONITOR_VM_STATUS_GUEST_PANICKED:
+        return VIR_DOMAIN_PAUSED_GUEST_PANICKED;
+
     /* unreachable from this point on */
     case QEMU_MONITOR_VM_STATUS_LAST:
         ;
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index a607712..543050c 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -140,6 +140,8 @@ struct _qemuMonitorCallbacks {
                                unsigned long long actual);
     int (*domainPMSuspendDisk)(qemuMonitorPtr mon,
                                virDomainObjPtr vm);
+    int (*domainGUESTPanicked)(qemuMonitorPtr mon,
+                               virDomainObjPtr vm);
 };
 
 char *qemuMonitorEscapeArg(const char *in);
@@ -220,6 +222,8 @@ int qemuMonitorEmitBlockJob(qemuMonitorPtr mon,
 int qemuMonitorEmitBalloonChange(qemuMonitorPtr mon,
                                  unsigned long long actual);
 int qemuMonitorEmitPMSuspendDisk(qemuMonitorPtr mon);
+int qemuMonitorEmitGUESTPanicked(qemuMonitorPtr mon);
+
 
 int qemuMonitorStartCPUs(qemuMonitorPtr mon,
                          virConnectPtr conn);
@@ -239,6 +243,7 @@ typedef enum {
     QEMU_MONITOR_VM_STATUS_SAVE_VM,
     QEMU_MONITOR_VM_STATUS_SHUTDOWN,
     QEMU_MONITOR_VM_STATUS_WATCHDOG,
+    QEMU_MONITOR_VM_STATUS_GUEST_PANICKED,
 
     QEMU_MONITOR_VM_STATUS_LAST
 } qemuMonitorVMStatus;
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 2b73884..b6efa52 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -74,6 +74,7 @@ static void qemuMonitorJSONHandleBlockJobCanceled(qemuMonitorPtr mon, virJSONVal
 static void qemuMonitorJSONHandleBlockJobReady(qemuMonitorPtr mon, virJSONValuePtr data);
 static void qemuMonitorJSONHandleBalloonChange(qemuMonitorPtr mon, virJSONValuePtr data);
 static void qemuMonitorJSONHandlePMSuspendDisk(qemuMonitorPtr mon, virJSONValuePtr data);
+static void qemuMonitorJSONHandleGUESTPanicked(qemuMonitorPtr mon, virJSONValuePtr data);
 
 typedef struct {
     const char *type;
@@ -87,6 +88,7 @@ static qemuEventHandler eventHandlers[] = {
     { "BLOCK_JOB_COMPLETED", qemuMonitorJSONHandleBlockJobCompleted, },
     { "BLOCK_JOB_READY", qemuMonitorJSONHandleBlockJobReady, },
     { "DEVICE_TRAY_MOVED", qemuMonitorJSONHandleTrayChange, },
+    { "GUEST_PANICKED", qemuMonitorJSONHandleGUESTPanicked, },
     { "POWERDOWN", qemuMonitorJSONHandlePowerdown, },
     { "RESET", qemuMonitorJSONHandleReset, },
     { "RESUME", qemuMonitorJSONHandleResume, },
@@ -593,6 +595,11 @@ static void qemuMonitorJSONHandleResume(qemuMonitorPtr mon, virJSONValuePtr data
     qemuMonitorEmitResume(mon);
 }
 
+static void qemuMonitorJSONHandleGUESTPanicked(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED)
+{
+    qemuMonitorEmitGUESTPanicked(mon);
+}
+
 static void qemuMonitorJSONHandleRTCChange(qemuMonitorPtr mon, virJSONValuePtr data)
 {
     long long offset = 0;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index d4fd4fb..29c8c4b 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -548,6 +548,7 @@ qemuProcessFakeReboot(void *opaque)
     qemuDomainObjPrivatePtr priv = vm->privateData;
     virDomainEventPtr event = NULL;
     virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+    virDomainRunningReason reason = VIR_DOMAIN_RUNNING_BOOTED;
     int ret = -1;
     VIR_DEBUG("vm=%p", vm);
     virObjectLock(vm);
@@ -573,8 +574,11 @@ qemuProcessFakeReboot(void *opaque)
         goto endjob;
     }
 
+    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_CRASHED)
+        reason = VIR_DOMAIN_RUNNING_CRASHED;
+
     if (qemuProcessStartCPUs(driver, vm, NULL,
-                             VIR_DOMAIN_RUNNING_BOOTED,
+                             reason,
                              QEMU_ASYNC_JOB_NONE) < 0) {
         if (virGetLastError() == NULL)
             virReportError(VIR_ERR_INTERNAL_ERROR,
@@ -1269,6 +1273,98 @@ qemuProcessHandlePMSuspendDisk(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
     return 0;
 }
 
+static int
+qemuProcessHandleGUESTPanicked(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
+                               virDomainObjPtr vm)
+{
+    virQEMUDriverPtr driver = qemu_driver;
+    qemuDomainObjPrivatePtr priv;
+    virDomainEventPtr event = NULL;
+    bool isReboot = true;
+    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
+
+    VIR_DEBUG("vm=%p", vm);
+
+    virObjectLock(vm);
+
+    if (!virDomainObjIsActive(vm)) {
+        VIR_DEBUG("Ignoring GUEST_PANICKED event from inactive domain %s",
+                  vm->def->name);
+        goto cleanup;
+    }
+
+    priv = vm->privateData;
+
+    virDomainObjSetState(vm,
+                         VIR_DOMAIN_CRASHED,
+                         VIR_DOMAIN_CRASHED_PANICKED);
+
+    event = virDomainEventNewFromObj(vm,
+                                     VIR_DOMAIN_EVENT_CRASHED,
+                                     VIR_DOMAIN_EVENT_CRASHED_PANICKED);
+
+    if (vm->def->onCrash == VIR_DOMAIN_LIFECYCLE_CRASH_PRESERVE) {
+        VIR_FREE(priv->lockState);
+
+        if (virDomainLockProcessPause(driver->lockManager, vm, &priv->lockState) < 0)
+            VIR_WARN("Unable to release lease on %s", vm->def->name);
+        VIR_DEBUG("Preserving lock state '%s'", NULLSTR(priv->lockState));
+
+        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
+            VIR_WARN("Unable to save status on vm %s after state change",
+                     vm->def->name);
+        }
+
+        goto cleanup;
+    }
+
+    if (vm->def->onCrash == VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY) {
+        isReboot = false;
+        VIR_INFO("Domain on_crash setting overridden, shutting down");
+    }
+
+    qemuDomainSetFakeReboot(driver, vm, isReboot);
+
+    if (isReboot) {
+        qemuProcessShutdownOrReboot(driver, vm);
+    } else {
+        priv->beingDestroyed = true;
+
+        if (qemuProcessKill(vm, VIR_QEMU_PROCESS_KILL_FORCE) < 0) {
+            priv->beingDestroyed = false;
+            goto cleanup;
+        }
+
+        priv->beingDestroyed = false;
+
+        if (! virDomainObjIsActive(vm)) {
+            virReportError(VIR_ERR_OPERATION_INVALID,
+                           "%s", _("domain is not running"));
+            goto cleanup;
+        }
+
+        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_CRASHED, 0);
+        event = virDomainEventNewFromObj(vm,
+                                         VIR_DOMAIN_EVENT_STOPPED,
+                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
+
+        virDomainAuditStop(vm, "destroyed");
+
+        if (! vm->persistent) {
+            qemuDomainRemoveInactive(driver, vm);
+            vm = NULL;
+        }
+    }
+
+cleanup:
+    if (vm)
+        virObjectUnlock(vm);
+    if (event)
+        qemuDomainEventQueue(driver, event);
+    virObjectUnref(cfg);
+
+    return 0;
+}
 
 static qemuMonitorCallbacks monitorCallbacks = {
     .destroy = qemuProcessHandleMonitorDestroy,
@@ -1289,6 +1385,7 @@ static qemuMonitorCallbacks monitorCallbacks = {
     .domainPMSuspend = qemuProcessHandlePMSuspend,
     .domainBalloonChange = qemuProcessHandleBalloonChange,
     .domainPMSuspendDisk = qemuProcessHandlePMSuspendDisk,
+    .domainGUESTPanicked = qemuProcessHandleGUESTPanicked,
 };
 
 static int
@@ -2673,6 +2770,10 @@ qemuProcessUpdateState(virQEMUDriverPtr driver, virDomainObjPtr vm)
             newState = VIR_DOMAIN_SHUTDOWN;
             newReason = VIR_DOMAIN_SHUTDOWN_UNKNOWN;
             ignore_value(VIR_STRDUP_QUIET(msg, "shutdown"));
+        } else if (reason == VIR_DOMAIN_PAUSED_GUEST_PANICKED) {
+            newState = VIR_DOMAIN_CRASHED;
+            newReason = VIR_DOMAIN_CRASHED_PANICKED;
+            ignore_value(VIR_STRDUP_QUIET(msg, "was crashed"));
         } else {
             newState = VIR_DOMAIN_PAUSED;
             newReason = reason;
diff --git a/tools/virsh-domain-monitor.c b/tools/virsh-domain-monitor.c
index 5ed89d1..4bddefe 100644
--- a/tools/virsh-domain-monitor.c
+++ b/tools/virsh-domain-monitor.c
@@ -192,6 +192,8 @@ vshDomainStateReasonToString(int state, int reason)
             return N_("save canceled");
         case VIR_DOMAIN_RUNNING_WAKEUP:
             return N_("event wakeup");
+        case VIR_DOMAIN_RUNNING_CRASHED:
+            return N_("from crashed");
         case VIR_DOMAIN_RUNNING_UNKNOWN:
         case VIR_DOMAIN_RUNNING_LAST:
             ;
@@ -226,6 +228,8 @@ vshDomainStateReasonToString(int state, int reason)
             return N_("shutting down");
         case VIR_DOMAIN_PAUSED_SNAPSHOT:
             return N_("creating snapshot");
+        case VIR_DOMAIN_PAUSED_GUEST_PANICKED:
+            return N_("guest panicked");
         case VIR_DOMAIN_PAUSED_UNKNOWN:
         case VIR_DOMAIN_PAUSED_LAST:
             ;
@@ -236,6 +240,8 @@ vshDomainStateReasonToString(int state, int reason)
         switch ((virDomainShutdownReason) reason) {
         case VIR_DOMAIN_SHUTDOWN_USER:
             return N_("user");
+        case VIR_DOMAIN_SHUTDOWN_CRASHED:
+            return N_("crashed");
         case VIR_DOMAIN_SHUTDOWN_UNKNOWN:
         case VIR_DOMAIN_SHUTDOWN_LAST:
             ;
@@ -266,6 +272,8 @@ vshDomainStateReasonToString(int state, int reason)
 
     case VIR_DOMAIN_CRASHED:
         switch ((virDomainCrashedReason) reason) {
+        case VIR_DOMAIN_CRASHED_PANICKED:
+            return N_("panicked");
         case VIR_DOMAIN_CRASHED_UNKNOWN:
         case VIR_DOMAIN_CRASHED_LAST:
             ;
-- 
1.8.1.4




More information about the libvir-list mailing list