[libvirt] [PATCHv4 1/3] Introduce virDomain{Get,Set}Time APIs

Michal Privoznik mprivozn at redhat.com
Wed May 7 08:19:07 UTC 2014


These APIs allow users to get or set time in a domain, which may come
handy if the domain has been resumed just recently and NTP is not
configured or hasn't kicked in yet and the guest is running
something time critical. In addition, NTP may refuse to re-set the clock
if the skew is too big.

In addition, new ACL attribute is introduced 'set_time'.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 daemon/remote.c              | 37 +++++++++++++++++
 include/libvirt/libvirt.h.in | 14 +++++++
 src/access/viraccessperm.c   |  2 +-
 src/access/viraccessperm.h   |  7 +++-
 src/driver.h                 | 14 +++++++
 src/libvirt.c                | 94 ++++++++++++++++++++++++++++++++++++++++++++
 src/libvirt_public.syms      |  2 +
 src/remote/remote_driver.c   | 35 +++++++++++++++++
 src/remote/remote_protocol.x | 31 ++++++++++++++-
 src/remote_protocol-structs  | 16 ++++++++
 10 files changed, 249 insertions(+), 3 deletions(-)

diff --git a/daemon/remote.c b/daemon/remote.c
index 8476961..34c96c9 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -6077,6 +6077,43 @@ qemuDispatchConnectDomainMonitorEventDeregister(virNetServerPtr server ATTRIBUTE
     return rv;
 }
 
+static int
+remoteDispatchDomainGetTime(virNetServerPtr server ATTRIBUTE_UNUSED,
+                            virNetServerClientPtr client,
+                            virNetMessagePtr msg ATTRIBUTE_UNUSED,
+                            virNetMessageErrorPtr rerr,
+                            remote_domain_get_time_args *args,
+                            remote_domain_get_time_ret *ret)
+{
+    int rv = -1;
+    virDomainPtr dom = NULL;
+    long long seconds;
+    unsigned int nseconds;
+    struct daemonClientPrivate *priv =
+        virNetServerClientGetPrivateData(client);
+
+    if (!priv->conn) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("connection not open"));
+        goto cleanup;
+    }
+
+    if (!(dom = get_nonnull_domain(priv->conn, args->dom)))
+        goto cleanup;
+
+    if (virDomainGetTime(dom, &seconds, &nseconds, args->flags) < 0)
+        goto cleanup;
+
+    ret->seconds = seconds;
+    ret->nseconds = nseconds;
+    rv = 0;
+
+ cleanup:
+    if (rv < 0)
+        virNetMessageSaveError(rerr);
+    if (dom)
+        virDomainFree(dom);
+    return rv;
+}
 
 /*----- Helpers. -----*/
 
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 337ad71..260c971 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -5289,6 +5289,20 @@ int virDomainFSThaw(virDomainPtr dom,
                     unsigned int nmountpoints,
                     unsigned int flags);
 
+int virDomainGetTime(virDomainPtr dom,
+                     long long *seconds,
+                     unsigned int *nseconds,
+                     unsigned int flags);
+
+typedef enum {
+    VIR_DOMAIN_TIME_SYNC = (1 << 0), /* Re-sync domain time from domain's RTC */
+} virDomainSetTimeFlags;
+
+int virDomainSetTime(virDomainPtr dom,
+                     long long seconds,
+                     unsigned int nseconds,
+                     unsigned int flags);
+
 /**
  * virSchedParameterType:
  *
diff --git a/src/access/viraccessperm.c b/src/access/viraccessperm.c
index 8ca1edf..9007186 100644
--- a/src/access/viraccessperm.c
+++ b/src/access/viraccessperm.c
@@ -43,7 +43,7 @@ VIR_ENUM_IMPL(virAccessPermDomain,
               "fs_trim", "fs_freeze",
               "block_read", "block_write", "mem_read",
               "open_graphics", "open_device", "screenshot",
-              "open_namespace");
+              "open_namespace", "set_time");
 
 VIR_ENUM_IMPL(virAccessPermInterface,
               VIR_ACCESS_PERM_INTERFACE_LAST,
diff --git a/src/access/viraccessperm.h b/src/access/viraccessperm.h
index 50cea1e..8ccbbad 100644
--- a/src/access/viraccessperm.h
+++ b/src/access/viraccessperm.h
@@ -288,13 +288,18 @@ typedef enum {
      */
     VIR_ACCESS_PERM_DOMAIN_SCREENSHOT,    /* Trigger a screen shot */
 
-
     /**
      * @desc: Open domain namespace
      * @message: Opening domain namespaces requires authorization
      */
     VIR_ACCESS_PERM_DOMAIN_OPEN_NAMESPACE,
 
+    /**
+     * @desc: Write domain time
+     * @message: Setting the domain time requires authorization
+     */
+    VIR_ACCESS_PERM_DOMAIN_SET_TIME,
+
     VIR_ACCESS_PERM_DOMAIN_LAST,
 } virAccessPermDomain;
 
diff --git a/src/driver.h b/src/driver.h
index 502f30e..5ac89d6 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -1084,6 +1084,18 @@ typedef int
                       unsigned int flags);
 
 typedef int
+(*virDrvDomainGetTime)(virDomainPtr dom,
+                       long long *seconds,
+                       unsigned int *nseconds,
+                       unsigned int flags);
+
+typedef int
+(*virDrvDomainSetTime)(virDomainPtr dom,
+                       long long seconds,
+                       unsigned int nseconds,
+                       unsigned int flags);
+
+typedef int
 (*virDrvDomainLxcOpenNamespace)(virDomainPtr dom,
                                 int **fdlist,
                                 unsigned int flags);
@@ -1377,6 +1389,8 @@ struct _virDriver {
     virDrvConnectGetCPUModelNames connectGetCPUModelNames;
     virDrvDomainFSFreeze domainFSFreeze;
     virDrvDomainFSThaw domainFSThaw;
+    virDrvDomainGetTime domainGetTime;
+    virDrvDomainSetTime domainSetTime;
 };
 
 
diff --git a/src/libvirt.c b/src/libvirt.c
index 2cd793c..ccb7113 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -20791,3 +20791,97 @@ virDomainFSThaw(virDomainPtr dom,
     virDispatchError(dom->conn);
     return -1;
 }
+
+/**
+ * virDomainGetTime:
+ * @dom: a domain object
+ * @seconds: domain's time in seconds
+ * @nseconds: the nanoscond part of @seconds
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Extract information about guest time and store it into
+ * @seconds and @nseconds. The @seconds represents the number of
+ * seconds since the UNIX Epoch of 1970-01-01 00:00:00 in UTC.
+ *
+ * Please note that some hypervisors may require guest agent to
+ * be configured and running in order to run this API.
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+int
+virDomainGetTime(virDomainPtr dom,
+                 long long *seconds,
+                 unsigned int *nseconds,
+                 unsigned int flags)
+{
+    VIR_DOMAIN_DEBUG(dom, "seconds=%p, nseconds=%p, flags=%x",
+                     seconds, nseconds, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+
+    if (dom->conn->driver->domainGetTime) {
+        int ret = dom->conn->driver->domainGetTime(dom, seconds,
+                                                   nseconds, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
+
+/**
+ * virDomainSetTime:
+ * @dom: a domain object
+ * @seconds: time to set
+ * @nseconds: the nanosecond part of @seconds
+ * @flags: bitwise-OR of virDomainSetTimeFlags
+ *
+ * When a domain is suspended or restored from a file the
+ * domain's OS has no idea that there was a big gap in the time.
+ * Depending on how long the gap was, NTP might not be able to
+ * resynchronize the guest.
+ *
+ * This API tries to set guest time to the given value. The time
+ * to set (@seconds and @nseconds) should be in seconds relative
+ * to the Epoch of 1970-01-01 00:00:00 in UTC.
+ *
+ * Please note that some hypervisors may require guest agent to
+ * be configured and running in order to be able to run this API.
+ *
+ * Returns 0 on success, -1 otherwise.
+ */
+int
+virDomainSetTime(virDomainPtr dom,
+                 long long seconds,
+                 unsigned int nseconds,
+                 unsigned int flags)
+{
+    VIR_DOMAIN_DEBUG(dom, "seconds=%lld, nseconds=%u, flags=%x",
+                     seconds, nseconds, flags);
+
+    virResetLastError();
+
+    virCheckDomainReturn(dom, -1);
+    virCheckReadOnlyGoto(dom->conn->flags, error);
+
+    if (dom->conn->driver->domainSetTime) {
+        int ret = dom->conn->driver->domainSetTime(dom, seconds,
+                                                   nseconds, flags);
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(dom->conn);
+    return -1;
+}
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index f8113f4..cce6bdf 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -654,6 +654,8 @@ LIBVIRT_1.2.5 {
     global:
         virDomainFSFreeze;
         virDomainFSThaw;
+        virDomainGetTime;
+        virDomainSetTime;
 } LIBVIRT_1.2.3;
 
 
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 4c3b38a..85fe597 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -7435,6 +7435,39 @@ remoteDomainCreateWithFiles(virDomainPtr dom,
     return rv;
 }
 
+static int
+remoteDomainGetTime(virDomainPtr dom,
+                    long long *seconds,
+                    unsigned int *nseconds,
+                    unsigned int flags)
+{
+    int rv = -1;
+    struct private_data *priv = dom->conn->privateData;
+    remote_domain_get_time_args args;
+    remote_domain_get_time_ret ret;
+
+    remoteDriverLock(priv);
+
+    make_nonnull_domain(&args.dom, dom);
+    args.flags = flags;
+
+    *seconds = *nseconds = 0;
+
+    if (call(dom->conn, priv, 0, REMOTE_PROC_DOMAIN_GET_TIME,
+             (xdrproc_t) xdr_remote_domain_get_time_args, (char *) &args,
+             (xdrproc_t) xdr_remote_domain_get_time_ret, (char *) &ret) == -1)
+        goto cleanup;
+
+    *seconds = ret.seconds;
+    *nseconds = ret.nseconds;
+    xdr_free((xdrproc_t) &xdr_remote_domain_get_time_ret, (char *) &ret);
+    rv = 0;
+
+ cleanup:
+    remoteDriverUnlock(priv);
+    return rv;
+}
+
 
 /* get_nonnull_domain and get_nonnull_network turn an on-wire
  * (name, uuid) pair into virDomainPtr or virNetworkPtr object.
@@ -7770,6 +7803,8 @@ static virDriver remote_driver = {
     .connectGetCPUModelNames = remoteConnectGetCPUModelNames, /* 1.1.3 */
     .domainFSFreeze = remoteDomainFSFreeze, /* 1.2.5 */
     .domainFSThaw = remoteDomainFSThaw, /* 1.2.5 */
+    .domainGetTime = remoteDomainGetTime, /* 1.2.5 */
+    .domainSetTime = remoteDomainSetTime, /* 1.2.5 */
 };
 
 static virNetworkDriver network_driver = {
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 608490c..1f9d583 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -2855,6 +2855,23 @@ struct remote_domain_fstrim_args {
     unsigned int flags;
 };
 
+struct remote_domain_get_time_args {
+    remote_nonnull_domain dom;
+    unsigned int flags;
+};
+
+struct remote_domain_get_time_ret {
+    hyper seconds;
+    unsigned int nseconds;
+};
+
+struct remote_domain_set_time_args {
+    remote_nonnull_domain dom;
+    hyper seconds;
+    unsigned int nseconds;
+    unsigned int flags;
+};
+
 struct remote_domain_migrate_begin3_params_args {
     remote_nonnull_domain dom;
     remote_typed_param params<REMOTE_DOMAIN_MIGRATE_PARAM_LIST_MAX>;
@@ -5309,5 +5326,17 @@ enum remote_procedure {
      * @generate: both
      * @acl: domain:fs_freeze
      */
-    REMOTE_PROC_DOMAIN_FSTHAW = 336
+    REMOTE_PROC_DOMAIN_FSTHAW = 336,
+
+    /**
+     * @generate: none
+     * @acl: domain:read
+     */
+    REMOTE_PROC_DOMAIN_GET_TIME = 337,
+
+    /**
+     * @generate: both
+     * @acl: domain:set_time
+     */
+    REMOTE_PROC_DOMAIN_SET_TIME = 338
 };
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index b62871f..5b22049 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -2290,6 +2290,20 @@ struct remote_domain_fstrim_args {
         uint64_t                   minimum;
         u_int                      flags;
 };
+struct remote_domain_get_time_args {
+        remote_nonnull_domain      dom;
+        u_int                      flags;
+};
+struct remote_domain_get_time_ret {
+        int64_t                    seconds;
+        u_int                      nseconds;
+};
+struct remote_domain_set_time_args {
+        remote_nonnull_domain      dom;
+        int64_t                    seconds;
+        u_int                      nseconds;
+        u_int                      flags;
+};
 struct remote_domain_migrate_begin3_params_args {
         remote_nonnull_domain      dom;
         struct {
@@ -2786,4 +2800,6 @@ enum remote_procedure {
         REMOTE_PROC_DOMAIN_CORE_DUMP_WITH_FORMAT = 334,
         REMOTE_PROC_DOMAIN_FSFREEZE = 335,
         REMOTE_PROC_DOMAIN_FSTHAW = 336,
+        REMOTE_PROC_DOMAIN_GET_TIME = 337,
+        REMOTE_PROC_DOMAIN_SET_TIME = 338,
 };
-- 
1.9.0




More information about the libvir-list mailing list