Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src Synchronize the clock periodically in vmt(4).



details:   https://anonhg.NetBSD.org/src/rev/67c3b6a4c303
branches:  trunk
changeset: 785482:67c3b6a4c303
user:      jmmv <jmmv%NetBSD.org@localhost>
date:      Sat Mar 16 01:26:52 2013 +0000

description:
Synchronize the clock periodically in vmt(4).

Add periodic clock synchronization to vmt(4) so that the guest clock
remains synchronized even when the host is suspended (which is a very
typical situation in a laptop).

Do this by default once per minute, but provide a sysctl to tune this
value (machdep.vmt0.clock_sync.period).

Sent to tech-kern@ for review and addressed a couple of issues.

diffstat:

 doc/CHANGES                   |    4 +-
 share/man/man4/man4.x86/vmt.4 |   23 ++++++-
 sys/arch/x86/x86/vmt.c        |  131 +++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 154 insertions(+), 4 deletions(-)

diffs (274 lines):

diff -r 7935c06426a5 -r 67c3b6a4c303 doc/CHANGES
--- a/doc/CHANGES       Sat Mar 16 01:00:16 2013 +0000
+++ b/doc/CHANGES       Sat Mar 16 01:26:52 2013 +0000
@@ -1,4 +1,4 @@
-# LIST OF CHANGES FROM LAST RELEASE:                   <$Revision: 1.1802 $>
+# LIST OF CHANGES FROM LAST RELEASE:                   <$Revision: 1.1803 $>
 #
 #
 # [Note: This file does not mention every change made to the NetBSD source tree.
@@ -210,3 +210,5 @@
        zoneinfo: Import tzdata2013a. [apb 20130303]
        zoneinfo: Import tzdata2013b. [apb 20130312]
        libc: Update to tzcode2013b. [christos 20130315]
+       vmt(4): Synchronize the clock periodically to ensure it remains
+               up-to-date even when the host is suspended.  [jmmv 20130316]
diff -r 7935c06426a5 -r 67c3b6a4c303 share/man/man4/man4.x86/vmt.4
--- a/share/man/man4/man4.x86/vmt.4     Sat Mar 16 01:00:16 2013 +0000
+++ b/share/man/man4/man4.x86/vmt.4     Sat Mar 16 01:26:52 2013 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: vmt.4,v 1.3 2011/10/18 14:25:06 wiz Exp $
+.\"    $NetBSD: vmt.4,v 1.4 2013/03/16 01:26:53 jmmv Exp $
 .\"    $OpenBSD: vmt.4,v 1.4 2010/10/26 05:07:31 jmc Exp $
 .\"
 .\" Copyright (c) 2008 Marco Peereboom <marco%openbsd.org@localhost>
@@ -15,7 +15,7 @@
 .\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 .\" ACTION OF CONTRACT, NEGLIGENCE OR TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-.Dd October 18, 2011
+.Dd March 16, 2013
 .Dt VMT 4 x86
 .Os
 .Sh NAME
@@ -44,6 +44,25 @@
 .Pp
 .Nm
 reports the guest's hostname and first non-loopback IP address to the host.
+.Ss Clock synchronization
+The
+.Nm
+driver synchronizes the virtual machine's clock with the host clock in the
+following situations:
+.Bl -bullet
+.It
+When the virtual machine resumes after having been suspended.
+.It
+Periodically with the interval indicated by the
+.Va machdep.vmt0.clock_sync.period
+.Xr sysctl 8
+variable.
+This is done so that the virtual machine can keep its clock synchronized
+when the host is suspended, because in this case the
+.Nm
+driver receives no notification of such an event.
+Setting this tunable to zero disables clock synchronization.
+.El
 .Sh SEE ALSO
 .\" .Xr cpu 4 ,
 .Xr powerd 8
diff -r 7935c06426a5 -r 67c3b6a4c303 sys/arch/x86/x86/vmt.c
--- a/sys/arch/x86/x86/vmt.c    Sat Mar 16 01:00:16 2013 +0000
+++ b/sys/arch/x86/x86/vmt.c    Sat Mar 16 01:26:52 2013 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: vmt.c,v 1.7 2011/10/21 10:10:28 jmcneill Exp $ */
+/* $NetBSD: vmt.c,v 1.8 2013/03/16 01:26:53 jmmv Exp $ */
 /* $OpenBSD: vmt.c,v 1.11 2011/01/27 21:29:25 dtucker Exp $ */
 
 /*
@@ -36,6 +36,7 @@
 #include <sys/socket.h>
 #include <sys/timetc.h>
 #include <sys/module.h>
+#include <sys/sysctl.h>
 
 #include <net/if.h>
 #include <netinet/in.h>
@@ -182,6 +183,7 @@
 struct vmt_softc {
        device_t                sc_dev;
 
+       struct sysctllog        *sc_log;
        struct vm_rpc           sc_tclo_rpc;
        bool                    sc_tclo_rpc_open;
        char                    *sc_rpc_buf;
@@ -193,6 +195,10 @@
        struct callout          sc_tick;
        struct callout          sc_tclo_tick;
 
+#define VMT_CLOCK_SYNC_PERIOD_SECONDS 60
+       int                     sc_clock_sync_period_seconds;
+       struct callout          sc_clock_sync_tick;
+
        struct vmt_event        sc_ev_power;
        struct vmt_event        sc_ev_reset;
        struct vmt_event        sc_ev_sleep;
@@ -204,6 +210,10 @@
 CFATTACH_DECL_NEW(vmt, sizeof(struct vmt_softc),
        vmt_match, vmt_attach, vmt_detach, NULL);
 
+static int vmt_sysctl_setup_root(device_t);
+static int vmt_sysctl_setup_clock_sync(device_t, const struct sysctlnode *);
+static int vmt_sysctl_update_clock_sync_period(SYSCTLFN_PROTO);
+
 static void vm_cmd(struct vm_backdoor *);
 static void vm_ins(struct vm_backdoor *);
 static void vm_outs(struct vm_backdoor *);
@@ -230,6 +240,7 @@
 
 static void vmt_tick(void *);
 static void vmt_tclo_tick(void *);
+static void vmt_clock_sync_tick(void *);
 static bool vmt_shutdown(device_t, int);
 static void vmt_pswitch_event(void *);
 
@@ -294,14 +305,27 @@
 static void
 vmt_attach(device_t parent, device_t self, void *aux)
 {
+       int rv;
        struct vmt_softc *sc = device_private(self);
 
        aprint_naive("\n");
        aprint_normal(": %s\n", vmt_type());
 
        sc->sc_dev = self;
+       sc->sc_log = NULL;
+
        callout_init(&sc->sc_tick, 0);
        callout_init(&sc->sc_tclo_tick, 0);
+       callout_init(&sc->sc_clock_sync_tick, 0);
+
+       sc->sc_clock_sync_period_seconds = VMT_CLOCK_SYNC_PERIOD_SECONDS;
+
+       rv = vmt_sysctl_setup_root(self);
+       if (rv != 0) {
+               aprint_error_dev(self, "failed to initialize sysctl "
+                   "(err %d)\n", rv);
+               goto free;
+       }
 
        sc->sc_rpc_buf = kmem_alloc(VMT_RPC_BUFLEN, KM_SLEEP);
        if (sc->sc_rpc_buf == NULL) {
@@ -346,6 +370,10 @@
        callout_schedule(&sc->sc_tclo_tick, hz);
        sc->sc_tclo_ping = 1;
 
+       callout_setfunc(&sc->sc_clock_sync_tick, vmt_clock_sync_tick, sc);
+       callout_schedule(&sc->sc_clock_sync_tick,
+           mstohz(sc->sc_clock_sync_period_seconds * 1000));
+
        vmt_sync_guest_clock(sc);
 
        return;
@@ -354,6 +382,8 @@
        if (sc->sc_rpc_buf)
                kmem_free(sc->sc_rpc_buf, VMT_RPC_BUFLEN);
        pmf_device_register(self, NULL, NULL);
+       if (sc->sc_log)
+               sysctl_teardown(&sc->sc_log);
 }
 
 static int
@@ -376,12 +406,111 @@
        callout_halt(&sc->sc_tclo_tick, NULL);
        callout_destroy(&sc->sc_tclo_tick);
 
+       callout_halt(&sc->sc_clock_sync_tick, NULL);
+       callout_destroy(&sc->sc_clock_sync_tick);
+
        if (sc->sc_rpc_buf)
                kmem_free(sc->sc_rpc_buf, VMT_RPC_BUFLEN);
 
+       if (sc->sc_log) {
+               sysctl_teardown(&sc->sc_log);
+               sc->sc_log = NULL;
+       }
+
        return 0;
 }
 
+static int
+vmt_sysctl_setup_root(device_t self)
+{
+       const struct sysctlnode *machdep_node, *vmt_node;
+       struct vmt_softc *sc = device_private(self);
+       int rv;
+
+       rv = sysctl_createv(&sc->sc_log, 0, NULL, &machdep_node,
+           CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
+           NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL);
+       if (rv != 0)
+               goto fail;
+
+       rv = sysctl_createv(&sc->sc_log, 0, &machdep_node, &vmt_node,
+           0, CTLTYPE_NODE, device_xname(self), NULL,
+           NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
+       if (rv != 0)
+               goto fail;
+
+       rv = vmt_sysctl_setup_clock_sync(self, vmt_node);
+       if (rv != 0)
+               goto fail;
+
+       return 0;
+
+fail:
+       sysctl_teardown(&sc->sc_log);
+       sc->sc_log = NULL;
+
+       return rv;
+}
+
+static int
+vmt_sysctl_setup_clock_sync(device_t self, const struct sysctlnode *root_node)
+{
+       const struct sysctlnode *node, *period_node;
+       struct vmt_softc *sc = device_private(self);
+       int rv;
+
+       rv = sysctl_createv(&sc->sc_log, 0, &root_node, &node,
+           0, CTLTYPE_NODE, "clock_sync", NULL,
+           NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL);
+       if (rv != 0)
+               return rv;
+
+       rv = sysctl_createv(&sc->sc_log, 0, &node, &period_node,
+           CTLFLAG_READWRITE, CTLTYPE_INT, "period",
+           SYSCTL_DESCR("Period, in seconds, at which to update the "
+               "guest's clock"),
+           vmt_sysctl_update_clock_sync_period, 0, (void *)sc, 0,
+           CTL_CREATE, CTL_EOL);
+       return rv;
+}
+
+static int
+vmt_sysctl_update_clock_sync_period(SYSCTLFN_ARGS)
+{
+       int error, period;
+       struct sysctlnode node;
+       struct vmt_softc *sc;
+
+       node = *rnode;
+       sc = (struct vmt_softc *)node.sysctl_data;
+
+       period = sc->sc_clock_sync_period_seconds;
+       node.sysctl_data = &period;
+       error = sysctl_lookup(SYSCTLFN_CALL(&node));
+       if (error || newp == NULL)
+               return error;
+
+       if (sc->sc_clock_sync_period_seconds != period) {
+               callout_halt(&sc->sc_clock_sync_tick, NULL);
+               sc->sc_clock_sync_period_seconds = period;
+               if (sc->sc_clock_sync_period_seconds > 0)
+                       callout_schedule(&sc->sc_clock_sync_tick,
+                           mstohz(sc->sc_clock_sync_period_seconds * 1000));
+       }
+       return 0;
+}
+
+static void
+vmt_clock_sync_tick(void *xarg)
+{
+       struct vmt_softc *sc = xarg;
+
+       vmt_sync_guest_clock(sc);
+
+       callout_schedule(&sc->sc_clock_sync_tick,
+           mstohz(sc->sc_clock_sync_period_seconds * 1000));
+}
+
 static void
 vmt_update_guest_uptime(struct vmt_softc *sc)
 {



Home | Main Index | Thread Index | Old Index