hwclock: fix RTC read logic
Over the past decade a few commits for a corner case problem
have left the RTC read branch in a bad place.
The problem was: when a corrupted RTC could not be read, then
it also could not be reset, because hwclock would error out
due to the RTC read failure.
2.15-rc1 commit
3b96a7a Aug 9 2008
2.19-rc1 commit
5606df5 Dec 29 2010
2.23-rc1 commit
ab8f402 Mar 21 2013
The first fix was to ignore a synchronization timeout only for
the busywait branch.
Two and a half years later a commit describing the same problem
took a little more heavy-handed approach by ignoring all
synchronization failures and the RTC read after it, for both of
the RTC set functions.
Because the previous fix also ignored the select() branch timeout
it caused a bogus warning. The chosen workaround for that was to
only print the select() timeout message in debug mode (this is
reverted by another patch).
The problem with these fixes is that we cannot just ignore the
synchronization timeout like that, because then the drift
correction operations will be invalid. The original logic was
correct; we must exit when synchronization fails.
Another problem is that now there are statements between the
timing-critical synchronize-read-timestamp trio (which were
also in the wrong order, but that part of the problem goes
back further in history).
The solution is to skip the RTC read block completely for the
RTC set functions when not also using the --update-drift
option. If we are updating the drift correction factor during
a set function then we must synchronize and read the RTC.
Otherwise reading the RTC is not needed. Anyone trying to set
a corrupt RTC should not be using --update-drift, because the
resulting drift correction factor would be invalid.
Using this approach has the added benefit of significantly
reducing system shutdown time when not using --update-drift:
time ./hwclock --test --systohc; time ./hwclock-master --test --systohc
Test mode: clock was not changed
real 0m0.072s
user 0m0.066s
sys 0m0.003s
Test mode: clock was not changed
real 0m1.000s
user 0m0.169s
sys 0m0.005s
I've see differences as high as 1.518 seconds.
Signed-off-by: J William Piggott <elseifthen@gmx.com>