diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 6fb4d55958..d613e65c4b 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -35,21 +35,6 @@ #include "user-util.h" #include "xattr-util.h" -/* The structure to pass to name_to_handle_at() on cgroupfs2 */ -typedef union { - struct file_handle file_handle; - uint8_t space[MAX_HANDLE_SZ]; -} cg_file_handle; - -#define CG_FILE_HANDLE_INIT \ - (cg_file_handle) { \ - .file_handle.handle_bytes = sizeof(uint64_t), \ - .file_handle.handle_type = FILEID_KERNFS, \ - } - -/* The .f_handle field is not aligned to 64bit on some archs, hence read it via an unaligned accessor */ -#define CG_FILE_HANDLE_CGROUPID(fh) unaligned_read_ne64(fh.file_handle.f_handle) - int cg_is_available(void) { struct statfs fs; @@ -85,7 +70,14 @@ int cg_cgroupid_open(int cgroupfs_fd, uint64_t id) { cgroupfs_fd = fsfd; } - cg_file_handle fh = CG_FILE_HANDLE_INIT; + union { + struct file_handle file_handle; + uint8_t space[offsetof(struct file_handle, f_handle) + sizeof(uint64_t)]; + } fh = { + .file_handle.handle_bytes = sizeof(uint64_t), + .file_handle.handle_type = FILEID_KERNFS, + }; + unaligned_write_ne64(fh.file_handle.f_handle, id); return RET_NERRNO(open_by_handle_at(cgroupfs_fd, &fh.file_handle, O_DIRECTORY|O_CLOEXEC)); @@ -112,24 +104,6 @@ int cg_path_from_cgroupid(int cgroupfs_fd, uint64_t id, char **ret) { return 0; } -int cg_get_cgroupid_at(int dfd, const char *path, uint64_t *ret) { - cg_file_handle fh = CG_FILE_HANDLE_INIT; - int mnt_id; - - assert(dfd >= 0 || (dfd == AT_FDCWD && path_is_absolute(path))); - assert(ret); - - /* This is cgroupfs so we know the size of the handle, thus no need to loop around like - * name_to_handle_at_loop() does in mountpoint-util.c */ - if (name_to_handle_at(dfd, strempty(path), &fh.file_handle, &mnt_id, isempty(path) ? AT_EMPTY_PATH : 0) < 0) { - assert(errno != EOVERFLOW); - return -errno; - } - - *ret = CG_FILE_HANDLE_CGROUPID(fh); - return 0; -} - int cg_enumerate_processes(const char *path, FILE **ret) { _cleanup_free_ char *fs = NULL; FILE *f; diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 641a179526..68a771e5ae 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -125,13 +125,6 @@ int cg_path_open(const char *path); int cg_cgroupid_open(int cgroupfs_fd, uint64_t id); int cg_path_from_cgroupid(int cgroupfs_fd, uint64_t id, char **ret); -int cg_get_cgroupid_at(int dfd, const char *path, uint64_t *ret); -static inline int cg_path_get_cgroupid(const char *path, uint64_t *ret) { - return cg_get_cgroupid_at(AT_FDCWD, path, ret); -} -static inline int cg_fd_get_cgroupid(int fd, uint64_t *ret) { - return cg_get_cgroupid_at(fd, NULL, ret); -} typedef enum CGroupFlags { CGROUP_SIGCONT = 1 << 0, diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c index 9c04d381f3..547183395e 100644 --- a/src/basic/mountpoint-util.c +++ b/src/basic/mountpoint-util.c @@ -17,6 +17,7 @@ #include "stat-util.h" #include "string-util.h" #include "strv.h" +#include "unaligned.h" /* This is the original MAX_HANDLE_SZ definition from the kernel, when the API was introduced. We use that in place of * any more currently defined value to future-proof things: if the size is increased in the API headers, and our code @@ -63,6 +64,11 @@ int name_to_handle_at_loop( * This improves on raw name_to_handle_at() also in one other regard: ret_handle and ret_mnt_id can be passed * as NULL if there's no interest in either. */ + if (isempty(path)) { + flags |= AT_EMPTY_PATH; + path = ""; + } + for (;;) { _cleanup_free_ struct file_handle *h = NULL; int mnt_id = -1; @@ -73,7 +79,7 @@ int name_to_handle_at_loop( h->handle_bytes = n; - if (name_to_handle_at(fd, strempty(path), h, &mnt_id, flags) >= 0) { + if (name_to_handle_at(fd, path, h, &mnt_id, flags) >= 0) { if (ret_handle) *ret_handle = TAKE_PTR(h); @@ -133,6 +139,27 @@ int name_to_handle_at_try_fid( return name_to_handle_at_loop(fd, path, ret_handle, ret_mnt_id, flags & ~AT_HANDLE_FID); } +int name_to_handle_at_u64(int fd, const char *path, uint64_t *ret) { + _cleanup_free_ struct file_handle *h = NULL; + int r; + + assert(fd >= 0 || fd == AT_FDCWD); + + /* This provides the first 64bit of the file handle. */ + + r = name_to_handle_at_loop(fd, path, &h, /* ret_mnt_id= */ NULL, /* flags= */ 0); + if (r < 0) + return r; + if (h->handle_bytes < sizeof(uint64_t)) + return -EBADMSG; + + if (ret) + /* Note, "struct file_handle" is 32bit aligned usually, but we need to read a 64bit value from it */ + *ret = unaligned_read_ne64(h->f_handle); + + return 0; +} + bool file_handle_equal(const struct file_handle *a, const struct file_handle *b) { if (a == b) return true; diff --git a/src/basic/mountpoint-util.h b/src/basic/mountpoint-util.h index 659f038556..8799224f3d 100644 --- a/src/basic/mountpoint-util.h +++ b/src/basic/mountpoint-util.h @@ -36,6 +36,13 @@ bool is_name_to_handle_at_fatal_error(int err); int name_to_handle_at_loop(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags); int name_to_handle_at_try_fid(int fd, const char *path, struct file_handle **ret_handle, int *ret_mnt_id, int flags); +int name_to_handle_at_u64(int fd, const char *path, uint64_t *ret); +static inline int path_to_handle_u64(const char *path, uint64_t *ret) { + return name_to_handle_at_u64(AT_FDCWD, path, ret); +} +static inline int fd_to_handle_u64(int fd, uint64_t *ret) { + return name_to_handle_at_u64(fd, NULL, ret); +} bool file_handle_equal(const struct file_handle *a, const struct file_handle *b); diff --git a/src/basic/pidfd-util.c b/src/basic/pidfd-util.c index 8c4c832452..7bfe83d319 100644 --- a/src/basic/pidfd-util.c +++ b/src/basic/pidfd-util.c @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include #include #include #include @@ -236,25 +235,10 @@ int pidfd_get_inode_id_impl(int fd, uint64_t *ret) { assert(fd >= 0); + /* Since kernel 6.14 (b3caba8f7a34a2bbaf45ffc6ff3a49b70afeb192), we can use name_to_handle_at(). */ if (file_handle_supported) { - union { - struct file_handle file_handle; - uint8_t space[MAX_HANDLE_SZ]; - } fh = { - .file_handle.handle_bytes = sizeof(uint64_t), - .file_handle.handle_type = FILEID_KERNFS, - }; - int mnt_id; - - r = RET_NERRNO(name_to_handle_at(fd, "", &fh.file_handle, &mnt_id, AT_EMPTY_PATH)); - if (r >= 0) { - if (ret) - /* Note, "struct file_handle" is 32bit aligned usually, but we need to read a 64bit value from it */ - *ret = unaligned_read_ne64(fh.file_handle.f_handle); - return 0; - } - assert(r != -EOVERFLOW); - if (is_name_to_handle_at_fatal_error(r)) + r = fd_to_handle_u64(fd, ret); + if (r >= 0 || is_name_to_handle_at_fatal_error(r)) return r; file_handle_supported = false; diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 35c0898e03..ad889db3b9 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -34,6 +34,7 @@ #include "ip-protocol-list.h" #include "limits-util.h" #include "manager.h" +#include "mountpoint-util.h" #include "netlink-internal.h" #include "nulstr-util.h" #include "parse-util.h" @@ -2069,13 +2070,14 @@ static int unit_update_cgroup( uint64_t cgroup_id = 0; r = cg_get_path(crt->cgroup_path, /* suffix= */ NULL, &cgroup_full_path); - if (r == 0) { - r = cg_path_get_cgroupid(cgroup_full_path, &cgroup_id); + if (r < 0) + log_unit_warning_errno(u, r, "Failed to get full cgroup path on cgroup %s, ignoring: %m", empty_to_root(crt->cgroup_path)); + else { + r = path_to_handle_u64(cgroup_full_path, &cgroup_id); if (r < 0) log_unit_full_errno(u, ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r, "Failed to get cgroup ID of cgroup %s, ignoring: %m", cgroup_full_path); - } else - log_unit_warning_errno(u, r, "Failed to get full cgroup path on cgroup %s, ignoring: %m", empty_to_root(crt->cgroup_path)); + } crt->cgroup_id = cgroup_id; diff --git a/src/nsresourced/nsresourcework.c b/src/nsresourced/nsresourcework.c index 7004d03c48..60d3a01ce0 100644 --- a/src/nsresourced/nsresourcework.c +++ b/src/nsresourced/nsresourcework.c @@ -1354,7 +1354,7 @@ static int validate_cgroup(sd_varlink *link, int fd, uint64_t *ret_cgroup_id) { if (r == 0) return sd_varlink_error_invalid_parameter_name(link, "controlGroupFileDescriptor"); - r = cg_fd_get_cgroupid(fd, ret_cgroup_id); + r = fd_to_handle_u64(fd, ret_cgroup_id); if (r < 0) return log_debug_errno(r, "Failed to read cgroup ID from cgroupfs: %m"); diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c index 109fe016f5..cfc80d666f 100644 --- a/src/shared/cgroup-show.c +++ b/src/shared/cgroup-show.c @@ -18,6 +18,7 @@ #include "glyph-util.h" #include "hostname-util.h" #include "log.h" +#include "mountpoint-util.h" #include "nulstr-util.h" #include "output-mode.h" #include "path-util.h" @@ -150,7 +151,7 @@ static int show_cgroup_name( delegate = r > 0; if (FLAGS_SET(flags, OUTPUT_CGROUP_ID)) { - r = cg_fd_get_cgroupid(fd, &cgroupid); + r = fd_to_handle_u64(fd, &cgroupid); if (r < 0) log_debug_errno(r, "Failed to determine cgroup ID of %s, ignoring: %m", path); } diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c index 0fd81284e8..b8393f3368 100644 --- a/src/test/test-cgroup-util.c +++ b/src/test/test-cgroup-util.c @@ -7,6 +7,7 @@ #include "errno-util.h" #include "fd-util.h" #include "format-util.h" +#include "mountpoint-util.h" #include "path-util.h" #include "pidref.h" #include "process-util.h" @@ -493,7 +494,7 @@ TEST(cgroupid) { ASSERT_OK(fd_get_path(fd, &p)); ASSERT_TRUE(path_equal(p, "/sys/fs/cgroup")); - ASSERT_OK(cg_fd_get_cgroupid(fd, &id)); + ASSERT_OK(fd_to_handle_u64(fd, &id)); fd2 = cg_cgroupid_open(fd, id); @@ -509,7 +510,7 @@ TEST(cgroupid) { ASSERT_OK(fd_get_path(fd2, &p2)); ASSERT_TRUE(path_equal(p2, "/sys/fs/cgroup")); - ASSERT_OK(cg_fd_get_cgroupid(fd2, &id2)); + ASSERT_OK(fd_to_handle_u64(fd2, &id2)); ASSERT_EQ(id, id2);