s390/time: convert tod_clock_base to union
authorHeiko Carstens <hca@linux.ibm.com>
Mon, 8 Feb 2021 15:06:10 +0000 (16:06 +0100)
committerVasily Gorbik <gor@linux.ibm.com>
Sat, 13 Feb 2021 16:17:54 +0000 (17:17 +0100)
commitf8d8977a3d971011ab04e4569a664628bd03935e
tree397a45a6eb3bd3534e944e826d75d8b62dfe1575
parentcc2c7db28f7924e9133adc06293a74838ddee59a
s390/time: convert tod_clock_base to union

Convert tod_clock_base to union tod_clock. This simplifies quite a bit
of code and also fixes a bug in read_persistent_clock64();

void read_persistent_clock64(struct timespec64 *ts)
{
        __u64 delta;

        delta = initial_leap_seconds + TOD_UNIX_EPOCH;
        get_tod_clock_ext(clk);
        *(__u64 *) &clk[1] -= delta;
        if (*(__u64 *) &clk[1] > delta)
                clk[0]--;
        ext_to_timespec64(clk, ts);
}

Assume &clk[1] == 3 and delta == 2; then after the substraction the if
condition becomes true and the epoch part of the clock is decremented
by one because of an assumed overflow, even though there is none.

Fix this by using 128 bit arithmetics and let the compiler do the
right thing:

void read_persistent_clock64(struct timespec64 *ts)
{
        union tod_clock clk;
        u64 delta;

        delta = initial_leap_seconds + TOD_UNIX_EPOCH;
        store_tod_clock_ext(&clk);
        clk.eitod -= delta;
        ext_to_timespec64(&clk, ts);
}

Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
arch/s390/include/asm/timex.h
arch/s390/kernel/early.c
arch/s390/kernel/perf_cpum_cf_diag.c
arch/s390/kernel/perf_cpum_sf.c
arch/s390/kernel/time.c