RE: [PATCH] hyperv: Implement Time Synchronization using host time sample

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

 



These old duplicated patches are accidentally send by the mail server...  Sorry for that. 

> -----Original Message-----
> From: Thomas Shao [mailto:huishao@xxxxxxxxxxxxx]
> Sent: Tuesday, October 14, 2014 1:49 PM
> To: tglx@xxxxxxxxxxxxx; gregkh@xxxxxxxxxxxxxxxxxxx; linux-
> kernel@xxxxxxxxxxxxxxx; devel@xxxxxxxxxxxxxxxxxxxxxx; olaf@xxxxxxxxx;
> apw@xxxxxxxxxxxxx; jasowang@xxxxxxxxxx; KY Srinivasan
> Cc: Thomas Shao
> Subject: [PATCH] hyperv: Implement Time Synchronization using host time
> sample
> 
> In current hyper-v time sync service,it only gets the initial clock time from the
> host. It didn't process the following time samples. This change introduced a
> module parameter called host_time_sync. If it is set to true, the guest will
> periodically sychronize it's time with the host clock using host time sample. By
> default it is disabled, because we still recommend user to configure NTP for
> time synchronization.
> 
> Signed-off-by: Thomas Shao <huishao@xxxxxxxxxxxxx>
> Reviewed-by: K. Y. Srinivasan <kys@xxxxxxxxxxxxx>
> ---
>  drivers/hv/hv_util.c      |  114
> +++++++++++++++++++++++++++++++++++++++++---
>  kernel/time/timekeeping.c |    1 +
>  2 files changed, 107 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index 3b9c9ef..1d8390c
> 100644
> --- a/drivers/hv/hv_util.c
> +++ b/drivers/hv/hv_util.c
> @@ -51,11 +51,30 @@
>  #define HB_WS2008_MAJOR	1
>  #define HB_WS2008_VERSION	(HB_WS2008_MAJOR << 16 | HB_MINOR)
> 
> +#define  TIMESAMPLE_INTERVAL 5000000000L  /* 5s in nanosecond */
> +
> +/*host sends time sample for every 5s.So the max polling interval  *is
> +128*5 = 640s.
> +*/
> +#define  TIME_ADJ_MAX_INTERVAL 128 /*Max polling interval */
> +
>  static int sd_srv_version;
>  static int ts_srv_version;
>  static int hb_srv_version;
>  static int util_fw_version;
> 
> +/*host sends time sample for every 5s.So the initial polling interval
> +*is 5s.
> +*/
> +static s32 adj_interval = 1;
> +
> +/*The host_time_sync module parameter is used to control the time
> +  sync between host and guest.
> +*/
> +static bool host_time_sync;
> +module_param(host_time_sync, bool, (S_IRUGO | S_IWUSR));
> +MODULE_PARM_DESC(host_time_sync, "If the guest sync time with host");
> +
>  static void shutdown_onchannelcallback(void *context);  static struct
> hv_util_service util_shutdown = {
>  	.util_cb = shutdown_onchannelcallback, @@ -163,15 +182,61 @@
> static void shutdown_onchannelcallback(void *context)
>  /*
>   * Set guest time to host UTC time.
>   */
> -static inline void do_adj_guesttime(u64 hosttime)
> +static inline void do_adj_guesttime(u64 hosttime, bool forceSync)
>  {
> -	s64 host_tns;
> -	struct timespec host_ts;
> +	s64 host_tns, guest_tns, diff;
> +	struct timespec host_ts, guest_ts;
> +	struct timex txc;
> +	s64 tickchg;
> +	int diff_sign;
> 
>  	host_tns = (hosttime - WLTIMEDELTA) * 100;
>  	host_ts = ns_to_timespec(host_tns);
> 
> -	do_settimeofday(&host_ts);
> +	if (forceSync) {
> +		do_settimeofday(&host_ts);
> +	} else {
> +		guest_ts = CURRENT_TIME;
> +		guest_tns = timespec_to_ns(&guest_ts);
> +		diff = host_tns - guest_tns;
> +		if (diff >= 0) {
> +			diff_sign = 1;
> +		} else {
> +			diff_sign = -1;
> +			diff = -diff;
> +		}
> +
> +		/*1s in nanosecond */
> +		if (diff > 1000000000 || diff < -1000000000) {
> +			do_settimeofday(&host_ts);
> +			return;
> +		}
> +
> +		/*1ms in nanosecond */
> +		if (diff > 1000000 || diff < -1000000) {
> +			/* get the current tick value */
> +			txc.modes = 0;
> +			do_adjtimex(&txc);
> +
> +			tickchg = diff * TICK_USEC /
> +					(TIMESAMPLE_INTERVAL *
> adj_interval);
> +
> +			if (tickchg > TICK_USEC/10)
> +				tickchg = TICK_USEC/10;
> +
> +			if (txc.tick == TICK_USEC + diff_sign * tickchg)
> +				return;
> +
> +			txc.modes = ADJ_TICK;
> +			txc.tick = TICK_USEC + diff_sign * tickchg;
> +
> +			do_adjtimex(&txc);
> +		} else {
> +			/* double the polling interval*/
> +			if (adj_interval < TIME_ADJ_MAX_INTERVAL)
> +				adj_interval = adj_interval * 2;
> +		}
> +	}
>  }
> 
>  /*
> @@ -179,8 +244,9 @@ static inline void do_adj_guesttime(u64 hosttime)
>   */
> 
>  struct adj_time_work {
> -	struct work_struct work;
> +	struct	work_struct work;
>  	u64	host_time;
> +	bool	forceSync;
>  };
> 
>  static void hv_set_host_time(struct work_struct *work) @@ -188,7 +254,7
> @@ static void hv_set_host_time(struct work_struct *work)
>  	struct adj_time_work	*wrk;
> 
>  	wrk = container_of(work, struct adj_time_work, work);
> -	do_adj_guesttime(wrk->host_time);
> +	do_adj_guesttime(wrk->host_time, wrk->forceSync);
>  	kfree(wrk);
>  }
> 
> @@ -202,11 +268,14 @@ static void hv_set_host_time(struct work_struct
> *work)
>   * 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.
> + * If the host_time_sync module parameter is set, we will use the host
> + time
> + * samples to adjust guest time after the first 50 samples.
>   */
>  static inline void adj_guesttime(u64 hosttime, u8 flags)  {
>  	struct adj_time_work    *wrk;
>  	static s32 scnt = 50;
> +	static s32 sample_count;
> 
>  	wrk = kmalloc(sizeof(struct adj_time_work), GFP_ATOMIC);
>  	if (wrk == NULL)
> @@ -214,6 +283,7 @@ static inline void adj_guesttime(u64 hosttime, u8 flags)
> 
>  	wrk->host_time = hosttime;
>  	if ((flags & ICTIMESYNCFLAG_SYNC) != 0) {
> +		wrk->forceSync = true;
>  		INIT_WORK(&wrk->work, hv_set_host_time);
>  		schedule_work(&wrk->work);
>  		return;
> @@ -221,10 +291,38 @@ static inline void adj_guesttime(u64 hosttime, u8
> flags)
> 
>  	if ((flags & ICTIMESYNCFLAG_SAMPLE) != 0 && scnt > 0) {
>  		scnt--;
> +		wrk->forceSync = true;
>  		INIT_WORK(&wrk->work, hv_set_host_time);
>  		schedule_work(&wrk->work);
> -	} else
> -		kfree(wrk);
> +		return;
> +	}
> +
> +	if (host_time_sync) {
> +		/*
> +		* Use the Hyper-V time sample to adjust the guest time. The
> +		* algorithm is: If the sample offsets exceeds 1 second, we
> +		* directly set the clock to the server time. If the offset is
> +		* less than 1ms, we ignore the time sample. Otherwise we
> adjust
> +		* the clock.
> +		*/
> +
> +		if ((flags & ICTIMESYNCFLAG_SAMPLE) != 0) {
> +			if (sample_count < adj_interval) {
> +				sample_count++;
> +				goto cleanup;
> +			}
> +			/* reset the polling interval */
> +			sample_count = 0;
> +			wrk->forceSync = false;
> +			INIT_WORK(&wrk->work, hv_set_host_time);
> +			schedule_work(&wrk->work);
> +			return;
> +		}
> +	}
> +
> +cleanup:
> +	kfree(wrk);
> +
>  }
> 
>  /*
> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index
> ec1791f..381a1ca 100644
> --- a/kernel/time/timekeeping.c
> +++ b/kernel/time/timekeeping.c
> @@ -1786,6 +1786,7 @@ int do_adjtimex(struct timex *txc)
> 
>  	return ret;
>  }
> +EXPORT_SYMBOL(do_adjtimex);
> 
>  #ifdef CONFIG_NTP_PPS
>  /**
> --
> 1.7.1

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel




[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux