New kernel interface for sys_tz and timewarp?

Arnd Bergmann
2019-08-13T09:06:14Z

The riscv32 kernel port uses the new time64 syscall interface that has no
'settimeofday', only 'clock_settime64'. During the review of the glibc port,
the question arose how to deal with the (old, horrible, deprecated) timezone
portion of the settimeofday() libc API.

Typical uses of timezones in gettimeofday() are broken and should use
the normal user space timezone handling built into localtime() instead,
so the initial idea was to just not bother on new architectures and
break any application at build time that tries to access the struct timezone
members to ensure they are finally fixed, and also do the same thing
across all architectures for consistency.

As it turns out, both util-linux/hwclock and systemd make use of the
timezone field in settimeofday purely for the purpose of setting the
kernel itself into a known state, for three traditional uses:

- gettimeofday reports the timezone that was last set with settimeofday,
something that is highly discouraged relying on but that has always
worked.

- a few device drivers and file systems (e.g. fs/fat, full list below) are
documented as storing timestamps in local time, so the global sys_tz variable
is used to decide the offset, in addition to a in-superblock offset in most
cases.

- on x86, windows dual-boot has traditionally (since linux-0.12) allowed the
hack that the first settimeofday() call after boot decides whether the RTC
is interpreted as localtime or UTC. This is particularly important because
with NTP enabled, the time warped mode also updates the RTC with
the kernel time every 11 minutes. See kernel/time/ntp.c:sync_hw_clock()
and timekeeping_warp_clock() .

The relevant discussion on libc-alpha and on for systemd is archived at:
https://patchwork.ozlabs.org/patch/1121610/
https://github.com/systemd/systemd/issues/13305

Now, to the actual questions:

* Should we allow setting the sys_tz on new architectures that use only
time64 interfaces at all, or should we try to get away from that anyway?

* Should the NTP timewarp setting ("int persistent_clock_is_local" and
its offset) be controllable separately from the timezone used in other
drivers?

* If we want keep having a way to set the sys_tz, what interface
should that use?

Suggestions so far include
- adding a clock_settimeofday_time64() syscall on all 32-bit architectures to
maintain the traditional behavior,
- adding a sysctl interface for accessing sys_tz.tz_tminuteswest,
- using a new field in 'struct timex' for the timewarp offset, and
- adding an ioctl command on /dev/rtc/ to control the timewarp
offset of that particular device.

Arnd
---
Appendix A: full list of kernel code using sys_tz

$ git grep -wl sys_tz drivers/ fs/ net/
drivers/media/platform/vivid/vivid-rds-gen.c
drivers/media/platform/vivid/vivid-vbi-gen.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/scsi/3w-9xxx.c
drivers/scsi/3w-sas.c
drivers/scsi/aacraid/commsup.c
drivers/scsi/arcmsr/arcmsr_hba.c
drivers/scsi/mvumi.c
drivers/scsi/mvumi.h
drivers/scsi/smartpqi/smartpqi_init.c
fs/affs/amigaffs.c
fs/affs/inode.c
fs/fat/misc.c
fs/hfs/hfs_fs.h
fs/hfs/inode.c
fs/hfs/sysdep.c
fs/hpfs/hpfs_fn.h
fs/udf/udftime.c
net/netfilter/xt_time.c