@@ -298,6 +298,11 @@ static struct {
298298 spinlock_t lock ;
299299} host_ts ;
300300
301+ static bool timesync_implicit ;
302+
303+ module_param (timesync_implicit , bool , 0644 );
304+ MODULE_PARM_DESC (timesync_implicit , "If set treat SAMPLE as SYNC when clock is behind" );
305+
301306static inline u64 reftime_to_ns (u64 reftime )
302307{
303308 return (reftime - WLTIMEDELTA ) * 100 ;
@@ -346,6 +351,29 @@ static void hv_set_host_time(struct work_struct *work)
346351 do_settimeofday64 (& ts );
347352}
348353
354+ /*
355+ * Due to a bug on Hyper-V hosts, the sync flag may not always be sent on resume.
356+ * Force a sync if the guest is behind.
357+ */
358+ static inline bool hv_implicit_sync (u64 host_time )
359+ {
360+ struct timespec64 new_ts ;
361+ struct timespec64 threshold_ts ;
362+
363+ new_ts = ns_to_timespec64 (reftime_to_ns (host_time ));
364+ ktime_get_real_ts64 (& threshold_ts );
365+
366+ threshold_ts .tv_sec += 5 ;
367+
368+ /*
369+ * If guest behind the host by 5 or more seconds.
370+ */
371+ if (timespec64_compare (& new_ts , & threshold_ts ) >= 0 )
372+ return true;
373+
374+ return false;
375+ }
376+
349377/*
350378 * Synchronize time with host after reboot, restore, etc.
351379 *
@@ -386,7 +414,8 @@ static inline void adj_guesttime(u64 hosttime, u64 reftime, u8 adj_flags)
386414 spin_unlock_irqrestore (& host_ts .lock , flags );
387415
388416 /* Schedule work to do do_settimeofday64() */
389- if (adj_flags & ICTIMESYNCFLAG_SYNC )
417+ if ((adj_flags & ICTIMESYNCFLAG_SYNC ) ||
418+ (timesync_implicit && hv_implicit_sync (host_ts .host_time )))
390419 schedule_work (& adj_time_work );
391420}
392421
0 commit comments