Introduce name_to_handle_at_u64() helper function and use it for getting pidfd ID and cgroup ID (#40500)
This commit is contained in:
+8
-34
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
+3
-19
@@ -1,6 +1,5 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/magic.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <threads.h>
|
||||
@@ -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;
|
||||
|
||||
+6
-4
@@ -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;
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user