Skip to content

Commit aaa872a

Browse files
DaanDeMeyeryuwata
authored andcommitted
core: Serialize both pid and pidfd to keep downgrades working
Currently, when downgrading from a version with pidfd support to a version without pidfd support, all information about running processes is lost as the newer systemd will serialized pidfds which are not recognized by the older systemd when deserializing. To improve the situation, let's serialize both the pid and the pidfd. This is safe because existing versions will either replace the first deserialized pidref with the second one or discard the second one in favor of the first one depending on the unit and field. Older versions that don't support pidfd's will silently discard any fields that contain a pidfd as those will try to parse the field as a pid and since a pidfd field will start with '@', those versions will debug error log and ignore the value. To make sure we reuse the existing pidfd as much as possible, the pidfd is serialized first. Both for scopes and service main pids, if the same pid is seen multiple times, the first pidref is kept. So by serializing the pidfd first we make sure the original pidfd is used instead of the new one which is opened when deserializing the first pid field. For other control units, older versions with pidfd support will discard the first pidfd and replace it with a new pidfd from the second pid field. This is a slight regression on downgrades, but we make sure it doesn't happen for future versions (and older versions when this commit is backported) by modifying the logic to only use the first successfully deserialized pidref so that the raw pid without pidfd is discarded instead of it replacing the existing pidfd.
1 parent 1ce28e5 commit aaa872a

File tree

5 files changed

+22
-17
lines changed

5 files changed

+22
-17
lines changed

src/core/mount.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -1438,8 +1438,8 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F
14381438

14391439
} else if (streq(key, "control-pid")) {
14401440

1441-
pidref_done(&m->control_pid);
1442-
(void) deserialize_pidref(fds, value, &m->control_pid);
1441+
if (!pidref_is_set(&m->control_pid))
1442+
(void) deserialize_pidref(fds, value, &m->control_pid);
14431443

14441444
} else if (streq(key, "control-command")) {
14451445
MountExecCommand id;

src/core/service.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -3188,9 +3188,9 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
31883188
s->reload_result = f;
31893189

31903190
} else if (streq(key, "control-pid")) {
3191-
pidref_done(&s->control_pid);
31923191

3193-
(void) deserialize_pidref(fds, value, &s->control_pid);
3192+
if (!pidref_is_set(&s->control_pid))
3193+
(void) deserialize_pidref(fds, value, &s->control_pid);
31943194

31953195
} else if (streq(key, "main-pid")) {
31963196
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;

src/core/socket.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -2631,8 +2631,9 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
26312631
else
26322632
s->n_refused += k;
26332633
} else if (streq(key, "control-pid")) {
2634-
pidref_done(&s->control_pid);
2635-
(void) deserialize_pidref(fds, value, &s->control_pid);
2634+
2635+
if (!pidref_is_set(&s->control_pid))
2636+
(void) deserialize_pidref(fds, value, &s->control_pid);
26362637

26372638
} else if (streq(key, "control-command")) {
26382639
SocketExecCommand id;

src/core/swap.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -955,8 +955,8 @@ static int swap_deserialize_item(Unit *u, const char *key, const char *value, FD
955955
s->result = f;
956956
} else if (streq(key, "control-pid")) {
957957

958-
pidref_done(&s->control_pid);
959-
(void) deserialize_pidref(fds, value, &s->control_pid);
958+
if (!pidref_is_set(&s->control_pid))
959+
(void) deserialize_pidref(fds, value, &s->control_pid);
960960

961961
} else if (streq(key, "control-command")) {
962962
SwapExecCommand id;

src/shared/serialize.c

+13-9
Original file line numberDiff line numberDiff line change
@@ -180,25 +180,29 @@ int serialize_strv(FILE *f, const char *key, char **l) {
180180
}
181181

182182
int serialize_pidref(FILE *f, FDSet *fds, const char *key, PidRef *pidref) {
183-
int copy;
183+
int r;
184184

185185
assert(f);
186186
assert(fds);
187187

188188
if (!pidref_is_set(pidref))
189189
return 0;
190190

191-
/* If we have a pidfd we serialize the fd and encode the fd number prefixed by "@" in the
192-
* serialization. Otherwise we serialize the numeric PID as it is. */
191+
/* We always serialize the pid, to keep downgrades mostly working (older versions will deserialize
192+
* the pid and silently fail to deserialize the pidfd). If we also have a pidfd, we serialize it
193+
* first and encode the fd number prefixed by "@" in the serialization. */
193194

194-
if (pidref->fd < 0)
195-
return serialize_item_format(f, key, PID_FMT, pidref->pid);
195+
if (pidref->fd >= 0) {
196+
int copy = fdset_put_dup(fds, pidref->fd);
197+
if (copy < 0)
198+
return log_error_errno(copy, "Failed to add file descriptor to serialization set: %m");
196199

197-
copy = fdset_put_dup(fds, pidref->fd);
198-
if (copy < 0)
199-
return log_error_errno(copy, "Failed to add file descriptor to serialization set: %m");
200+
r = serialize_item_format(f, key, "@%i", copy);
201+
if (r < 0)
202+
return log_error_errno(r, "Failed to serialize PID file descriptor: %m");
203+
}
200204

201-
return serialize_item_format(f, key, "@%i", copy);
205+
return serialize_item_format(f, key, PID_FMT, pidref->pid);
202206
}
203207

204208
int serialize_ratelimit(FILE *f, const char *key, const RateLimit *rl) {

0 commit comments

Comments
 (0)