From 2c8198c9c2ff82b8ec84737a595a18956378a2f8 Mon Sep 17 00:00:00 2001 From: James Muir Date: Fri, 14 Feb 2025 16:06:42 -0500 Subject: [PATCH 1/3] WIP 1 Share the first part of the Cisco patch authored by Oleksiy Obitotskyy to fix reading from /proc/schedstat post-switch-root (see #60). More changes are needed since writing the svg file fails. --- src/store.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/src/store.c b/src/store.c index 785d408..e64af79 100644 --- a/src/store.c +++ b/src/store.c @@ -20,6 +20,8 @@ along with systemd; If not, see . ***/ +#define _POSIX_C_SOURCE + #include #include #include @@ -29,6 +31,7 @@ #include #include #include +#include #include "alloc-util.h" #include "bootchart.h" @@ -119,6 +122,68 @@ static void garbage_collect_dead_processes(struct ps_struct *ps_first) { } } +static int proc_read_full_file(int procfd, const char *fn, char **contents, size_t *size) { + int fd = -1; + size_t n, l; + _cleanup_free_ char *buf = NULL; + struct stat st; + + fd = openat(procfd, fn, O_RDONLY|O_CLOEXEC); + if (fd < 0) + return log_error_errno(errno, "Failed to openat /proc/<>: %m"); + + if (fstatat(procfd, fn, &st, 0) < 0) + return log_error_errno(errno, "Failed to fstatat /proc/<>: %m"); + + n = LINE_MAX; + if (S_ISREG(st.st_mode)) { + + /* Safety check */ + if (st.st_size > 4*1024*1024) + return -E2BIG; + + /* Start with the right file size, but be prepared for + * files from /proc which generally report a file size + * of 0 */ + if (st.st_size > 0) + n = st.st_size; + } + + l = 0; + for (;;) { + char *t; + ssize_t k; + + t = realloc(buf, n+1); + if (!t) + return -ENOMEM; + + buf = t; + k = pread(fd, buf + l, n - l, l); + + if (k < 0) + return log_error_errno(errno, "Failed to pread /proc/<>: %m"); + if (k == 0) + break; + + l += k; + n *= 2; + + /* Safety check */ + if (n > 4*1024*1024) + return -E2BIG; + } + + buf[l] = 0; + *contents = buf; + buf = NULL; /* do not free */ + + if (size) + *size = l; + + safe_close(fd); + return 0; +} int log_sample(DIR *proc, int sample, @@ -189,7 +254,7 @@ int log_sample(DIR *proc, } /* Parse "/proc/schedstat" for overall CPU utilization */ - r = read_full_file("/proc/schedstat", &buf_schedstat, NULL); + r = proc_read_full_file(procfd, "schedstat", &buf_schedstat, NULL); if (r < 0) return log_error_errno(r, "Unable to read schedstat: %m"); From 3f1dccd4d03373504a3a722bbcc63198d16fa027 Mon Sep 17 00:00:00 2001 From: James Muir Date: Fri, 21 Feb 2025 08:17:15 -0500 Subject: [PATCH 2/3] use fstat(), include filename in error messages. --- src/store.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/store.c b/src/store.c index e64af79..9670042 100644 --- a/src/store.c +++ b/src/store.c @@ -130,10 +130,10 @@ static int proc_read_full_file(int procfd, const char *fn, char **contents, size fd = openat(procfd, fn, O_RDONLY|O_CLOEXEC); if (fd < 0) - return log_error_errno(errno, "Failed to openat /proc/<>: %m"); + return log_error_errno(errno, "Failed to openat /proc/%s: %m", fn); - if (fstatat(procfd, fn, &st, 0) < 0) - return log_error_errno(errno, "Failed to fstatat /proc/<>: %m"); + if (fstat(fd, &st) < 0) + return log_error_errno(errno, "Failed to fstat /proc/%s: %m", fn); n = LINE_MAX; if (S_ISREG(st.st_mode)) { @@ -162,7 +162,7 @@ static int proc_read_full_file(int procfd, const char *fn, char **contents, size k = pread(fd, buf + l, n - l, l); if (k < 0) - return log_error_errno(errno, "Failed to pread /proc/<>: %m"); + return log_error_errno(errno, "Failed to pread /proc/%s: %m", fn); if (k == 0) break; From 44c66604bb96c49daac9589f521e01fdfe142ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alfonso=20S=C3=A1nchez-Beato?= Date: Mon, 25 Aug 2025 16:16:02 -0400 Subject: [PATCH 3/3] chroot before systemd switches root chroot to the directory where systemd switches root from the initramfs. Otherwise the svg file cannot be saved. --- src/bootchart.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/src/bootchart.c b/src/bootchart.c index 15aaa2e..dfe7258 100644 --- a/src/bootchart.c +++ b/src/bootchart.c @@ -44,6 +44,8 @@ #include #include #include +#include +#include #ifdef HAVE_LIBSYSTEMD #include @@ -310,6 +312,38 @@ static int do_journal_append(char *file) { return 0; } + +static int is_mountpoint(const char *path) { + struct stat s_path, s_parent; + char *path_aux, *parent_path; + + // Root is always a mountpoint + if (strcmp(path, "/") == 0) { + return 1; + } + + if (stat(path, &s_path) == -1) { + return -1; + } + + // Duplicate path as dirname can modify it + path_aux = strdup(path); + if (!path_aux) { + return -1; + } + + parent_path = dirname(path_aux); + if (stat(parent_path, &s_parent) == -1) { + free(path_aux); + return -1; + } + + free(path_aux); + + // mount point if the directory and its parent are on different devices (filesystems) + return (s_path.st_dev != s_parent.st_dev); +} + int main(int argc, char *argv[]) { static struct list_sample_data *sampledata; _cleanup_closedir_ DIR *proc = NULL; @@ -333,6 +367,7 @@ int main(int argc, char *argv[]) { .sa_handler = signal_handler, }; bool has_procfs = false; + bool sysroot_mounted = false; parse_conf(); @@ -433,6 +468,25 @@ int main(int argc, char *argv[]) { if (r < 0) return EXIT_FAILURE; } + if (!sysroot_mounted) { + // sysroot is where systemd will switch root when + // switching from initramfs to the root fs. We chroot + // there so we can write later the svg file. + // + // TODO instead of detecting this way, use signal from initramfs service. + sysroot_mounted = is_mountpoint("/sysroot") == 1; + if (sysroot_mounted) { + // chroot does not change the cwd of the process, so we do that first + if (chdir("/sysroot") != 0) { + log_info_errno(errno, "cannot chdir to /sysroot: %m\n"); + return EXIT_FAILURE; + } + if (chroot(".") != 0) { + log_info_errno(errno, "cannot chroot: %m\n"); + return EXIT_FAILURE; + } + } + } sample_stop = gettime_ns();