forked from luck/tmp_suning_uos_patched
9c1645727b
The clocksource delta to nanoseconds conversion is using signed math, but the delta is unsigned. This makes the conversion space smaller than necessary and in case of a multiplication overflow the conversion can become negative. The conversion is done with scaled math: s64 nsec_delta = ((s64)clkdelta * clk->mult) >> clk->shift; Shifting a signed integer right obvioulsy preserves the sign, which has interesting consequences: - Time jumps backwards - __iter_div_u64_rem() which is used in one of the calling code pathes will take forever to piecewise calculate the seconds/nanoseconds part. This has been reported by several people with different scenarios: David observed that when stopping a VM with a debugger: "It was essentially the stopped by debugger case. I forget exactly why, but the guest was being explicitly stopped from outside, it wasn't just scheduling lag. I think it was something in the vicinity of 10 minutes stopped." When lifting the stop the machine went dead. The stopped by debugger case is not really interesting, but nevertheless it would be a good thing not to die completely. But this was also observed on a live system by Liav: "When the OS is too overloaded, delta will get a high enough value for the msb of the sum delta * tkr->mult + tkr->xtime_nsec to be set, and so after the shift the nsec variable will gain a value similar to 0xffffffffff000000." Unfortunately this has been reintroduced recently with commit |
||
---|---|---|
.. | ||
alarmtimer.c | ||
clockevents.c | ||
clocksource.c | ||
hrtimer.c | ||
itimer.c | ||
jiffies.c | ||
Kconfig | ||
Makefile | ||
ntp_internal.h | ||
ntp.c | ||
posix-clock.c | ||
posix-cpu-timers.c | ||
posix-stubs.c | ||
posix-timers.c | ||
sched_clock.c | ||
test_udelay.c | ||
tick-broadcast-hrtimer.c | ||
tick-broadcast.c | ||
tick-common.c | ||
tick-internal.h | ||
tick-oneshot.c | ||
tick-sched.c | ||
tick-sched.h | ||
time.c | ||
timeconst.bc | ||
timeconv.c | ||
timecounter.c | ||
timekeeping_debug.c | ||
timekeeping_internal.h | ||
timekeeping.c | ||
timekeeping.h | ||
timer_list.c | ||
timer_stats.c | ||
timer.c |