From: Dmitry Safonov <dima@arista.com> To: linux-kernel@vger.kernel.org Cc: Dmitry Safonov <0x7f454c46@gmail.com>, Dmitry Safonov <dima@arista.com>, Adrian Reber <adrian@lisas.de>, Andrei Vagin <avagin@openvz.org>, Andy Lutomirski <luto@kernel.org>, Arnd Bergmann <arnd@arndb.de>, Christian Brauner <christian.brauner@ubuntu.com>, Cyrill Gorcunov <gorcunov@openvz.org>, "Eric W. Biederman" <ebiederm@xmission.com>, "H. Peter Anvin" <hpa@zytor.com>, Ingo Molnar <mingo@redhat.com>, Jann Horn <jannh@google.com>, Jeff Dike <jdike@addtoit.com>, Oleg Nesterov <oleg@redhat.com>, Pavel Emelyanov <xemul@virtuozzo.com>, Shuah Khan <shuah@kernel.org>, Thomas Gleixner <tglx@linutronix.de>, Vincenzo Frascino <vincenzo.frascino@arm.com>, containers@lists.linux-foundation.org, criu@openvz.org, linux-api@vger.kernel.org, x86@kernel.org, Andrei Vagin <avagin@gmail.com> Subject: [PATCHv8 28/34] selftests/timens: Add Time Namespace test for supported clocks Date: Tue, 12 Nov 2019 01:27:17 +0000 [thread overview] Message-ID: <20191112012724.250792-29-dima@arista.com> (raw) In-Reply-To: <20191112012724.250792-1-dima@arista.com> A test to check that all supported clocks work on host and inside a new time namespace. Use both ways to get time: through VDSO and by entering the kernel with implicit syscall. Introduce a new timens directory in selftests framework for the next timens tests. Output on success: 1..10 ok 1 Passed for CLOCK_BOOTTIME (syscall) ok 2 Passed for CLOCK_BOOTTIME (vdso) ok 3 Passed for CLOCK_BOOTTIME_ALARM (syscall) ok 4 Passed for CLOCK_BOOTTIME_ALARM (vdso) ok 5 Passed for CLOCK_MONOTONIC (syscall) ok 6 Passed for CLOCK_MONOTONIC (vdso) ok 7 Passed for CLOCK_MONOTONIC_COARSE (syscall) ok 8 Passed for CLOCK_MONOTONIC_COARSE (vdso) ok 9 Passed for CLOCK_MONOTONIC_RAW (syscall) ok 10 Passed for CLOCK_MONOTONIC_RAW (vdso) # Pass 10 Fail 0 Xfail 0 Xpass 0 Skip 0 Error 0 Output with lack of permissions: 1..10 not ok 1 # SKIP need to run as root Output without support of time namespaces: 1..10 not ok 1 # SKIP Time namespaces are not supported Co-developed-by: Andrei Vagin <avagin@openvz.org> Signed-off-by: Andrei Vagin <avagin@gmail.com> Signed-off-by: Dmitry Safonov <dima@arista.com> --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/timens/.gitignore | 1 + tools/testing/selftests/timens/Makefile | 6 + tools/testing/selftests/timens/config | 1 + tools/testing/selftests/timens/log.h | 26 +++ tools/testing/selftests/timens/timens.c | 190 ++++++++++++++++++++++ tools/testing/selftests/timens/timens.h | 100 ++++++++++++ 7 files changed, 325 insertions(+) create mode 100644 tools/testing/selftests/timens/.gitignore create mode 100644 tools/testing/selftests/timens/Makefile create mode 100644 tools/testing/selftests/timens/config create mode 100644 tools/testing/selftests/timens/log.h create mode 100644 tools/testing/selftests/timens/timens.c create mode 100644 tools/testing/selftests/timens/timens.h diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 319e094c3212..56e130066c43 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -50,6 +50,7 @@ TARGETS += splice TARGETS += static_keys TARGETS += sync TARGETS += sysctl +TARGETS += timens ifneq (1, $(quicktest)) TARGETS += timers endif diff --git a/tools/testing/selftests/timens/.gitignore b/tools/testing/selftests/timens/.gitignore new file mode 100644 index 000000000000..27a693229ce1 --- /dev/null +++ b/tools/testing/selftests/timens/.gitignore @@ -0,0 +1 @@ +timens diff --git a/tools/testing/selftests/timens/Makefile b/tools/testing/selftests/timens/Makefile new file mode 100644 index 000000000000..49a9dcc26c3a --- /dev/null +++ b/tools/testing/selftests/timens/Makefile @@ -0,0 +1,6 @@ +TEST_GEN_PROGS := timens + +CFLAGS := -Wall -Werror +LDFLAGS := -lrt + +include ../lib.mk diff --git a/tools/testing/selftests/timens/config b/tools/testing/selftests/timens/config new file mode 100644 index 000000000000..4480620f6f49 --- /dev/null +++ b/tools/testing/selftests/timens/config @@ -0,0 +1 @@ +CONFIG_TIME_NS=y diff --git a/tools/testing/selftests/timens/log.h b/tools/testing/selftests/timens/log.h new file mode 100644 index 000000000000..db64df2a8483 --- /dev/null +++ b/tools/testing/selftests/timens/log.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __SELFTEST_TIMENS_LOG_H__ +#define __SELFTEST_TIMENS_LOG_H__ + +#define pr_msg(fmt, lvl, ...) \ + ksft_print_msg("[%s] (%s:%d)\t" fmt "\n", \ + lvl, __FILE__, __LINE__, ##__VA_ARGS__) + +#define pr_p(func, fmt, ...) func(fmt ": %m", ##__VA_ARGS__) + +#define pr_err(fmt, ...) \ + ({ \ + ksft_test_result_error(fmt "\n", ##__VA_ARGS__); \ + -1; \ + }) + +#define pr_fail(fmt, ...) \ + ({ \ + ksft_test_result_fail(fmt, ##__VA_ARGS__); \ + -1; \ + }) + +#define pr_perror(fmt, ...) pr_p(pr_err, fmt, ##__VA_ARGS__) + +#endif diff --git a/tools/testing/selftests/timens/timens.c b/tools/testing/selftests/timens/timens.c new file mode 100644 index 000000000000..559d26e21ba0 --- /dev/null +++ b/tools/testing/selftests/timens/timens.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE +#include <errno.h> +#include <fcntl.h> +#include <sched.h> +#include <stdio.h> +#include <stdbool.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> +#include <time.h> +#include <string.h> + +#include "log.h" +#include "timens.h" + +/* + * Test shouldn't be run for a day, so add 10 days to child + * time and check parent's time to be in the same day. + */ +#define DAY_IN_SEC (60*60*24) +#define TEN_DAYS_IN_SEC (10*DAY_IN_SEC) + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +struct test_clock { + clockid_t id; + char *name; + /* + * off_id is -1 if a clock has own offset, or it contains an index + * which contains a right offset of this clock. + */ + int off_id; + time_t offset; +}; + +#define ct(clock, off_id) { clock, #clock, off_id } +static struct test_clock clocks[] = { + ct(CLOCK_BOOTTIME, -1), + ct(CLOCK_BOOTTIME_ALARM, 1), + ct(CLOCK_MONOTONIC, -1), + ct(CLOCK_MONOTONIC_COARSE, 1), + ct(CLOCK_MONOTONIC_RAW, 1), +}; +#undef ct + +static int child_ns, parent_ns = -1; + +static int switch_ns(int fd) +{ + if (setns(fd, CLONE_NEWTIME)) { + pr_perror("setns()"); + return -1; + } + + return 0; +} + +static int init_namespaces(void) +{ + char path[] = "/proc/self/ns/time_for_children"; + struct stat st1, st2; + + if (parent_ns == -1) { + parent_ns = open(path, O_RDONLY); + if (parent_ns <= 0) + return pr_perror("Unable to open %s", path); + } + + if (fstat(parent_ns, &st1)) + return pr_perror("Unable to stat the parent timens"); + + if (unshare_timens()) + return -1; + + child_ns = open(path, O_RDONLY); + if (child_ns <= 0) + return pr_perror("Unable to open %s", path); + + if (fstat(child_ns, &st2)) + return pr_perror("Unable to stat the timens"); + + if (st1.st_ino == st2.st_ino) + return pr_perror("The same child_ns after CLONE_NEWTIME"); + + return 0; +} + +static int test_gettime(clockid_t clock_index, bool raw_syscall, time_t offset) +{ + struct timespec child_ts_new, parent_ts_old, cur_ts; + char *entry = raw_syscall ? "syscall" : "vdso"; + double precision = 0.0; + + if (check_skip(clocks[clock_index].id)) + return 0; + + switch (clocks[clock_index].id) { + case CLOCK_MONOTONIC_COARSE: + case CLOCK_MONOTONIC_RAW: + precision = -2.0; + break; + } + + if (switch_ns(parent_ns)) + return pr_err("switch_ns(%d)", child_ns); + + if (_gettime(clocks[clock_index].id, &parent_ts_old, raw_syscall)) + return -1; + + child_ts_new.tv_nsec = parent_ts_old.tv_nsec; + child_ts_new.tv_sec = parent_ts_old.tv_sec + offset; + + if (switch_ns(child_ns)) + return pr_err("switch_ns(%d)", child_ns); + + if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall)) + return -1; + + if (difftime(cur_ts.tv_sec, child_ts_new.tv_sec) < precision) { + ksft_test_result_fail( + "Child's %s (%s) time has not changed: %lu -> %lu [%lu]\n", + clocks[clock_index].name, entry, parent_ts_old.tv_sec, + child_ts_new.tv_sec, cur_ts.tv_sec); + return -1; + } + + if (switch_ns(parent_ns)) + return pr_err("switch_ns(%d)", parent_ns); + + if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall)) + return -1; + + if (difftime(cur_ts.tv_sec, parent_ts_old.tv_sec) > DAY_IN_SEC) { + ksft_test_result_fail( + "Parent's %s (%s) time has changed: %lu -> %lu [%lu]\n", + clocks[clock_index].name, entry, parent_ts_old.tv_sec, + child_ts_new.tv_sec, cur_ts.tv_sec); + /* Let's play nice and put it closer to original */ + clock_settime(clocks[clock_index].id, &cur_ts); + return -1; + } + + ksft_test_result_pass("Passed for %s (%s)\n", + clocks[clock_index].name, entry); + return 0; +} + +int main(int argc, char *argv[]) +{ + unsigned int i; + time_t offset; + int ret = 0; + + nscheck(); + + check_config_posix_timers(); + + ksft_set_plan(ARRAY_SIZE(clocks) * 2); + + if (init_namespaces()) + return 1; + + /* Offsets have to be set before tasks enter the namespace. */ + for (i = 0; i < ARRAY_SIZE(clocks); i++) { + if (clocks[i].off_id != -1) + continue; + offset = TEN_DAYS_IN_SEC + i * 1000; + clocks[i].offset = offset; + if (_settime(clocks[i].id, offset)) + return 1; + } + + for (i = 0; i < ARRAY_SIZE(clocks); i++) { + if (clocks[i].off_id != -1) + offset = clocks[clocks[i].off_id].offset; + else + offset = clocks[i].offset; + ret |= test_gettime(i, true, offset); + ret |= test_gettime(i, false, offset); + } + + if (ret) + ksft_exit_fail(); + + ksft_exit_pass(); + return !!ret; +} diff --git a/tools/testing/selftests/timens/timens.h b/tools/testing/selftests/timens/timens.h new file mode 100644 index 000000000000..e09e7e39bc52 --- /dev/null +++ b/tools/testing/selftests/timens/timens.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __TIMENS_H__ +#define __TIMENS_H__ + +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> + +#include "../kselftest.h" + +#ifndef CLONE_NEWTIME +# define CLONE_NEWTIME 0x00000080 +#endif + +static int config_posix_timers = true; + +static inline void check_config_posix_timers(void) +{ + if (timer_create(-1, 0, 0) == -1 && errno == ENOSYS) + config_posix_timers = false; +} + +static inline bool check_skip(int clockid) +{ + if (config_posix_timers) + return false; + + switch (clockid) { + /* Only these clocks are supported without CONFIG_POSIX_TIMERS. */ + case CLOCK_BOOTTIME: + case CLOCK_MONOTONIC: + case CLOCK_REALTIME: + return false; + default: + ksft_test_result_skip("Posix Clocks & timers are not supported\n"); + return true; + } + + return false; +} + +static inline int unshare_timens(void) +{ + if (unshare(CLONE_NEWTIME)) { + if (errno == EPERM) + ksft_exit_skip("need to run as root\n"); + return pr_perror("Can't unshare() timens"); + } + return 0; +} + +static inline int _settime(clockid_t clk_id, time_t offset) +{ + int fd, len; + char buf[4096]; + + if (clk_id == CLOCK_MONOTONIC_COARSE || clk_id == CLOCK_MONOTONIC_RAW) + clk_id = CLOCK_MONOTONIC; + + len = snprintf(buf, sizeof(buf), "%d %ld 0", clk_id, offset); + + fd = open("/proc/self/timens_offsets", O_WRONLY); + if (fd < 0) + return pr_perror("/proc/self/timens_offsets"); + + if (write(fd, buf, len) != len) + return pr_perror("/proc/self/timens_offsets"); + + close(fd); + + return 0; +} + +static inline int _gettime(clockid_t clk_id, struct timespec *res, bool raw_syscall) +{ + int err; + + if (!raw_syscall) { + if (clock_gettime(clk_id, res)) { + pr_perror("clock_gettime(%d)", (int)clk_id); + return -1; + } + return 0; + } + + err = syscall(SYS_clock_gettime, clk_id, res); + if (err) + pr_perror("syscall(SYS_clock_gettime(%d))", (int)clk_id); + + return err; +} + +static inline void nscheck(void) +{ + if (access("/proc/self/ns/time", F_OK) < 0) + ksft_exit_skip("Time namespaces are not supported\n"); +} + +#endif -- 2.24.0
WARNING: multiple messages have this Message-ID (diff)
From: Dmitry Safonov <dima@arista.com> To: linux-kernel@vger.kernel.org Cc: Dmitry Safonov <0x7f454c46@gmail.com>, Dmitry Safonov <dima@arista.com>, Adrian Reber <adrian@lisas.de>, Andrei Vagin <avagin@openvz.org>, Andy Lutomirski <luto@kernel.org>, Arnd Bergmann <arnd@arndb.de>, Christian Brauner <christian.brauner@ubuntu.com>, Cyrill Gorcunov <gorcunov@openvz.org>, "Eric W. Biederman" <ebiederm@xmission.com>, "H. Peter Anvin" <hpa@zytor.com>, Ingo Molnar <mingo@redhat.com>, Jann Horn <jannh@google.com>, Jeff Dike <jdike@addtoit.com>, Oleg Nesterov <oleg@redhat.com>, Pavel Emelyanov <xemul@virtuozzo.com>, Shuah Khan <shuah@kernel.org>, Thomas Gleixner <tglx@linutronix.de>, Vincenzo Frascino <vincenzo.frascino@arm.com>, containers@lists.linux-foundation.org, criu@openvz.org, linux-api@vger.kernel.org, x86@kernel.org Subject: [PATCHv8 28/34] selftests/timens: Add Time Namespace test for supported clocks Date: Tue, 12 Nov 2019 01:27:17 +0000 [thread overview] Message-ID: <20191112012724.250792-29-dima@arista.com> (raw) In-Reply-To: <20191112012724.250792-1-dima@arista.com> A test to check that all supported clocks work on host and inside a new time namespace. Use both ways to get time: through VDSO and by entering the kernel with implicit syscall. Introduce a new timens directory in selftests framework for the next timens tests. Output on success: 1..10 ok 1 Passed for CLOCK_BOOTTIME (syscall) ok 2 Passed for CLOCK_BOOTTIME (vdso) ok 3 Passed for CLOCK_BOOTTIME_ALARM (syscall) ok 4 Passed for CLOCK_BOOTTIME_ALARM (vdso) ok 5 Passed for CLOCK_MONOTONIC (syscall) ok 6 Passed for CLOCK_MONOTONIC (vdso) ok 7 Passed for CLOCK_MONOTONIC_COARSE (syscall) ok 8 Passed for CLOCK_MONOTONIC_COARSE (vdso) ok 9 Passed for CLOCK_MONOTONIC_RAW (syscall) ok 10 Passed for CLOCK_MONOTONIC_RAW (vdso) # Pass 10 Fail 0 Xfail 0 Xpass 0 Skip 0 Error 0 Output with lack of permissions: 1..10 not ok 1 # SKIP need to run as root Output without support of time namespaces: 1..10 not ok 1 # SKIP Time namespaces are not supported Co-developed-by: Andrei Vagin <avagin@openvz.org> Signed-off-by: Andrei Vagin <avagin@gmail.com> Signed-off-by: Dmitry Safonov <dima@arista.com> --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/timens/.gitignore | 1 + tools/testing/selftests/timens/Makefile | 6 + tools/testing/selftests/timens/config | 1 + tools/testing/selftests/timens/log.h | 26 +++ tools/testing/selftests/timens/timens.c | 190 ++++++++++++++++++++++ tools/testing/selftests/timens/timens.h | 100 ++++++++++++ 7 files changed, 325 insertions(+) create mode 100644 tools/testing/selftests/timens/.gitignore create mode 100644 tools/testing/selftests/timens/Makefile create mode 100644 tools/testing/selftests/timens/config create mode 100644 tools/testing/selftests/timens/log.h create mode 100644 tools/testing/selftests/timens/timens.c create mode 100644 tools/testing/selftests/timens/timens.h diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 319e094c3212..56e130066c43 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -50,6 +50,7 @@ TARGETS += splice TARGETS += static_keys TARGETS += sync TARGETS += sysctl +TARGETS += timens ifneq (1, $(quicktest)) TARGETS += timers endif diff --git a/tools/testing/selftests/timens/.gitignore b/tools/testing/selftests/timens/.gitignore new file mode 100644 index 000000000000..27a693229ce1 --- /dev/null +++ b/tools/testing/selftests/timens/.gitignore @@ -0,0 +1 @@ +timens diff --git a/tools/testing/selftests/timens/Makefile b/tools/testing/selftests/timens/Makefile new file mode 100644 index 000000000000..49a9dcc26c3a --- /dev/null +++ b/tools/testing/selftests/timens/Makefile @@ -0,0 +1,6 @@ +TEST_GEN_PROGS := timens + +CFLAGS := -Wall -Werror +LDFLAGS := -lrt + +include ../lib.mk diff --git a/tools/testing/selftests/timens/config b/tools/testing/selftests/timens/config new file mode 100644 index 000000000000..4480620f6f49 --- /dev/null +++ b/tools/testing/selftests/timens/config @@ -0,0 +1 @@ +CONFIG_TIME_NS=y diff --git a/tools/testing/selftests/timens/log.h b/tools/testing/selftests/timens/log.h new file mode 100644 index 000000000000..db64df2a8483 --- /dev/null +++ b/tools/testing/selftests/timens/log.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __SELFTEST_TIMENS_LOG_H__ +#define __SELFTEST_TIMENS_LOG_H__ + +#define pr_msg(fmt, lvl, ...) \ + ksft_print_msg("[%s] (%s:%d)\t" fmt "\n", \ + lvl, __FILE__, __LINE__, ##__VA_ARGS__) + +#define pr_p(func, fmt, ...) func(fmt ": %m", ##__VA_ARGS__) + +#define pr_err(fmt, ...) \ + ({ \ + ksft_test_result_error(fmt "\n", ##__VA_ARGS__); \ + -1; \ + }) + +#define pr_fail(fmt, ...) \ + ({ \ + ksft_test_result_fail(fmt, ##__VA_ARGS__); \ + -1; \ + }) + +#define pr_perror(fmt, ...) pr_p(pr_err, fmt, ##__VA_ARGS__) + +#endif diff --git a/tools/testing/selftests/timens/timens.c b/tools/testing/selftests/timens/timens.c new file mode 100644 index 000000000000..559d26e21ba0 --- /dev/null +++ b/tools/testing/selftests/timens/timens.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE +#include <errno.h> +#include <fcntl.h> +#include <sched.h> +#include <stdio.h> +#include <stdbool.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> +#include <time.h> +#include <string.h> + +#include "log.h" +#include "timens.h" + +/* + * Test shouldn't be run for a day, so add 10 days to child + * time and check parent's time to be in the same day. + */ +#define DAY_IN_SEC (60*60*24) +#define TEN_DAYS_IN_SEC (10*DAY_IN_SEC) + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +struct test_clock { + clockid_t id; + char *name; + /* + * off_id is -1 if a clock has own offset, or it contains an index + * which contains a right offset of this clock. + */ + int off_id; + time_t offset; +}; + +#define ct(clock, off_id) { clock, #clock, off_id } +static struct test_clock clocks[] = { + ct(CLOCK_BOOTTIME, -1), + ct(CLOCK_BOOTTIME_ALARM, 1), + ct(CLOCK_MONOTONIC, -1), + ct(CLOCK_MONOTONIC_COARSE, 1), + ct(CLOCK_MONOTONIC_RAW, 1), +}; +#undef ct + +static int child_ns, parent_ns = -1; + +static int switch_ns(int fd) +{ + if (setns(fd, CLONE_NEWTIME)) { + pr_perror("setns()"); + return -1; + } + + return 0; +} + +static int init_namespaces(void) +{ + char path[] = "/proc/self/ns/time_for_children"; + struct stat st1, st2; + + if (parent_ns == -1) { + parent_ns = open(path, O_RDONLY); + if (parent_ns <= 0) + return pr_perror("Unable to open %s", path); + } + + if (fstat(parent_ns, &st1)) + return pr_perror("Unable to stat the parent timens"); + + if (unshare_timens()) + return -1; + + child_ns = open(path, O_RDONLY); + if (child_ns <= 0) + return pr_perror("Unable to open %s", path); + + if (fstat(child_ns, &st2)) + return pr_perror("Unable to stat the timens"); + + if (st1.st_ino == st2.st_ino) + return pr_perror("The same child_ns after CLONE_NEWTIME"); + + return 0; +} + +static int test_gettime(clockid_t clock_index, bool raw_syscall, time_t offset) +{ + struct timespec child_ts_new, parent_ts_old, cur_ts; + char *entry = raw_syscall ? "syscall" : "vdso"; + double precision = 0.0; + + if (check_skip(clocks[clock_index].id)) + return 0; + + switch (clocks[clock_index].id) { + case CLOCK_MONOTONIC_COARSE: + case CLOCK_MONOTONIC_RAW: + precision = -2.0; + break; + } + + if (switch_ns(parent_ns)) + return pr_err("switch_ns(%d)", child_ns); + + if (_gettime(clocks[clock_index].id, &parent_ts_old, raw_syscall)) + return -1; + + child_ts_new.tv_nsec = parent_ts_old.tv_nsec; + child_ts_new.tv_sec = parent_ts_old.tv_sec + offset; + + if (switch_ns(child_ns)) + return pr_err("switch_ns(%d)", child_ns); + + if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall)) + return -1; + + if (difftime(cur_ts.tv_sec, child_ts_new.tv_sec) < precision) { + ksft_test_result_fail( + "Child's %s (%s) time has not changed: %lu -> %lu [%lu]\n", + clocks[clock_index].name, entry, parent_ts_old.tv_sec, + child_ts_new.tv_sec, cur_ts.tv_sec); + return -1; + } + + if (switch_ns(parent_ns)) + return pr_err("switch_ns(%d)", parent_ns); + + if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall)) + return -1; + + if (difftime(cur_ts.tv_sec, parent_ts_old.tv_sec) > DAY_IN_SEC) { + ksft_test_result_fail( + "Parent's %s (%s) time has changed: %lu -> %lu [%lu]\n", + clocks[clock_index].name, entry, parent_ts_old.tv_sec, + child_ts_new.tv_sec, cur_ts.tv_sec); + /* Let's play nice and put it closer to original */ + clock_settime(clocks[clock_index].id, &cur_ts); + return -1; + } + + ksft_test_result_pass("Passed for %s (%s)\n", + clocks[clock_index].name, entry); + return 0; +} + +int main(int argc, char *argv[]) +{ + unsigned int i; + time_t offset; + int ret = 0; + + nscheck(); + + check_config_posix_timers(); + + ksft_set_plan(ARRAY_SIZE(clocks) * 2); + + if (init_namespaces()) + return 1; + + /* Offsets have to be set before tasks enter the namespace. */ + for (i = 0; i < ARRAY_SIZE(clocks); i++) { + if (clocks[i].off_id != -1) + continue; + offset = TEN_DAYS_IN_SEC + i * 1000; + clocks[i].offset = offset; + if (_settime(clocks[i].id, offset)) + return 1; + } + + for (i = 0; i < ARRAY_SIZE(clocks); i++) { + if (clocks[i].off_id != -1) + offset = clocks[clocks[i].off_id].offset; + else + offset = clocks[i].offset; + ret |= test_gettime(i, true, offset); + ret |= test_gettime(i, false, offset); + } + + if (ret) + ksft_exit_fail(); + + ksft_exit_pass(); + return !!ret; +} diff --git a/tools/testing/selftests/timens/timens.h b/tools/testing/selftests/timens/timens.h new file mode 100644 index 000000000000..e09e7e39bc52 --- /dev/null +++ b/tools/testing/selftests/timens/timens.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __TIMENS_H__ +#define __TIMENS_H__ + +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> + +#include "../kselftest.h" + +#ifndef CLONE_NEWTIME +# define CLONE_NEWTIME 0x00000080 +#endif + +static int config_posix_timers = true; + +static inline void check_config_posix_timers(void) +{ + if (timer_create(-1, 0, 0) == -1 && errno == ENOSYS) + config_posix_timers = false; +} + +static inline bool check_skip(int clockid) +{ + if (config_posix_timers) + return false; + + switch (clockid) { + /* Only these clocks are supported without CONFIG_POSIX_TIMERS. */ + case CLOCK_BOOTTIME: + case CLOCK_MONOTONIC: + case CLOCK_REALTIME: + return false; + default: + ksft_test_result_skip("Posix Clocks & timers are not supported\n"); + return true; + } + + return false; +} + +static inline int unshare_timens(void) +{ + if (unshare(CLONE_NEWTIME)) { + if (errno == EPERM) + ksft_exit_skip("need to run as root\n"); + return pr_perror("Can't unshare() timens"); + } + return 0; +} + +static inline int _settime(clockid_t clk_id, time_t offset) +{ + int fd, len; + char buf[4096]; + + if (clk_id == CLOCK_MONOTONIC_COARSE || clk_id == CLOCK_MONOTONIC_RAW) + clk_id = CLOCK_MONOTONIC; + + len = snprintf(buf, sizeof(buf), "%d %ld 0", clk_id, offset); + + fd = open("/proc/self/timens_offsets", O_WRONLY); + if (fd < 0) + return pr_perror("/proc/self/timens_offsets"); + + if (write(fd, buf, len) != len) + return pr_perror("/proc/self/timens_offsets"); + + close(fd); + + return 0; +} + +static inline int _gettime(clockid_t clk_id, struct timespec *res, bool raw_syscall) +{ + int err; + + if (!raw_syscall) { + if (clock_gettime(clk_id, res)) { + pr_perror("clock_gettime(%d)", (int)clk_id); + return -1; + } + return 0; + } + + err = syscall(SYS_clock_gettime, clk_id, res); + if (err) + pr_perror("syscall(SYS_clock_gettime(%d))", (int)clk_id); + + return err; +} + +static inline void nscheck(void) +{ + if (access("/proc/self/ns/time", F_OK) < 0) + ksft_exit_skip("Time namespaces are not supported\n"); +} + +#endif -- 2.24.0
next prev parent reply other threads:[~2019-11-12 1:28 UTC|newest] Thread overview: 160+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-11-12 1:26 [PATCHv8 00/34] kernel: Introduce Time Namespace Dmitry Safonov 2019-11-12 1:26 ` Dmitry Safonov 2019-11-12 1:26 ` [PATCHv8 01/34] lib/vdso: Add unlikely() hint into vdso_read_begin() Dmitry Safonov 2019-11-12 1:26 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:26 ` [PATCHv8 02/34] lib/vdso: make do_hres and do_coarse as __always_inline Dmitry Safonov 2019-11-12 1:26 ` Dmitry Safonov 2020-01-10 9:45 ` Vincenzo Frascino 2020-01-10 9:45 ` Vincenzo Frascino 2020-01-10 11:42 ` Thomas Gleixner 2020-01-10 11:47 ` Vincenzo Frascino 2020-01-10 11:47 ` Vincenzo Frascino 2020-01-10 12:02 ` Thomas Gleixner 2020-01-10 12:18 ` Vincenzo Frascino 2020-01-10 12:18 ` Vincenzo Frascino 2020-01-13 5:27 ` Andrei Vagin 2020-01-13 5:27 ` Andrei Vagin 2020-01-13 19:09 ` [tip: timers/core] lib/vdso: Mark do_hres() and do_coarse() " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:26 ` [PATCHv8 03/34] ns: Introduce Time Namespace Dmitry Safonov 2019-11-12 1:26 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2020-01-27 14:12 ` [PATCHv8 03/34] " Dmitry Vyukov 2020-01-27 14:12 ` Dmitry Vyukov 2020-01-27 14:19 ` Dmitry Safonov 2020-01-27 14:19 ` Dmitry Safonov 2020-02-17 14:20 ` Time Namespaces: CLONE_NEWTIME and clone3()? Michael Kerrisk 2020-02-17 14:59 ` Christian Brauner 2020-02-17 21:47 ` Michael Kerrisk (man-pages) 2020-02-17 23:03 ` Christian Brauner 2020-02-17 23:29 ` Thomas Gleixner 2020-02-18 2:37 ` Eric W. Biederman 2020-02-18 17:11 ` Adrian Reber 2020-02-18 17:26 ` Christian Brauner 2019-11-12 1:26 ` [PATCHv8 04/34] time: Add timens_offsets to be used for tasks in timens Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] time: Add timens_offsets to be used for tasks in time namespace tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:26 ` [PATCHv8 05/34] posix-clocks: Rename the clock_get() callback to clock_get_timespec() Dmitry Safonov 2019-11-12 1:26 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:26 ` [PATCHv8 06/34] posix-clocks: Rename .clock_get_timespec() callbacks accordingly Dmitry Safonov 2019-11-12 1:26 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:26 ` [PATCHv8 07/34] alarmtimer: Rename gettime() callback to get_ktime() Dmitry Safonov 2019-11-12 1:26 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:26 ` [PATCHv8 08/34] alarmtimer: Provide get_timespec() callback Dmitry Safonov 2019-11-12 1:26 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:26 ` [PATCHv8 09/34] posix-clocks: Introduce clock_get_ktime() callback Dmitry Safonov 2019-11-12 1:26 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:26 ` [PATCHv8 10/34] posix-timers: Use clock_get_ktime() in common_timer_get() Dmitry Safonov 2019-11-12 1:26 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:27 ` [PATCHv8 11/34] posix-clocks: Wire up clock_gettime() with timens offsets Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:27 ` [PATCHv8 12/34] kernel: Add do_timens_ktime_to_host() helper Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] time: " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:27 ` [PATCHv8 13/34] timerfd: Make timerfd_settime() time namespace aware Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:27 ` [PATCHv8 14/34] posix-timers: Make timer_settime() " Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:27 ` [PATCHv8 15/34] alarmtimer: Make nanosleep " Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] alarmtimer: Make nanosleep() " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:27 ` [PATCHv8 16/34] hrtimers: Prepare hrtimer_nanosleep() for time namespaces Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:27 ` [PATCHv8 17/34] posix-timers: Make clock_nanosleep() time namespace aware Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:27 ` [PATCHv8 18/34] fs/proc: Respect boottime inside time namespace for /proc/uptime Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Dmitry Safonov 2020-01-14 13:02 ` tip-bot2 for Dmitry Safonov 2019-11-12 1:27 ` [PATCHv8 19/34] x86/vdso: Restrict splitting VVAR VMA Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Dmitry Safonov 2020-01-14 13:02 ` tip-bot2 for Dmitry Safonov 2019-11-12 1:27 ` [PATCHv8 20/34] lib/vdso: Prepare for time namespace support Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-12 10:32 ` Thomas Gleixner 2020-01-12 10:32 ` Thomas Gleixner 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Thomas Gleixner 2020-01-14 13:02 ` tip-bot2 for Thomas Gleixner 2019-11-12 1:27 ` [PATCHv8 21/34] x86/vdso: Provide vdso_data offset on vvar_page Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Dmitry Safonov 2020-01-14 13:02 ` tip-bot2 for Dmitry Safonov 2019-11-12 1:27 ` [PATCHv8 22/34] x86/vdso: Add timens page Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] x86/vdso: Add time napespace page tip-bot2 for Dmitry Safonov 2020-01-14 13:02 ` tip-bot2 for Dmitry Safonov 2019-11-12 1:27 ` [PATCHv8 23/34] time: Allocate per-timens vvar page Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Dmitry Safonov 2020-01-14 13:02 ` tip-bot2 for Dmitry Safonov 2019-11-12 1:27 ` [PATCHv8 24/34] x86/vdso: Handle faults on timens page Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Dmitry Safonov 2020-01-14 13:02 ` tip-bot2 for Dmitry Safonov 2019-11-12 1:27 ` [PATCHv8 25/34] x86/vdso: On timens page fault prefault also VVAR page Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Dmitry Safonov 2020-01-14 13:02 ` tip-bot2 for Dmitry Safonov 2019-11-12 1:27 ` [PATCHv8 26/34] x86/vdso: Zap vvar pages on switch a time namspace Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] x86/vdso: Zap vvar pages when switching to a time namespace tip-bot2 for Dmitry Safonov 2020-01-14 13:02 ` tip-bot2 for Dmitry Safonov 2019-11-12 1:27 ` [PATCHv8 27/34] fs/proc: Introduce /proc/pid/timens_offsets Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:27 ` Dmitry Safonov [this message] 2019-11-12 1:27 ` [PATCHv8 28/34] selftests/timens: Add Time Namespace test for supported clocks Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Dmitry Safonov 2020-01-14 13:02 ` tip-bot2 for Dmitry Safonov 2019-11-12 1:27 ` [PATCHv8 29/34] selftests/timens: Add a test for timerfd Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:27 ` [PATCHv8 30/34] selftests/timens: Add a test for clock_nanosleep() Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:27 ` [PATCHv8 31/34] selftests/timens: Add procfs selftest Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Dmitry Safonov 2020-01-14 13:02 ` tip-bot2 for Dmitry Safonov 2019-11-12 1:27 ` [PATCHv8 32/34] selftests/timens: Add timer offsets test Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:27 ` [PATCHv8 33/34] selftests/timens: Add a simple perf test for clock_gettime() Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-12 1:27 ` [PATCHv8 34/34] selftests/timens: Check for right timens offsets after fork and exec Dmitry Safonov 2019-11-12 1:27 ` Dmitry Safonov 2020-01-13 19:09 ` [tip: timers/core] " tip-bot2 for Andrei Vagin 2020-01-14 13:02 ` tip-bot2 for Andrei Vagin 2019-11-21 18:05 ` [PATCHv8 00/34] kernel: Introduce Time Namespace Andrei Vagin 2019-12-11 20:38 ` Dmitry Safonov 2020-01-09 21:09 ` Thomas Gleixner 2020-01-10 9:52 ` Vincenzo Frascino
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20191112012724.250792-29-dima@arista.com \ --to=dima@arista.com \ --cc=0x7f454c46@gmail.com \ --cc=adrian@lisas.de \ --cc=arnd@arndb.de \ --cc=avagin@gmail.com \ --cc=avagin@openvz.org \ --cc=christian.brauner@ubuntu.com \ --cc=containers@lists.linux-foundation.org \ --cc=criu@openvz.org \ --cc=ebiederm@xmission.com \ --cc=gorcunov@openvz.org \ --cc=hpa@zytor.com \ --cc=jannh@google.com \ --cc=jdike@addtoit.com \ --cc=linux-api@vger.kernel.org \ --cc=linux-kernel@vger.kernel.org \ --cc=luto@kernel.org \ --cc=mingo@redhat.com \ --cc=oleg@redhat.com \ --cc=shuah@kernel.org \ --cc=tglx@linutronix.de \ --cc=vincenzo.frascino@arm.com \ --cc=x86@kernel.org \ --cc=xemul@virtuozzo.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.