timens.c 4.1 KB

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