Have our dom0 periodically set Xen's time-of-day clock (much as Linux does).
That time is used by ~all domUs when they boot (or resume), and Linux by default will pin the local clock to it; so, it's useful to correct its drift as best we can. A sysctl (machdep.xen_timepush_ticks) has been added to allow changing the interval or disabling this feature.
This commit is contained in:
parent
0f4e4cae54
commit
78e3490d47
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: clock.c,v 1.22 2006/04/28 02:30:42 jld Exp $ */
|
||||
/* $NetBSD: clock.c,v 1.23 2006/05/05 19:38:38 jld Exp $ */
|
||||
|
||||
/*
|
||||
*
|
||||
@ -34,13 +34,14 @@
|
||||
#include "opt_xen.h"
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.22 2006/04/28 02:30:42 jld Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.23 2006/05/05 19:38:38 jld Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/device.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <machine/xen.h>
|
||||
#include <machine/hypervisor.h>
|
||||
@ -69,6 +70,12 @@ static int timeset;
|
||||
|
||||
static uint64_t processed_system_time;
|
||||
|
||||
#ifdef DOM0OPS
|
||||
/* If we're dom0, send our time to Xen every minute or so. */
|
||||
int xen_timepush_ticks = 0;
|
||||
static struct callout xen_timepush_co = CALLOUT_INITIALIZER;
|
||||
#endif
|
||||
|
||||
#define NS_PER_TICK (1000000000ULL/hz)
|
||||
|
||||
/*
|
||||
@ -171,15 +178,15 @@ fstime:
|
||||
printf("WARNING: CHECK AND RESET THE DATE!\n");
|
||||
}
|
||||
|
||||
void
|
||||
resettodr()
|
||||
static void
|
||||
resettodr_i(void)
|
||||
{
|
||||
#ifdef DOM0OPS
|
||||
dom0_op_t op;
|
||||
int s;
|
||||
#endif
|
||||
#ifdef DEBUG_CLOCK
|
||||
struct clock_ymdhms dt;
|
||||
struct timeval sent_delta;
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -190,10 +197,19 @@ resettodr()
|
||||
return;
|
||||
|
||||
#ifdef DEBUG_CLOCK
|
||||
clock_secs_to_ymdhms(time.tv_sec - rtc_offset * 60, &dt);
|
||||
|
||||
printf("setclock: %d/%d/%d %02d:%02d:%02d\n", dt.dt_year,
|
||||
dt.dt_mon, dt.dt_day, dt.dt_hour, dt.dt_min, dt.dt_sec);
|
||||
{
|
||||
char pm;
|
||||
|
||||
if (timercmp(&time, &shadow_tv, >)) {
|
||||
timersub(&time, &shadow_tv, &sent_delta);
|
||||
pm = '+';
|
||||
} else {
|
||||
timersub(&shadow_tv, &time, &sent_delta);
|
||||
pm = '-';
|
||||
}
|
||||
printf("resettodr: stepping Xen clock by %c%ld.%06ld\n",
|
||||
pm, sent_delta.tv_sec, sent_delta.tv_usec);
|
||||
}
|
||||
#endif
|
||||
#ifdef DOM0OPS
|
||||
if (xen_start_info.flags & SIF_PRIVILEGED) {
|
||||
@ -214,6 +230,22 @@ resettodr()
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* When the clock is administratively set, in addition to resetting
|
||||
* Xen's clock if possible, we should also allow xen_microtime to
|
||||
* step backwards without complaint.
|
||||
*/
|
||||
void
|
||||
resettodr()
|
||||
{
|
||||
CPU_INFO_ITERATOR cii;
|
||||
struct cpu_info *ci;
|
||||
|
||||
resettodr_i();
|
||||
for (CPU_INFO_FOREACH(cii, ci))
|
||||
timerclear(&ci->ci_cc.cc_time);
|
||||
}
|
||||
|
||||
void
|
||||
startrtclock()
|
||||
{
|
||||
@ -301,11 +333,12 @@ xen_microtime(struct timeval *tv)
|
||||
tv->tv_sec++;
|
||||
tv->tv_usec -= 1000000;
|
||||
}
|
||||
/* Avoid backsteps, e.g. at the beginning of a negative adjustment. */
|
||||
/* Avoid small backsteps, e.g. at the beginning of a negative adjustment. */
|
||||
if (timerisset(&ci->ci_cc.cc_time) &&
|
||||
timercmp(tv, &ci->ci_cc.cc_time, <)) {
|
||||
struct timeval backstep; /* XXX hook resettodr() instead of doing this. */
|
||||
struct timeval backstep;
|
||||
|
||||
/* XXXjld: not sure if this check can be safely removed now */
|
||||
timersub(&ci->ci_cc.cc_time, tv, &backstep);
|
||||
if (backstep.tv_sec == 0) { /* if it was < 1sec */
|
||||
*tv = ci->ci_cc.cc_time;
|
||||
@ -323,11 +356,52 @@ xen_microtime(struct timeval *tv)
|
||||
splx(s);
|
||||
}
|
||||
|
||||
#ifdef DOM0OPS
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
xen_timepush(void *arg)
|
||||
{
|
||||
struct callout *co = arg;
|
||||
|
||||
resettodr_i();
|
||||
if (xen_timepush_ticks > 0)
|
||||
callout_schedule(co, xen_timepush_ticks);
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static int
|
||||
sysctl_xen_timepush(SYSCTLFN_ARGS)
|
||||
{
|
||||
int error, new_ticks;
|
||||
struct sysctlnode node;
|
||||
|
||||
new_ticks = xen_timepush_ticks;
|
||||
node = *rnode;
|
||||
node.sysctl_data = &new_ticks;
|
||||
error = sysctl_lookup(SYSCTLFN_CALL(&node));
|
||||
if (error || newp == NULL)
|
||||
return error;
|
||||
|
||||
if (new_ticks < 0)
|
||||
return EINVAL;
|
||||
if (new_ticks != xen_timepush_ticks) {
|
||||
xen_timepush_ticks = new_ticks;
|
||||
if (new_ticks > 0)
|
||||
callout_schedule(&xen_timepush_co, new_ticks);
|
||||
else
|
||||
callout_stop(&xen_timepush_co);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
xen_initclocks()
|
||||
{
|
||||
int evtch = bind_virq_to_evtch(VIRQ_TIMER);
|
||||
int evtch;
|
||||
|
||||
evtch = bind_virq_to_evtch(VIRQ_TIMER);
|
||||
aprint_verbose("Xen clock: using event channel %d\n", evtch);
|
||||
|
||||
get_time_values_from_xen();
|
||||
@ -336,6 +410,19 @@ xen_initclocks()
|
||||
event_set_handler(evtch, (int (*)(void *))xen_timer_handler,
|
||||
NULL, IPL_CLOCK, "clock");
|
||||
hypervisor_enable_event(evtch);
|
||||
|
||||
#ifdef DOM0OPS
|
||||
xen_timepush_ticks = 53 * hz + 3; /* avoid exact # of min/sec */
|
||||
if (xen_start_info.flags & SIF_PRIVILEGED) {
|
||||
sysctl_createv(NULL, 0, NULL, NULL, CTLFLAG_READWRITE,
|
||||
CTLTYPE_INT, "xen_timepush_ticks", SYSCTL_DESCR("How often"
|
||||
" to update the hypervisor's time-of-day; 0 to disable"),
|
||||
sysctl_xen_timepush, 0, &xen_timepush_ticks, 0,
|
||||
CTL_MACHDEP, CTL_CREATE, CTL_EOL);
|
||||
callout_reset(&xen_timepush_co, xen_timepush_ticks,
|
||||
&xen_timepush, &xen_timepush_co);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
|
Loading…
Reference in New Issue
Block a user