Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #define _GNU_SOURCE
0003 #include <errno.h>
0004 #include <fcntl.h>
0005 #include <sched.h>
0006 #include <stdio.h>
0007 #include <stdbool.h>
0008 #include <sys/stat.h>
0009 #include <sys/syscall.h>
0010 #include <sys/types.h>
0011 #include <time.h>
0012 #include <unistd.h>
0013 #include <string.h>
0014 
0015 #include "log.h"
0016 #include "timens.h"
0017 
0018 /*
0019  * Test shouldn't be run for a day, so add 10 days to child
0020  * time and check parent's time to be in the same day.
0021  */
0022 #define DAY_IN_SEC          (60*60*24)
0023 #define TEN_DAYS_IN_SEC         (10*DAY_IN_SEC)
0024 
0025 struct test_clock {
0026     clockid_t id;
0027     char *name;
0028     /*
0029      * off_id is -1 if a clock has own offset, or it contains an index
0030      * which contains a right offset of this clock.
0031      */
0032     int off_id;
0033     time_t offset;
0034 };
0035 
0036 #define ct(clock, off_id)   { clock, #clock, off_id }
0037 static struct test_clock clocks[] = {
0038     ct(CLOCK_BOOTTIME, -1),
0039     ct(CLOCK_BOOTTIME_ALARM, 1),
0040     ct(CLOCK_MONOTONIC, -1),
0041     ct(CLOCK_MONOTONIC_COARSE, 1),
0042     ct(CLOCK_MONOTONIC_RAW, 1),
0043 };
0044 #undef ct
0045 
0046 static int child_ns, parent_ns = -1;
0047 
0048 static int switch_ns(int fd)
0049 {
0050     if (setns(fd, CLONE_NEWTIME)) {
0051         pr_perror("setns()");
0052         return -1;
0053     }
0054 
0055     return 0;
0056 }
0057 
0058 static int init_namespaces(void)
0059 {
0060     char path[] = "/proc/self/ns/time_for_children";
0061     struct stat st1, st2;
0062 
0063     if (parent_ns == -1) {
0064         parent_ns = open(path, O_RDONLY);
0065         if (parent_ns <= 0)
0066             return pr_perror("Unable to open %s", path);
0067     }
0068 
0069     if (fstat(parent_ns, &st1))
0070         return pr_perror("Unable to stat the parent timens");
0071 
0072     if (unshare_timens())
0073         return  -1;
0074 
0075     child_ns = open(path, O_RDONLY);
0076     if (child_ns <= 0)
0077         return pr_perror("Unable to open %s", path);
0078 
0079     if (fstat(child_ns, &st2))
0080         return pr_perror("Unable to stat the timens");
0081 
0082     if (st1.st_ino == st2.st_ino)
0083         return pr_perror("The same child_ns after CLONE_NEWTIME");
0084 
0085     return 0;
0086 }
0087 
0088 static int test_gettime(clockid_t clock_index, bool raw_syscall, time_t offset)
0089 {
0090     struct timespec child_ts_new, parent_ts_old, cur_ts;
0091     char *entry = raw_syscall ? "syscall" : "vdso";
0092     double precision = 0.0;
0093 
0094     if (check_skip(clocks[clock_index].id))
0095         return 0;
0096 
0097     switch (clocks[clock_index].id) {
0098     case CLOCK_MONOTONIC_COARSE:
0099     case CLOCK_MONOTONIC_RAW:
0100         precision = -2.0;
0101         break;
0102     }
0103 
0104     if (switch_ns(parent_ns))
0105         return pr_err("switch_ns(%d)", child_ns);
0106 
0107     if (_gettime(clocks[clock_index].id, &parent_ts_old, raw_syscall))
0108         return -1;
0109 
0110     child_ts_new.tv_nsec = parent_ts_old.tv_nsec;
0111     child_ts_new.tv_sec = parent_ts_old.tv_sec + offset;
0112 
0113     if (switch_ns(child_ns))
0114         return pr_err("switch_ns(%d)", child_ns);
0115 
0116     if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall))
0117         return -1;
0118 
0119     if (difftime(cur_ts.tv_sec, child_ts_new.tv_sec) < precision) {
0120         ksft_test_result_fail(
0121             "Child's %s (%s) time has not changed: %lu -> %lu [%lu]\n",
0122             clocks[clock_index].name, entry, parent_ts_old.tv_sec,
0123             child_ts_new.tv_sec, cur_ts.tv_sec);
0124         return -1;
0125     }
0126 
0127     if (switch_ns(parent_ns))
0128         return pr_err("switch_ns(%d)", parent_ns);
0129 
0130     if (_gettime(clocks[clock_index].id, &cur_ts, raw_syscall))
0131         return -1;
0132 
0133     if (difftime(cur_ts.tv_sec, parent_ts_old.tv_sec) > DAY_IN_SEC) {
0134         ksft_test_result_fail(
0135             "Parent's %s (%s) time has changed: %lu -> %lu [%lu]\n",
0136             clocks[clock_index].name, entry, parent_ts_old.tv_sec,
0137             child_ts_new.tv_sec, cur_ts.tv_sec);
0138         /* Let's play nice and put it closer to original */
0139         clock_settime(clocks[clock_index].id, &cur_ts);
0140         return -1;
0141     }
0142 
0143     ksft_test_result_pass("Passed for %s (%s)\n",
0144                 clocks[clock_index].name, entry);
0145     return 0;
0146 }
0147 
0148 int main(int argc, char *argv[])
0149 {
0150     unsigned int i;
0151     time_t offset;
0152     int ret = 0;
0153 
0154     nscheck();
0155 
0156     check_supported_timers();
0157 
0158     ksft_set_plan(ARRAY_SIZE(clocks) * 2);
0159 
0160     if (init_namespaces())
0161         return 1;
0162 
0163     /* Offsets have to be set before tasks enter the namespace. */
0164     for (i = 0; i < ARRAY_SIZE(clocks); i++) {
0165         if (clocks[i].off_id != -1)
0166             continue;
0167         offset = TEN_DAYS_IN_SEC + i * 1000;
0168         clocks[i].offset = offset;
0169         if (_settime(clocks[i].id, offset))
0170             return 1;
0171     }
0172 
0173     for (i = 0; i < ARRAY_SIZE(clocks); i++) {
0174         if (clocks[i].off_id != -1)
0175             offset = clocks[clocks[i].off_id].offset;
0176         else
0177             offset = clocks[i].offset;
0178         ret |= test_gettime(i, true, offset);
0179         ret |= test_gettime(i, false, offset);
0180     }
0181 
0182     if (ret)
0183         ksft_exit_fail();
0184 
0185     ksft_exit_pass();
0186     return !!ret;
0187 }