Last update: 24-Apr-2022
Author: R. Koucha
Systemd does not benefit from VDSO
Introduction

In a project, we observe that despite of the activation of CONFIG_VDSO in the Linux kernel, systemd is still calling clock_gettime() system call instead of the library call provided by the dummy VDSO shared library.

Observation

We are running an ARM v7 target with Linux in 32 bits mode.

The kernel configuration activates VDSO:

# cat /proc/config.gz | grep VDSO
CONFIG_VDSO=y

We verify that systemd dynamically links with VDSO:

# /lib/ld-linux-armhf.so.3 --list /lib/systemd/systemd
        linux-vdso.so.1 (0xbef87000)
        libsystemd-shared-243.so => /lib/systemd/libsystemd-shared-243.so (0xb6d3c000)
        librt.so.1 => /lib/librt.so.1 (0xb6d14000)
        libselinux.so.1 => /lib/libselinux.so.1 (0xb6ce7000)
        libmount.so.1 => /lib/libmount.so.1 (0xb6ca7000)
        libkmod.so.2 => /lib/libkmod.so.2 (0xb6c88000)
        libpthread.so.0 => /lib/libpthread.so.0 (0xb6c5f000)
        libc.so.6 => /lib/libc.so.6 (0xb6b1d000)
        /lib/ld-linux-armhf.so.3 (0xb6f5b000)
        libcap.so.2 => /lib/libcap.so.2 (0xb6b08000)
        libblkid.so.1 => /lib/libblkid.so.1 (0xb6ad2000)
        libm.so.6 => /lib/libm.so.6 (0xb6a52000)
        libpcre.so.1 => /usr/lib/libpcre.so.1 (0xb6a08000)
        libdl.so.2 => /lib/libdl.so.2 (0xb69f5000)
        libuuid.so.1 => /lib/libuuid.so.1 (0xb69df000)

Despite the previous settings, the spy of systemd with strace tool still show calls to clock_gettime() meaning that the VDSO implementation of the latter is not takien in account:

# strace -fp 1
[...]
[pid     1] clock_gettime(CLOCK_BOOTTIME,  
[pid     1] <... clock_gettime resumed>{tv_sec=125, tv_nsec=830187294}) = 0
[...]
Analysis

clock_gettime()'s prototype is:

int clock_gettime(clockid_t clk_id, struct timespec *tp);

The system call is passed as first parameter a clock identifier. The possible values (depending on the kernel version) are:

Systemd uses several clock identifiers but we can note that only the calls to clock_gettime() with the CLOCK_BOOTTIME identifier are showing up in the strace calls.

Looking at the source code of the kernel, we can see that the VDSO implementation of clock_gettime() located in arch/arm/vdso/vgettimeofday.c only supports a subset of all the possible clock identifiers (in red). For the others, a fallback to the actual system call is done (call to clock_gettime_fallback()):

notrace int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
{
      struct vdso_data *vdata;
      int ret = -1;

      vdata = __get_datapage();

      switch (clkid) {
      case CLOCK_REALTIME_COARSE:
            ret = do_realtime_coarse(ts, vdata);
            break;
      case CLOCK_MONOTONIC_COARSE:
            ret = do_monotonic_coarse(ts, vdata);
            break;
      case CLOCK_REALTIME:
            ret = do_realtime(ts, vdata);
            break;
      case CLOCK_MONOTONIC:
            ret = do_monotonic(ts, vdata);
            break;
      default:
            break;
      }

      if (ret)
            ret = clock_gettime_fallback(clkid, ts);

      return ret;
}
Conclusion

So, when system is using CLOCK_BOOTTIME and since the latter is not in the set supported by the VDSO implementation, the actual system call is invoked.

About the author

The author is an engineer in computer sciences located in France. He can be contacted here.