File Index
Files and directories
Sign in
FILE

timens.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/timens/timens.c C
  1// SPDX-License-Identifier: GPL-2.0
  2#define _GNU_SOURCE
  3#include <errno.h>
  4#include <fcntl.h>
  5#include <sched.h>
  6#include <stdio.h>
  7#include <stdbool.h>
  8#include <sys/stat.h>
  9#include <sys/syscall.h>
 10#include <sys/types.h>
 11#include <time.h>
 12#include <unistd.h>
 13#include <string.h>
 14
 15#include "log.h"
 16#include "timens.h"
 17
 18/*
 19 * Test shouldn't be run for a day, so add 10 days to child
 20 * time and check parent's time to be in the same day.
 21 */
 22#define DAY_IN_SEC			(60*60*24)
 23#define TEN_DAYS_IN_SEC			(10*DAY_IN_SEC)
 24
 25struct test_clock {
 26	clockid_t id;
 27	char *name;
 28	/*
 29	 * off_id is -1 if a clock has own offset, or it contains an index
 30	 * which contains a right offset of this clock.
 31	 */
 32	int off_id;
 33	time_t offset;
 34};
 35
 36#define ct(clock, off_id)	{ clock, #clock, off_id }
 37static struct test_clock clocks[] = {
 38	ct(CLOCK_BOOTTIME, -1),
 39	ct(CLOCK_BOOTTIME_ALARM, 1),
 40	ct(CLOCK_MONOTONIC, -1),
 41	ct(CLOCK_MONOTONIC_COARSE, 1),
 42	ct(CLOCK_MONOTONIC_RAW, 1),
 43};
 44#undef ct
 45
 46static int child_ns, parent_ns = -1;
 47
 48static int switch_ns(int fd)
 49{
 50	if (setns(fd, CLONE_NEWTIME)) {
 51		pr_perror("setns()");
 52		return -1;
 53	}
 54
 55	return 0;
 56}
 57
 58static int init_namespaces(void)
 59{
 60	char path[] = "/proc/self/ns/time_for_children";
 61	struct stat st1, st2;
 62
 63	if (parent_ns == -1) {
 64		parent_ns = open(path, O_RDONLY);
 65		if (parent_ns <= 0)
 66			return pr_perror("Unable to open %s", path);
 67	}
 68
 69	if (fstat(parent_ns, &st1))
 70		return pr_perror("Unable to stat the parent timens");
 71
 72	if (unshare_timens())
 73		return  -1;
 74
 75	child_ns = open(path, O_RDONLY);
 76	if (child_ns <= 0)
 77		return pr_perror("Unable to open %s", path);
 78
 79	if (fstat(child_ns, &st2))
 80		return pr_perror("Unable to stat the timens");
 81
 82	if (st1.st_ino == st2.st_ino)
 83		return pr_perror("The same child_ns after CLONE_NEWTIME");
 84
 85	return 0;
 86}
 87
 88static int test_gettime(clockid_t clock_index, bool raw_syscall, time_t offset)
 89{
 90	struct timespec child_ts_new, parent_ts_old, cur_ts;
 91	char *entry = raw_syscall ? "syscall" : "vdso";
 92	double precision = 0.0;
 93
 94	if (check_skip(clocks[clock_index].id))
 95		return 0;
 96
 97	switch (clocks[clock_index].id) {
 98	case CLOCK_MONOTONIC_COARSE:
 99	case CLOCK_MONOTONIC_RAW:
100		precision = -2.0;
101		break;
102	}
103
104	if (switch_ns(parent_ns))
105		return pr_err("switch_ns(%d)", child_ns);
106
107	if (_gettime(clocks[clock_index].id, &parent_ts_old, raw_syscall))
108		return -1;
109
110	child_ts_new.tv_nsec = parent_ts_old.tv_nsec;
111	child_ts_new.tv_sec = parent_ts_old.tv_sec + offset;
112
113	if (switch_ns(child_ns))
114		return pr_err("switch_ns(%d)", child_ns);
115
116	if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall))
117		return -1;
118
119	if (difftime(cur_ts.tv_sec, child_ts_new.tv_sec) < precision) {
120		ksft_test_result_fail(
121			"Child's %s (%s) time has not changed: %lu -> %lu [%lu]\n",
122			clocks[clock_index].name, entry, parent_ts_old.tv_sec,
123			child_ts_new.tv_sec, cur_ts.tv_sec);
124		return -1;
125	}
126
127	if (switch_ns(parent_ns))
128		return pr_err("switch_ns(%d)", parent_ns);
129
130	if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall))
131		return -1;
132
133	if (difftime(cur_ts.tv_sec, parent_ts_old.tv_sec) > DAY_IN_SEC) {
134		ksft_test_result_fail(
135			"Parent's %s (%s) time has changed: %lu -> %lu [%lu]\n",
136			clocks[clock_index].name, entry, parent_ts_old.tv_sec,
137			child_ts_new.tv_sec, cur_ts.tv_sec);
138		/* Let's play nice and put it closer to original */
139		clock_settime(clocks[clock_index].id, &cur_ts);
140		return -1;
141	}
142
143	ksft_test_result_pass("Passed for %s (%s)\n",
144				clocks[clock_index].name, entry);
145	return 0;
146}
147
148int main(int argc, char *argv[])
149{
150	unsigned int i;
151	time_t offset;
152	int ret = 0;
153
154	ksft_print_header();
155
156	nscheck();
157
158	check_supported_timers();
159
160	ksft_set_plan(ARRAY_SIZE(clocks) * 2);
161
162	if (init_namespaces())
163		return 1;
164
165	/* Offsets have to be set before tasks enter the namespace. */
166	for (i = 0; i < ARRAY_SIZE(clocks); i++) {
167		if (clocks[i].off_id != -1)
168			continue;
169		offset = TEN_DAYS_IN_SEC + i * 1000;
170		clocks[i].offset = offset;
171		if (_settime(clocks[i].id, offset))
172			return 1;
173	}
174
175	for (i = 0; i < ARRAY_SIZE(clocks); i++) {
176		if (clocks[i].off_id != -1)
177			offset = clocks[clocks[i].off_id].offset;
178		else
179			offset = clocks[i].offset;
180		ret |= test_gettime(i, true, offset);
181		ret |= test_gettime(i, false, offset);
182	}
183
184	if (ret)
185		ksft_exit_fail();
186
187	ksft_exit_pass();
188	return !!ret;
189}
~/ Read-only file preview.