Merge tag 'time-namespace-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux

Pull time namespace updates from Christian Brauner:
 "When time namespaces were introduced we missed to virtualize the
  'btime' field in /proc/stat. This confuses tasks which are in another
  time namespace with a virtualized boottime which is common in some
  container workloads. This contains Michael's series to fix 'btime'
  which Thomas asked me to take through my tree.

  To fix 'btime' virtualization we simply subtract the offset of the
  time namespace's boottime from btime before printing the stats. Note
  that since start_boottime of processes are seconds since boottime and
  the boottime stamp is now shifted according to the time namespace's
  offset, the offset of the time namespace also needs to be applied
  before the process stats are given to userspace. This avoids that
  processes shown by tools such as 'ps' appear as time travelers in the
  corresponding time namespace.

  Selftests are included to verify that btime virtualization in
  /proc/stat works as expected"

* tag 'time-namespace-v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux:
  namespace: make timens_on_fork() return nothing
  selftests/timens: added selftest for /proc/stat btime
  fs/proc: apply the time namespace offset to /proc/stat btime
  timens: additional helper functions for boottime offset handling
This commit is contained in:
Linus Torvalds
2020-12-14 16:35:39 -08:00
6 changed files with 92 additions and 16 deletions
+57 -1
View File
@@ -93,6 +93,33 @@ static int read_proc_uptime(struct timespec *uptime)
return 0;
}
static int read_proc_stat_btime(unsigned long long *boottime_sec)
{
FILE *proc;
char line_buf[2048];
proc = fopen("/proc/stat", "r");
if (proc == NULL) {
pr_perror("Unable to open /proc/stat");
return -1;
}
while (fgets(line_buf, 2048, proc)) {
if (sscanf(line_buf, "btime %llu", boottime_sec) != 1)
continue;
fclose(proc);
return 0;
}
if (errno) {
pr_perror("fscanf");
fclose(proc);
return -errno;
}
pr_err("failed to parse /proc/stat");
fclose(proc);
return -1;
}
static int check_uptime(void)
{
struct timespec uptime_new, uptime_old;
@@ -123,18 +150,47 @@ static int check_uptime(void)
return 0;
}
static int check_stat_btime(void)
{
unsigned long long btime_new, btime_old;
unsigned long long btime_expected;
if (switch_ns(parent_ns))
return pr_err("switch_ns(%d)", parent_ns);
if (read_proc_stat_btime(&btime_old))
return 1;
if (switch_ns(child_ns))
return pr_err("switch_ns(%d)", child_ns);
if (read_proc_stat_btime(&btime_new))
return 1;
btime_expected = btime_old - TEN_DAYS_IN_SEC;
if (btime_new != btime_expected) {
pr_fail("btime in /proc/stat: old %llu, new %llu [%llu]",
btime_old, btime_new, btime_expected);
return 1;
}
ksft_test_result_pass("Passed for /proc/stat btime\n");
return 0;
}
int main(int argc, char *argv[])
{
int ret = 0;
nscheck();
ksft_set_plan(1);
ksft_set_plan(2);
if (init_namespaces())
return 1;
ret |= check_uptime();
ret |= check_stat_btime();
if (ret)
ksft_exit_fail();