From 2a7451dc5dba7de5884d39771226e63b1e64159f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 5 Oct 2023 12:45:38 +0200 Subject: [PATCH] pid1: serialize pidrefs as pidfds if possible One major step towards total pidfdification of systemd. --- src/core/mount.c | 8 ++---- src/core/scope.c | 11 +++++--- src/core/service.c | 36 +++++++------------------ src/core/socket.c | 9 +++---- src/core/swap.c | 9 ++----- src/core/unit.c | 14 ---------- src/core/unit.h | 1 - src/shared/serialize.c | 60 ++++++++++++++++++++++++++++++++++++++++++ src/shared/serialize.h | 3 +++ 9 files changed, 87 insertions(+), 64 deletions(-) diff --git a/src/core/mount.c b/src/core/mount.c index 55e0c2ec886..6424c56ed32 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1405,9 +1405,7 @@ static int mount_serialize(Unit *u, FILE *f, FDSet *fds) { (void) serialize_item(f, "result", mount_result_to_string(m->result)); (void) serialize_item(f, "reload-result", mount_result_to_string(m->reload_result)); (void) serialize_item_format(f, "n-retry-umount", "%u", m->n_retry_umount); - - if (pidref_is_set(&m->control_pid)) - (void) serialize_item_format(f, "control-pid", PID_FMT, m->control_pid.pid); + (void) serialize_pidref(f, fds, "control-pid", &m->control_pid); if (m->control_command_id >= 0) (void) serialize_item(f, "control-command", mount_exec_command_to_string(m->control_command_id)); @@ -1461,9 +1459,7 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F } else if (streq(key, "control-pid")) { pidref_done(&m->control_pid); - r = pidref_set_pidstr(&m->control_pid, value); - if (r < 0) - log_debug_errno(r, "Failed to set control PID to '%s': %m", value); + (void) deserialize_pidref(fds, value, &m->control_pid); } else if (streq(key, "control-command")) { MountExecCommand id; diff --git a/src/core/scope.c b/src/core/scope.c index 69ac20e53c1..e4c27da91d2 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -546,7 +546,7 @@ static int scope_serialize(Unit *u, FILE *f, FDSet *fds) { (void) serialize_item(f, "controller", s->controller); SET_FOREACH(pid, u->pids) - serialize_item_format(f, "pids", PID_FMT, pid->pid); + serialize_pidref(f, fds, "pids", pid); return 0; } @@ -584,10 +584,13 @@ static int scope_deserialize_item(Unit *u, const char *key, const char *value, F return log_oom(); } else if (streq(key, "pids")) { + _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; - r = unit_watch_pid_str(u, value, /* exclusive= */ false); - if (r < 0) - log_unit_debug(u, "Failed to parse pids value, ignoring: %s", value); + if (deserialize_pidref(fds, value, &pidref) >= 0) { + r = unit_watch_pidref(u, &pidref, /* exclusive= */ false); + if (r < 0) + log_unit_debug(u, "Failed to watch PID, ignoring: %s", value); + } } else log_unit_debug(u, "Unknown serialization key: %s", key); diff --git a/src/core/service.c b/src/core/service.c index 8dc98813502..73a678b0cc1 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -213,19 +213,6 @@ static int service_set_main_pidref(Service *s, PidRef *pidref) { return 0; } -static int service_set_main_pid(Service *s, pid_t pid) { - _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; - int r; - - assert(s); - - r = pidref_set_pid(&pidref, pid); - if (r < 0) - return r; - - return service_set_main_pidref(s, &pidref); -} - void service_release_socket_fd(Service *s) { assert(s); @@ -2949,11 +2936,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { (void) serialize_item(f, "result", service_result_to_string(s->result)); (void) serialize_item(f, "reload-result", service_result_to_string(s->reload_result)); - if (pidref_is_set(&s->control_pid)) - (void) serialize_item_format(f, "control-pid", PID_FMT, s->control_pid.pid); - - if (s->main_pid_known && pidref_is_set(&s->main_pid)) - (void) serialize_item_format(f, "main-pid", PID_FMT, s->main_pid.pid); + (void) serialize_pidref(f, fds, "control-pid", &s->control_pid); + if (s->main_pid_known) + (void) serialize_pidref(f, fds, "main-pid", &s->main_pid); (void) serialize_bool(f, "main-pid-known", s->main_pid_known); (void) serialize_bool(f, "bus-name-good", s->bus_name_good); @@ -3188,16 +3173,15 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, } else if (streq(key, "control-pid")) { pidref_done(&s->control_pid); - r = pidref_set_pidstr(&s->control_pid, value); - if (r < 0) - log_unit_debug_errno(u, r, "Failed to initialize control PID '%s' from serialization, ignoring.", value); + + (void) deserialize_pidref(fds, value, &s->control_pid); + } else if (streq(key, "main-pid")) { - pid_t pid; + _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; + + if (deserialize_pidref(fds, value, &pidref) >= 0) + (void) service_set_main_pidref(s, &pidref); - if (parse_pid(value, &pid) < 0) - log_unit_debug(u, "Failed to parse main-pid value: %s", value); - else - (void) service_set_main_pid(s, pid); } else if (streq(key, "main-pid-known")) { int b; diff --git a/src/core/socket.c b/src/core/socket.c index e5b2e8ae762..1bbcadc3ba3 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -2557,9 +2557,7 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) { (void) serialize_item(f, "result", socket_result_to_string(s->result)); (void) serialize_item_format(f, "n-accepted", "%u", s->n_accepted); (void) serialize_item_format(f, "n-refused", "%u", s->n_refused); - - if (pidref_is_set(&s->control_pid)) - (void) serialize_item_format(f, "control-pid", PID_FMT, s->control_pid.pid); + (void) serialize_pidref(f, fds, "control-pid", &s->control_pid); if (s->control_command_id >= 0) (void) serialize_item(f, "control-command", socket_exec_command_to_string(s->control_command_id)); @@ -2641,9 +2639,8 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value, s->n_refused += k; } else if (streq(key, "control-pid")) { pidref_done(&s->control_pid); - r = pidref_set_pidstr(&s->control_pid, value); - if (r < 0) - log_debug_errno(r, "Failed to pin control PID '%s', ignoring: %m", value); + (void) deserialize_pidref(fds, value, &s->control_pid); + } else if (streq(key, "control-command")) { SocketExecCommand id; diff --git a/src/core/swap.c b/src/core/swap.c index 8a6a32543a9..008c5bbc247 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -962,9 +962,7 @@ static int swap_serialize(Unit *u, FILE *f, FDSet *fds) { (void) serialize_item(f, "state", swap_state_to_string(s->state)); (void) serialize_item(f, "result", swap_result_to_string(s->result)); - - if (pidref_is_set(&s->control_pid)) - (void) serialize_item_format(f, "control-pid", PID_FMT, s->control_pid.pid); + (void) serialize_pidref(f, fds, "control-pid", &s->control_pid); if (s->control_command_id >= 0) (void) serialize_item(f, "control-command", swap_exec_command_to_string(s->control_command_id)); @@ -974,7 +972,6 @@ static int swap_serialize(Unit *u, FILE *f, FDSet *fds) { static int swap_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { Swap *s = SWAP(u); - int r; assert(s); assert(fds); @@ -998,9 +995,7 @@ static int swap_deserialize_item(Unit *u, const char *key, const char *value, FD } else if (streq(key, "control-pid")) { pidref_done(&s->control_pid); - r = pidref_set_pidstr(&s->control_pid, value); - if (r < 0) - log_debug_errno(r, "Failed to pin control PID '%s', ignoring: %m", value); + (void) deserialize_pidref(fds, value, &s->control_pid); } else if (streq(key, "control-command")) { SwapExecCommand id; diff --git a/src/core/unit.c b/src/core/unit.c index ea49cfa504f..70a4f840366 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -2918,20 +2918,6 @@ int unit_watch_pid(Unit *u, pid_t pid, bool exclusive) { return unit_watch_pidref(u, &pidref, exclusive); } -int unit_watch_pid_str(Unit *u, const char *s, bool exclusive) { - _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; - int r; - - assert(u); - assert(s); - - r = pidref_set_pidstr(&pidref, s); - if (r < 0) - return r; - - return unit_watch_pidref(u, &pidref, exclusive); -} - void unit_unwatch_pidref(Unit *u, PidRef *pid) { assert(u); assert(pidref_is_set(pid)); diff --git a/src/core/unit.h b/src/core/unit.h index b39d868f869..a95aec345fb 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -921,7 +921,6 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su int unit_watch_pidref(Unit *u, PidRef *pid, bool exclusive); int unit_watch_pid(Unit *u, pid_t pid, bool exclusive); -int unit_watch_pid_str(Unit *u, const char *s, bool exclusive); void unit_unwatch_pidref(Unit *u, PidRef *pid); void unit_unwatch_pid(Unit *u, pid_t pid); void unit_unwatch_all_pids(Unit *u); diff --git a/src/shared/serialize.c b/src/shared/serialize.c index f9795efe367..2ffc524f15d 100644 --- a/src/shared/serialize.c +++ b/src/shared/serialize.c @@ -5,6 +5,7 @@ #include "alloc-util.h" #include "env-util.h" #include "escape.h" +#include "fd-util.h" #include "fileio.h" #include "memfd-util.h" #include "missing_mman.h" @@ -101,6 +102,7 @@ int serialize_fd(FILE *f, FDSet *fds, const char *key, int fd) { int copy; assert(f); + assert(fds); assert(key); if (fd < 0) @@ -149,6 +151,28 @@ int serialize_strv(FILE *f, const char *key, char **l) { return ret; } +int serialize_pidref(FILE *f, FDSet *fds, const char *key, PidRef *pidref) { + int copy; + + assert(f); + assert(fds); + + if (!pidref_is_set(pidref)) + return 0; + + /* If we have a pidfd we serialize the fd and encode the fd number prefixed by "@" in the + * serialization. Otherwise we serialize the numeric PID as it is. */ + + if (pidref->fd < 0) + return serialize_item_format(f, key, PID_FMT, pidref->pid); + + copy = fdset_put_dup(fds, pidref->fd); + if (copy < 0) + return log_error_errno(copy, "Failed to add file descriptor to serialization set: %m"); + + return serialize_item_format(f, key, "@%i", copy); +} + int deserialize_read_line(FILE *f, char **ret) { _cleanup_free_ char *line = NULL; int r; @@ -255,6 +279,42 @@ int deserialize_environment(const char *value, char ***list) { return 0; } +int deserialize_pidref(FDSet *fds, const char *value, PidRef *ret) { + const char *e; + int r; + + assert(value); + assert(ret); + + e = startswith(value, "@"); + if (e) { + _cleanup_close_ int our_fd = -EBADF; + int parsed_fd; + + parsed_fd = parse_fd(e); + if (parsed_fd < 0) + return log_debug_errno(parsed_fd, "Failed to parse file descriptor specification: %s", e); + + our_fd = fdset_remove(fds, parsed_fd); /* Take possession of the fd */ + if (our_fd < 0) + return log_debug_errno(our_fd, "Failed to acquire pidfd from serialization fds: %m"); + + r = pidref_set_pidfd_consume(ret, TAKE_FD(our_fd)); + } else { + pid_t pid; + + r = parse_pid(value, &pid); + if (r < 0) + return log_debug_errno(r, "Failed to parse PID: %s", value); + + r = pidref_set_pid(ret, pid); + } + if (r < 0) + return log_debug_errno(r, "Failed to initialize pidref: %m"); + + return 0; +} + int open_serialization_fd(const char *ident) { int fd; diff --git a/src/shared/serialize.h b/src/shared/serialize.h index fa1731acb57..9463d1127cf 100644 --- a/src/shared/serialize.h +++ b/src/shared/serialize.h @@ -5,6 +5,7 @@ #include "fdset.h" #include "macro.h" +#include "pidref.h" #include "string-util.h" #include "time-util.h" @@ -15,6 +16,7 @@ int serialize_fd(FILE *f, FDSet *fds, const char *key, int fd); int serialize_usec(FILE *f, const char *key, usec_t usec); int serialize_dual_timestamp(FILE *f, const char *key, const dual_timestamp *t); int serialize_strv(FILE *f, const char *key, char **l); +int serialize_pidref(FILE *f, FDSet *fds, const char *key, PidRef *pidref); static inline int serialize_bool(FILE *f, const char *key, bool b) { return serialize_item(f, key, yes_no(b)); @@ -29,5 +31,6 @@ int deserialize_usec(const char *value, usec_t *timestamp); int deserialize_dual_timestamp(const char *value, dual_timestamp *t); int deserialize_environment(const char *value, char ***environment); int deserialize_strv(char ***l, const char *value); +int deserialize_pidref(FDSet *fds, const char *value, PidRef *ret); int open_serialization_fd(const char *ident); -- 2.47.3