From: Lennart Poettering Date: Tue, 12 Dec 2023 09:44:57 +0000 (+0100) Subject: cgroup-util: add helpers for opening cgroup by id X-Git-Tag: v256-rc1~283^2~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3b2874952fed9b71726ca08e4c888e02ca275ca2;p=thirdparty%2Fsystemd.git cgroup-util: add helpers for opening cgroup by id --- diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 6991460f86e..8303b376843 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -22,6 +22,7 @@ #include "log.h" #include "login-util.h" #include "macro.h" +#include "missing_fs.h" #include "missing_magic.h" #include "missing_threads.h" #include "mkdir.h" @@ -39,6 +40,38 @@ #include "user-util.h" #include "xattr-util.h" +int cg_path_open(const char *controller, const char *path) { + _cleanup_free_ char *fs = NULL; + int r; + + r = cg_get_path(controller, path, /* item=*/ NULL, &fs); + if (r < 0) + return r; + + return RET_NERRNO(open(fs, O_DIRECTORY|O_CLOEXEC)); +} + +int cg_cgroupid_open(int cgroupfs_fd, uint64_t id) { + _cleanup_close_ int fsfd = -EBADF; + + if (cgroupfs_fd < 0) { + fsfd = open("/sys/fs/cgroup", O_CLOEXEC|O_DIRECTORY); + if (fsfd < 0) + return -errno; + + cgroupfs_fd = fsfd; + } + + cg_file_handle fh = CG_FILE_HANDLE_INIT; + CG_FILE_HANDLE_CGROUPID(fh) = id; + + int fd = open_by_handle_at(cgroupfs_fd, &fh.file_handle, O_DIRECTORY|O_CLOEXEC); + if (fd < 0) + return -errno; + + return fd; +} + static int cg_enumerate_items(const char *controller, const char *path, FILE **ret, const char *item) { _cleanup_free_ char *fs = NULL; FILE *f; @@ -1404,7 +1437,7 @@ int cg_pid_get_machine_name(pid_t pid, char **ret_machine) { int cg_path_get_cgroupid(const char *path, uint64_t *ret) { cg_file_handle fh = CG_FILE_HANDLE_INIT; - int mnt_id = -1; + int mnt_id; assert(path); assert(ret); @@ -1418,6 +1451,20 @@ int cg_path_get_cgroupid(const char *path, uint64_t *ret) { return 0; } +int cg_fd_get_cgroupid(int fd, uint64_t *ret) { + cg_file_handle fh = CG_FILE_HANDLE_INIT; + int mnt_id = -1; + + assert(fd >= 0); + assert(ret); + + if (name_to_handle_at(fd, "", &fh.file_handle, &mnt_id, AT_EMPTY_PATH) < 0) + return -errno; + + *ret = CG_FILE_HANDLE_CGROUPID(fh); + return 0; +} + int cg_path_get_session(const char *path, char **ret_session) { _cleanup_free_ char *unit = NULL; char *start, *end; diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 244f3b657bf..9ad6dd8eb6c 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -180,6 +180,9 @@ typedef enum CGroupUnified { * generate paths with multiple adjacent / removed. */ +int cg_path_open(const char *controller, const char *path); +int cg_cgroupid_open(int fsfd, uint64_t id); + int cg_enumerate_processes(const char *controller, const char *path, FILE **ret); int cg_read_pid(FILE *f, pid_t *ret); int cg_read_pidref(FILE *f, PidRef *ret); @@ -267,6 +270,7 @@ int cg_is_empty_recursive(const char *controller, const char *path); int cg_get_root_path(char **path); int cg_path_get_cgroupid(const char *path, uint64_t *ret); +int cg_fd_get_cgroupid(int fd, uint64_t *ret); int cg_path_get_session(const char *path, char **ret_session); int cg_path_get_owner_uid(const char *path, uid_t *ret_uid); int cg_path_get_unit(const char *path, char **ret_unit); @@ -352,5 +356,10 @@ typedef union { uint8_t space[offsetof(struct file_handle, f_handle) + sizeof(uint64_t)]; } cg_file_handle; -#define CG_FILE_HANDLE_INIT { .file_handle.handle_bytes = sizeof(uint64_t) } +#define CG_FILE_HANDLE_INIT \ + (cg_file_handle) { \ + .file_handle.handle_bytes = sizeof(uint64_t), \ + .file_handle.handle_type = FILEID_KERNFS, \ + } + #define CG_FILE_HANDLE_CGROUPID(fh) (*(uint64_t*) (fh).file_handle.f_handle) diff --git a/src/basic/missing_fs.h b/src/basic/missing_fs.h index ee70ae08dbc..d97b1901316 100644 --- a/src/basic/missing_fs.h +++ b/src/basic/missing_fs.h @@ -111,3 +111,8 @@ assert_cc(FS_PROJINHERIT_FL == 0x20000000); #else assert_cc(FS_KEY_DESCRIPTOR_SIZE == 8); #endif + +/* linux/exportfs.h */ +#ifndef FILEID_KERNFS +#define FILEID_KERNFS 0xfe +#endif diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c index c2ee1c5aef6..c7af10687df 100644 --- a/src/shared/cgroup-show.c +++ b/src/shared/cgroup-show.c @@ -150,18 +150,9 @@ static int show_cgroup_name( delegate = r > 0; if (FLAGS_SET(flags, OUTPUT_CGROUP_ID)) { - cg_file_handle fh = CG_FILE_HANDLE_INIT; - int mnt_id = -1; - - if (name_to_handle_at( - fd, - "", - &fh.file_handle, - &mnt_id, - AT_EMPTY_PATH) < 0) + r = cg_fd_get_cgroupid(fd, &cgroupid); + if (r < 0) log_debug_errno(errno, "Failed to determine cgroup ID of %s, ignoring: %m", path); - else - cgroupid = CG_FILE_HANDLE_CGROUPID(fh); } r = path_extract_filename(path, &b); diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c index 9b174d708b5..06cf8867296 100644 --- a/src/test/test-cgroup.c +++ b/src/test/test-cgroup.c @@ -5,6 +5,7 @@ #include "cgroup-setup.h" #include "cgroup-util.h" #include "errno-util.h" +#include "fd-util.h" #include "path-util.h" #include "process-util.h" #include "string-util.h" @@ -129,4 +130,47 @@ TEST(cg_create) { assert_se(cg_rmdir(SYSTEMD_CGROUP_CONTROLLER, test_a) == 0); } +TEST(id) { + _cleanup_free_ char *p = NULL, *p2 = NULL; + _cleanup_close_ int fd = -EBADF, fd2 = -EBADF; + uint64_t id, id2; + int r; + + r = cg_all_unified(); + if (r == 0) { + log_tests_skipped("skipping cgroupid test, not running in unified mode"); + return; + } + if (IN_SET(r, -ENOMEDIUM, -ENOENT)) { + log_tests_skipped("cgroupfs is not mounted"); + return; + } + assert_se(r > 0); + + fd = cg_path_open(SYSTEMD_CGROUP_CONTROLLER, "/"); + assert_se(fd >= 0); + + assert_se(fd_get_path(fd, &p) >= 0); + assert_se(path_equal(p, "/sys/fs/cgroup")); + + assert_se(cg_fd_get_cgroupid(fd, &id) >= 0); + + fd2 = cg_cgroupid_open(fd, id); + + if (ERRNO_IS_NEG_PRIVILEGE(fd2)) + log_notice("Skipping open-by-cgroup-id test because lacking privs."); + else { + assert_se(fd2 >= 0); + + assert_se(fd_get_path(fd2, &p2) >= 0); + assert_se(path_equal(p2, "/sys/fs/cgroup")); + + assert_se(cg_fd_get_cgroupid(fd2, &id2) >= 0); + + assert_se(id == id2); + + assert_se(inode_same_at(fd, NULL, fd2, NULL, AT_EMPTY_PATH) > 0); + } +} + DEFINE_TEST_MAIN(LOG_DEBUG);