遇到一个Linux系统时间突变问题

221 阅读3分钟

这是我参与8月更文挑战的第29天,活动详情查看:8月更文挑战

最近遇到一个Linux系统时间无法更改小于某个固定时间的问题。

有关部门反馈,一旦将设备的时间设置小于2019年11月3号4点34分,复位设备后,系统时间就会变成2019年11月3号4点后的时间。此问题十分诡异。负责业务的同志无法排查,于是安排我——或许天生注定,我这里,所有和Linux有关,所有“底层问题”,都可以找到我。

首先重现问题,拿到设备,用上位机设置时间,结果和反馈的一样。仔细分析,uboot时间和内核时间是一致的,但到了系统里面,时间就变了。再用nfs启动来测试就没问题,一切正常,date时间和内核时间一致。和硬件的同志交流了,虽然他们以前也发现了这个现象,但没什么头绪。甚至一度怀疑RTC电池的问题,但如果这样,RTC时间会变成2000年,而不是一个奇怪的时间。交流的结果是从系统启动脚本入手。

由于脚本较多,首先想到的是在内核RTC驱动中打印设置、读取时间,以便观察是在何处操作了RTC。然后跟踪了脚本,从rc.d目录看,发现几个和时间有关脚本,查看了一下,里面调用hwclock来读取、设置时间。最终确定了问题所在。

问题是这样的。

我们使用的那套rootfs,对于系统启动时的时间管理有一个机制,就是在启动脚本中判断当前的时间比上一次的时间戳,如果小于超过一天的时候,就会使用上一次的时间戳,如果不是,则不使用。脚本大概是这样的:

# Set the system clock from hardware clock
# If the timestamp is 1 day or more recent than the current time,
# use the timestamp instead.
test -x /etc/init.d/hwclock.sh && /etc/init.d/hwclock.sh start
 
if test -e /etc/timestamp // !~~~~~
then
     SYSTEMDATE=`date "+%Y%m%d"`
     TIMESTAMP=`cat /etc/timestamp | awk '{ print substr($0,9,4) substr($0,1,4);}'`
        NEEDUPDATE=`expr \( $TIMESTAMP \> $SYSTEMDATE \)`                                                
        if [ $NEEDUPDATE -eq 1 ]; then
          date `cat /etc/timestamp`
          /etc/init.d/hwclock.sh stop
     fi
fi

在/etc/init.d目录里有脚本读取RTC时间和保存timestamp。在每次启动时,都会如此。

我们所用的是UBI文件系统,是只读的(先前是可读可写的,但发现flash损坏事件而改为只读)。timestamp是我之前使用rootfs时所留下的时间。因此,当设置的时候小于这个值时,就会出现上文的时间了。而我的NFS是可读可写的,所以使用NFS无问题。

——但是想想,即使是可读可写的,只要时间误差太离谱,系统都会强行改为上一启动的时间。 为此再深入研究发现,这个问题本身就是rootfs的问题,上述分析也变得是一厢情愿了。不知何故,这个rootfs里已经没有调用保存rtc的脚本了,但判断时间戳的语句还在,/etc/timestamp文件还在,所以,无论怎样,问题还是存在的。

对于这个“bug”,我个人认为没有必要修改,我相信现在不会有人把设备时间改为几年了,我不知道某些部门是如何想的。当今的RTC芯片,为了方便(如计算闰年),把年份限制到00~99,即2000年开始的百年时间,在系统中设置时间小于2000年没问题,但写到RTC就会报错。估计这一点要向大家说明才行,不然又因认知问题导致误解。