Page MenuHomeFreeBSD

D7745.diff
No OneTemporary

D7745.diff

Index: head/sys/dev/hyperv/utilities/hv_timesync.c
===================================================================
--- head/sys/dev/hyperv/utilities/hv_timesync.c
+++ head/sys/dev/hyperv/utilities/hv_timesync.c
@@ -22,37 +22,25 @@
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD$
*/
-/*
- * A common driver for all hyper-V util services.
- */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include <sys/param.h>
-#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/malloc.h>
+#include <sys/kernel.h>
#include <sys/module.h>
-#include <sys/reboot.h>
-#include <sys/timetc.h>
#include <sys/syscallsubr.h>
-#include <sys/systm.h>
#include <sys/sysctl.h>
+#include <sys/systm.h>
#include <dev/hyperv/include/hyperv.h>
#include <dev/hyperv/include/vmbus.h>
-#include <dev/hyperv/utilities/hv_utilreg.h>
-#include "hv_util.h"
-#include "vmbus_if.h"
+#include <dev/hyperv/utilities/hv_util.h>
+#include <dev/hyperv/utilities/vmbus_icreg.h>
-#define HV_WLTIMEDELTA 116444736000000000L /* in 100ns unit */
-#define HV_ICTIMESYNCFLAG_PROBE 0
-#define HV_ICTIMESYNCFLAG_SYNC 1
-#define HV_ICTIMESYNCFLAG_SAMPLE 2
-#define HV_NANO_SEC_PER_SEC 1000000000
-#define HV_NANO_SEC_PER_MILLI_SEC 1000000
+#include "vmbus_if.h"
static const struct vmbus_ic_desc vmbus_timesync_descs[] = {
{
@@ -64,135 +52,144 @@
VMBUS_IC_DESC_END
};
-struct hv_ictimesync_data {
- uint64_t parenttime;
- uint64_t childtime;
- uint64_t roundtriptime;
- uint8_t flags;
-} __packed;
-
-/*
- * Globals
- */
SYSCTL_NODE(_hw, OID_AUTO, hvtimesync, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
"Hyper-V timesync interface");
-/* Ignore the sync request when set to 1. */
-static int ignore_sync_req = 0;
-SYSCTL_INT(_hw_hvtimesync, OID_AUTO, ignore_sync_req, CTLFLAG_RWTUN,
- &ignore_sync_req, 0,
- "Ignore the sync request when set to 1.");
+static int vmbus_ts_ignore_sync = 0;
+SYSCTL_INT(_hw_hvtimesync, OID_AUTO, ignore_sync, CTLFLAG_RWTUN,
+ &vmbus_ts_ignore_sync, 0, "Ignore the sync request.");
/*
* Trigger sample sync when drift exceeds threshold (ms).
* Ignore the sample request when set to 0.
*/
-static int sample_drift = 100;
-SYSCTL_INT(_hw_hvtimesync, OID_AUTO, sample_drift, CTLFLAG_RWTUN,
- &sample_drift, 0,
- "Threshold that makes sample request trigger the sync.");
+static int vmbus_ts_sample_thresh = 100;
+SYSCTL_INT(_hw_hvtimesync, OID_AUTO, sample_thresh, CTLFLAG_RWTUN,
+ &vmbus_ts_sample_thresh, 0,
+ "Threshold that makes sample request trigger the sync (unit: ms).");
+
+static int vmbus_ts_sample_verbose = 0;
+SYSCTL_INT(_hw_hvtimesync, OID_AUTO, sample_verbose, CTLFLAG_RWTUN,
+ &vmbus_ts_sample_verbose, 0, "Increase sample request verbosity.");
-/**
- * @brief Synchronize time with host after reboot, restore, etc.
- *
- * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM.
- * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time
- * message after the timesync channel is opened. Since the hv_utils module is
- * loaded after hv_vmbus, the first message is usually missed. The other
- * thing is, systime is automatically set to emulated hardware clock which may
- * not be UTC time or in the same time zone. So, to override these effects, we
- * use the first 50 time samples for initial system time setting.
- */
-static inline
-void hv_adj_guesttime(hv_util_sc *sc, uint64_t hosttime, uint8_t flags)
+static void
+vmbus_timesync(struct hv_util_sc *sc, uint64_t hvtime, uint8_t tsflags)
{
- struct timespec guest_ts, host_ts;
- uint64_t host_tns, guest_tns;
- int64_t diff;
- int error;
-
- host_tns = (hosttime - HV_WLTIMEDELTA) * 100;
- host_ts.tv_sec = (time_t)(host_tns/HV_NANO_SEC_PER_SEC);
- host_ts.tv_nsec = (long)(host_tns%HV_NANO_SEC_PER_SEC);
+ struct timespec vm_ts;
+ uint64_t hv_ns, vm_ns;
- nanotime(&guest_ts);
- guest_tns = guest_ts.tv_sec * HV_NANO_SEC_PER_SEC + guest_ts.tv_nsec;
+ hv_ns = (hvtime - VMBUS_ICMSG_TS_BASE) * VMBUS_ICMSG_TS_FACTOR;
+ nanotime(&vm_ts);
+ vm_ns = (vm_ts.tv_sec * NANOSEC) + vm_ts.tv_nsec;
+
+ if ((tsflags & VMBUS_ICMSG_TS_FLAG_SYNC) && !vmbus_ts_ignore_sync) {
+ struct timespec hv_ts;
- if ((flags & HV_ICTIMESYNCFLAG_SYNC) != 0 && ignore_sync_req == 0) {
if (bootverbose) {
- device_printf(sc->ic_dev, "handle sync request "
- "{host: %ju, guest: %ju}\n",
- (uintmax_t)host_tns, (uintmax_t)guest_tns);
+ device_printf(sc->ic_dev, "apply sync request, "
+ "hv: %ju, vm: %ju\n",
+ (uintmax_t)hv_ns, (uintmax_t)vm_ns);
}
-
- error = kern_clock_settime(curthread, CLOCK_REALTIME,
- &host_ts);
+ hv_ts.tv_sec = hv_ns / NANOSEC;
+ hv_ts.tv_nsec = hv_ns % NANOSEC;
+ kern_clock_settime(curthread, CLOCK_REALTIME, &hv_ts);
+ /* Done! */
return;
}
- if ((flags & HV_ICTIMESYNCFLAG_SAMPLE) != 0 && sample_drift != 0) {
- if (bootverbose) {
- device_printf(sc->ic_dev, "handle sample request "
- "{host: %ju, guest: %ju}\n",
- (uintmax_t)host_tns, (uintmax_t)guest_tns);
+ if ((tsflags & VMBUS_ICMSG_TS_FLAG_SAMPLE) &&
+ vmbus_ts_sample_thresh > 0) {
+ int64_t diff;
+
+ if (vmbus_ts_sample_verbose) {
+ device_printf(sc->ic_dev, "sample request, "
+ "hv: %ju, vm: %ju\n",
+ (uintmax_t)hv_ns, (uintmax_t)vm_ns);
}
- diff = (int64_t)(host_tns - guest_tns) / HV_NANO_SEC_PER_MILLI_SEC;
- if (diff > sample_drift || diff < -sample_drift) {
- error = kern_clock_settime(curthread, CLOCK_REALTIME,
- &host_ts);
- if (bootverbose)
- device_printf(sc->ic_dev, "trigger sample sync");
+ if (hv_ns > vm_ns)
+ diff = hv_ns - vm_ns;
+ else
+ diff = vm_ns - hv_ns;
+ /* nanosec -> millisec */
+ diff /= 1000000;
+
+ if (diff > vmbus_ts_sample_thresh) {
+ struct timespec hv_ts;
+
+ if (bootverbose) {
+ device_printf(sc->ic_dev,
+ "apply sample request, hv: %ju, vm: %ju\n",
+ (uintmax_t)hv_ns, (uintmax_t)vm_ns);
+ }
+ hv_ts.tv_sec = hv_ns / NANOSEC;
+ hv_ts.tv_nsec = hv_ns % NANOSEC;
+ kern_clock_settime(curthread, CLOCK_REALTIME, &hv_ts);
}
+ /* Done */
return;
}
}
-/**
- * Time Sync Channel message handler
- */
static void
-hv_timesync_cb(struct vmbus_channel *channel, void *context)
+vmbus_timesync_cb(struct vmbus_channel *chan, void *xsc)
{
- hv_vmbus_icmsg_hdr* icmsghdrp;
- uint32_t recvlen;
- uint64_t requestId;
- int ret;
- uint8_t* time_buf;
- struct hv_ictimesync_data* timedatap;
- hv_util_sc *softc;
-
- softc = (hv_util_sc*)context;
- time_buf = softc->receive_buffer;
-
- recvlen = softc->ic_buflen;
- ret = vmbus_chan_recv(channel, time_buf, &recvlen, &requestId);
- KASSERT(ret != ENOBUFS, ("hvtimesync recvbuf is not large enough"));
- /* XXX check recvlen to make sure that it contains enough data */
-
- if ((ret == 0) && recvlen > 0) {
- icmsghdrp = (struct hv_vmbus_icmsg_hdr *) &time_buf[
- sizeof(struct hv_vmbus_pipe_hdr)];
+ struct hv_util_sc *sc = xsc;
+ struct vmbus_icmsg_hdr *hdr;
+ const struct vmbus_icmsg_timesync *msg;
+ int dlen, error;
+ uint64_t xactid;
+ void *data;
+
+ /*
+ * Receive request.
+ */
+ data = sc->receive_buffer;
+ dlen = sc->ic_buflen;
+ error = vmbus_chan_recv(chan, data, &dlen, &xactid);
+ KASSERT(error != ENOBUFS, ("icbuf is not large enough"));
+ if (error)
+ return;
- if (icmsghdrp->icmsgtype == HV_ICMSGTYPE_NEGOTIATE) {
- int error;
+ if (dlen < sizeof(*hdr)) {
+ device_printf(sc->ic_dev, "invalid data len %d\n", dlen);
+ return;
+ }
+ hdr = data;
- error = vmbus_ic_negomsg(softc, time_buf, &recvlen);
+ /*
+ * Update request, which will be echoed back as response.
+ */
+ switch (hdr->ic_type) {
+ case VMBUS_ICMSG_TYPE_NEGOTIATE:
+ error = vmbus_ic_negomsg(sc, data, &dlen);
if (error)
return;
- } else {
- timedatap = (struct hv_ictimesync_data *) &time_buf[
- sizeof(struct hv_vmbus_pipe_hdr) +
- sizeof(struct hv_vmbus_icmsg_hdr)];
- hv_adj_guesttime(softc, timedatap->parenttime, timedatap->flags);
- }
+ break;
- icmsghdrp->icflags = HV_ICMSGHDRFLAG_TRANSACTION
- | HV_ICMSGHDRFLAG_RESPONSE;
-
- vmbus_chan_send(channel, VMBUS_CHANPKT_TYPE_INBAND, 0,
- time_buf, recvlen, requestId);
+ case VMBUS_ICMSG_TYPE_TIMESYNC:
+ if (dlen < sizeof(*msg)) {
+ device_printf(sc->ic_dev, "invalid timesync len %d\n",
+ dlen);
+ return;
+ }
+ msg = data;
+ vmbus_timesync(sc, msg->ic_hvtime, msg->ic_tsflags);
+ break;
+
+ default:
+ device_printf(sc->ic_dev, "got 0x%08x icmsg\n", hdr->ic_type);
+ break;
}
+
+ /*
+ * Send response by echoing the updated request back.
+ */
+ hdr->ic_flags = VMBUS_ICMSG_FLAG_XACT | VMBUS_ICMSG_FLAG_RESP;
+ error = vmbus_chan_send(chan, VMBUS_CHANPKT_TYPE_INBAND, 0,
+ data, dlen, xactid);
+ if (error)
+ device_printf(sc->ic_dev, "resp send failed: %d\n", error);
}
static int
@@ -205,20 +202,15 @@
static int
hv_timesync_attach(device_t dev)
{
- return hv_util_attach(dev, hv_timesync_cb);
-}
-static int
-hv_timesync_detach(device_t dev)
-{
- return hv_util_detach(dev);
+ return (hv_util_attach(dev, vmbus_timesync_cb));
}
static device_method_t timesync_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, hv_timesync_probe),
DEVMETHOD(device_attach, hv_timesync_attach),
- DEVMETHOD(device_detach, hv_timesync_detach),
+ DEVMETHOD(device_detach, hv_util_detach),
{ 0, 0 }
};
Index: head/sys/dev/hyperv/utilities/vmbus_icreg.h
===================================================================
--- head/sys/dev/hyperv/utilities/vmbus_icreg.h
+++ head/sys/dev/hyperv/utilities/vmbus_icreg.h
@@ -91,6 +91,7 @@
#define VMBUS_ICMSG_HEARTBEAT_SIZE_MIN \
__offsetof(struct vmbus_icmsg_heartbeat, ic_rsvd[0])
+/* VMBUS_ICMSG_TYPE_SHUTDOWN */
struct vmbus_icmsg_shutdown {
struct vmbus_icmsg_hdr ic_hdr;
uint32_t ic_code;
@@ -102,4 +103,23 @@
#define VMBUS_ICMSG_SHUTDOWN_SIZE_MIN \
__offsetof(struct vmbus_icmsg_shutdown, ic_msg[0])
+/* VMBUS_ICMSG_TYPE_TIMESYNC */
+struct vmbus_icmsg_timesync {
+ struct vmbus_icmsg_hdr ic_hdr;
+ uint64_t ic_hvtime;
+ uint64_t ic_vmtime;
+ uint64_t ic_rtt;
+ uint8_t ic_tsflags; /* VMBUS_ICMSG_TS_FLAG_ */
+} __packed;
+
+#define VMBUS_ICMSG_TS_FLAG_SYNC 0x01
+#define VMBUS_ICMSG_TS_FLAG_SAMPLE 0x02
+
+/* XXX consolidate w/ hyperv */
+#define VMBUS_ICMSG_TS_BASE 116444736000000000ULL
+#define VMBUS_ICMSG_TS_FACTOR 100ULL
+#ifndef NANOSEC
+#define NANOSEC 1000000000ULL
+#endif
+
#endif /* !_VMBUS_ICREG_H_ */

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 23, 11:41 PM (19 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14811302
Default Alt Text
D7745.diff (10 KB)

Event Timeline