brintos

brintos / linux-shallow public Read only

0
0
Text · 4.1 KiB · 3872207 Raw
188 lines · c
1// SPDX-License-Identifier: GPL-2.02#define _GNU_SOURCE3#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 child20 * 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 index30	 * 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 ct45 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	nscheck();155 156	check_supported_timers();157 158	ksft_set_plan(ARRAY_SIZE(clocks) * 2);159 160	if (init_namespaces())161		return 1;162 163	/* Offsets have to be set before tasks enter the namespace. */164	for (i = 0; i < ARRAY_SIZE(clocks); i++) {165		if (clocks[i].off_id != -1)166			continue;167		offset = TEN_DAYS_IN_SEC + i * 1000;168		clocks[i].offset = offset;169		if (_settime(clocks[i].id, offset))170			return 1;171	}172 173	for (i = 0; i < ARRAY_SIZE(clocks); i++) {174		if (clocks[i].off_id != -1)175			offset = clocks[clocks[i].off_id].offset;176		else177			offset = clocks[i].offset;178		ret |= test_gettime(i, true, offset);179		ret |= test_gettime(i, false, offset);180	}181 182	if (ret)183		ksft_exit_fail();184 185	ksft_exit_pass();186	return !!ret;187}188