+11
-3
@@ -17,10 +17,11 @@ because upstream code was refactored since the fallback was removed.
|
|||||||
| `mount_option_supported()` | `fsopen()` (5.2) | **revert** of part of `c2198d0c3f`: return `-EAGAIN` ("don't know") when the new mount API is unavailable. | `src/basic/mountpoint-util.c` |
|
| `mount_option_supported()` | `fsopen()` (5.2) | **revert** of part of `c2198d0c3f`: return `-EAGAIN` ("don't know") when the new mount API is unavailable. | `src/basic/mountpoint-util.c` |
|
||||||
| `close_all_fds*()` (every fork/exec, `systemd-executor`) | `close_range()` (5.9) | **revert** of `c471cca093` and `d58c826c54`: fall back to iterating `/proc/self/fd` (or the frugal loop). | `src/basic/fd-util.c`, `src/basic/fd-util.h`, `src/test/test-fd-util.c` |
|
| `close_all_fds*()` (every fork/exec, `systemd-executor`) | `close_range()` (5.9) | **revert** of `c471cca093` and `d58c826c54`: fall back to iterating `/proc/self/fd` (or the frugal loop). | `src/basic/fd-util.c`, `src/basic/fd-util.h`, `src/test/test-fd-util.c` |
|
||||||
| `pidref_set_pid()` (every process PID1 tracks, `safe_fork()`, `posix_spawn_wrapper()`) | `pidfd_open()` (5.3) | **revert** (adjusted) of part of `6e14c46bac`: ENOSYS ⇒ PidRef without fd (plain PID). | `src/basic/pidref.c` |
|
| `pidref_set_pid()` (every process PID1 tracks, `safe_fork()`, `posix_spawn_wrapper()`) | `pidfd_open()` (5.3) | **revert** (adjusted) of part of `6e14c46bac`: ENOSYS ⇒ PidRef without fd (plain PID). | `src/basic/pidref.c` |
|
||||||
|
| `pidfd_open()` shim (all pidfd users), `pidfd_waitid()` | `waitid(P_PIDFD)` (5.4) | **new**: vendor kernels (Android 4.19) backport `pidfd_open()` but not `waitid(P_PIDFD)`, so every wait failed with EINVAL (PID1 froze after generators). The shim probes once on a pidfd of self that `pidfd_send_signal()` and `poll()` work (without pidfd poll support a live process reports readable); if not, `pidfd_open()` returns ENOSYS so the plain-PID fallbacks above apply. Waits go through `pidfd_waitid()`, which probes `waitid(P_PIDFD)` (ECHILD = supported, EINVAL = not) and otherwise uses `waitid(P_PID)` with the known PID (safe for children: the PID cannot be reused before reaping). Keeping pidfds is required by logind, which since v258 refuses sessions whose leader has no pidfd (`NoSessionPIDFD`). | `src/libc/pidfd.c`, `src/include/override/sys/pidfd.h`, `src/basic/pidref.c`, `src/libsystemd/sd-event/sd-event.c` |
|
||||||
| `pidref_wait_for_terminate_full()` with timeout | pidfd (5.3) | **new**: without pidfd poll `waitid(P_PID, …, WNOHANG)` every 10 ms instead of returning `-ENOMEDIUM`. | `src/basic/pidref.c` |
|
| `pidref_wait_for_terminate_full()` with timeout | pidfd (5.3) | **new**: without pidfd poll `waitid(P_PID, …, WNOHANG)` every 10 ms instead of returning `-ENOMEDIUM`. | `src/basic/pidref.c` |
|
||||||
| `pidfd_check_pidfs()`, `pidfd_info_mask_is_supported()`, `pidfd_get_inode_id_self_cached()` | pidfd (5.3) | **revert**/new: ENOSYS ⇒ "not supported" instead of hard error. | `src/basic/pidfd-util.c` |
|
| `pidfd_check_pidfs()`, `pidfd_info_mask_is_supported()`, `pidfd_get_inode_id_self_cached()` | pidfd (5.3) | **revert**/new: ENOSYS ⇒ "not supported" instead of hard error. | `src/basic/pidfd-util.c` |
|
||||||
| sd-event child sources (`sd_event_add_child()`, used by udevd, logind, …) | pidfd (5.3), `waitid(P_PIDFD)` (5.4) | **new** (upstream removed the non-pidfd path in `6e14c46bac` and later made the code pidfd-only): if `pidfd_open()` is unsupported the source works on the PID via `waitid(P_PID)` + SIGCHLD signalfd. SIGCHLD is blocked automatically in that case (upstream no longer requires callers to block it). `send_child_signal()` falls back to `kill()`/`rt_sigqueueinfo()`; `set_child_pidfd_own()` returns `-EOPNOTSUPP` without pidfd. | `src/libsystemd/sd-event/sd-event.c` |
|
| sd-event child sources (`sd_event_add_child()`, used by udevd, logind, …) | pidfd (5.3), `waitid(P_PIDFD)` (5.4) | **new** (upstream removed the non-pidfd path in `6e14c46bac` and later made the code pidfd-only): if `pidfd_open()` is unsupported the source works on the PID via `waitid(P_PID)` + SIGCHLD signalfd. SIGCHLD is blocked automatically in that case (upstream no longer requires callers to block it). `send_child_signal()` falls back to `kill()`/`rt_sigqueueinfo()`; `set_child_pidfd_own()` returns `-EOPNOTSUPP` without pidfd. | `src/libsystemd/sd-event/sd-event.c` |
|
||||||
| `pam_systemd` session creation | pidfd (5.3) | **revert** of part of `6e14c46bac`: fall back to `CreateSession` (PID based). | `src/login/pam_systemd.c` |
|
| `pam_systemd` session creation | pidfd (5.3) | **revert** of part of `6e14c46bac`: fall back to `CreateSession` (PID based). Ineffective on its own: logind (Varlink and D-Bus) rejects leaders without pidfd, so sessions need a kernel with `pidfd_open()` + pidfd poll. | `src/login/pam_systemd.c` |
|
||||||
| Unit cgroup-empty tracking (`unit_check_cgroup_events()`) | `frozen` key in `cgroup.events` (5.2) | **new**: if the key is missing, read only `populated`. Without this every cgroup event read failed and stopped units were never noticed as empty. | `src/core/cgroup.c` |
|
| Unit cgroup-empty tracking (`unit_check_cgroup_events()`) | `frozen` key in `cgroup.events` (5.2) | **new**: if the key is missing, read only `populated`. Without this every cgroup event read failed and stopped units were never noticed as empty. | `src/core/cgroup.c` |
|
||||||
| Freeze/thaw | cgroup v2 freezer (5.2) | **revert** of `3c86a935ad`: `cg_freezer_supported()` restored; freeze is `-EOPNOTSUPP` / no-op when `cgroup.freeze` is absent. | `src/basic/cgroup-util.[ch]`, `src/core/cgroup.c`, `src/core/unit.c` |
|
| Freeze/thaw | cgroup v2 freezer (5.2) | **revert** of `3c86a935ad`: `cg_freezer_supported()` restored; freeze is `-EOPNOTSUPP` / no-op when `cgroup.freeze` is absent. | `src/basic/cgroup-util.[ch]`, `src/core/cgroup.c`, `src/core/unit.c` |
|
||||||
| Credentials (`LoadCredential=`, `SetCredential=`, `ImportCredential=` — used by many stock units) | new mount API `fsopen`/`fsmount`/`move_mount` (5.2) | **new**: if the credentials fs cannot be created because the API is missing, use the existing "plain directory" fallback (previously only used on EPERM). | `src/core/exec-credential.c` |
|
| Credentials (`LoadCredential=`, `SetCredential=`, `ImportCredential=` — used by many stock units) | new mount API `fsopen`/`fsmount`/`move_mount` (5.2) | **new**: if the credentials fs cannot be created because the API is missing, use the existing "plain directory" fallback (previously only used on EPERM). | `src/core/exec-credential.c` |
|
||||||
@@ -64,7 +65,10 @@ because upstream code was refactored since the fallback was removed.
|
|||||||
EINVAL workaround (`00c4851af0`), expect warnings when used.
|
EINVAL workaround (`00c4851af0`), expect warnings when used.
|
||||||
- **udev net_id** for IP-over-InfiniBand (`dev_port`, 4.20): `d3d375a686` not reverted; multi-port
|
- **udev net_id** for IP-over-InfiniBand (`dev_port`, 4.20): `d3d375a686` not reverted; multi-port
|
||||||
IPoIB devices may get colliding names.
|
IPoIB devices may get colliding names.
|
||||||
- `test-event`'s `test_pidfd` inherently requires pidfds and fails without them.
|
- `test-event`'s `test_pidfd` inherently requires pidfds and fails without them; it and
|
||||||
|
`test_child_pidfd_wnowait` also call `waitid(P_PIDFD)` directly and fail without it.
|
||||||
|
- logind sessions require pidfds (see `pam_systemd` row); on kernels without `pidfd_open()` no
|
||||||
|
login session can be created.
|
||||||
- Anything else newer than 5.10 listed in `README` as "recommended baseline" is expected to fall
|
- Anything else newer than 5.10 listed in `README` as "recommended baseline" is expected to fall
|
||||||
back gracefully upstream, but that has not been verified on a real old kernel.
|
back gracefully upstream, but that has not been verified on a real old kernel.
|
||||||
|
|
||||||
@@ -77,4 +81,8 @@ because upstream code was refactored since the fallback was removed.
|
|||||||
(with the built generators) under an `LD_PRELOAD` shim that simulates an old kernel: strips
|
(with the built generators) under an `LD_PRELOAD` shim that simulates an old kernel: strips
|
||||||
`STATX_MNT_ID*`/`STATX_ATTR_MOUNT_ROOT` from `statx()` results and makes `pidfd_open`,
|
`STATX_MNT_ID*`/`STATX_ATTR_MOUNT_ROOT` from `statx()` results and makes `pidfd_open`,
|
||||||
`pidfd_send_signal`, `pidfd_spawn`, `close_range` and the new mount API return ENOSYS.
|
`pidfd_send_signal`, `pidfd_spawn`, `close_range` and the new mount API return ENOSYS.
|
||||||
- **Not** booted on a real 4.19 kernel yet.
|
- `test-pidref`, `test-process-util`, `test-event` (except `test_pidfd`, `test_child_pidfd_wnowait`)
|
||||||
|
under an `LD_PRELOAD` shim that only makes `waitid(P_PIDFD)` fail with EINVAL (Android 4.19
|
||||||
|
vendor kernel case: pidfds stay enabled, waits use the `P_PID` fallback).
|
||||||
|
- Booted on an Android 4.19 vendor kernel (Xiaomi vince): reaches `graphical.target`; login
|
||||||
|
sessions not verified yet.
|
||||||
|
|||||||
+1
-1
@@ -522,7 +522,7 @@ int pidref_wait_for_terminate_full(PidRef *pidref, usec_t timeout, siginfo_t *re
|
|||||||
siginfo_t si = {};
|
siginfo_t si = {};
|
||||||
|
|
||||||
if (pidref->fd >= 0)
|
if (pidref->fd >= 0)
|
||||||
r = RET_NERRNO(waitid(P_PIDFD, pidref->fd, &si, WEXITED));
|
r = RET_NERRNO(pidfd_waitid(pidref->fd, pidref->pid, &si, WEXITED));
|
||||||
else
|
else
|
||||||
r = RET_NERRNO(waitid(P_PID, pidref->pid, &si, WEXITED));
|
r = RET_NERRNO(waitid(P_PID, pidref->pid, &si, WEXITED));
|
||||||
if (r >= 0) {
|
if (r >= 0) {
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ int pidfd_open_shim(pid_t pid, unsigned flags);
|
|||||||
int pidfd_open_checked(pid_t pid, unsigned flags);
|
int pidfd_open_checked(pid_t pid, unsigned flags);
|
||||||
#define pidfd_open pidfd_open_checked
|
#define pidfd_open pidfd_open_checked
|
||||||
|
|
||||||
|
/* ANCIENT-MOD: waitid(P_PIDFD) (kernel v5.4) with waitid(P_PID) fallback. */
|
||||||
|
int pidfd_waitid(int fd, pid_t pid, siginfo_t *info, int options);
|
||||||
|
|
||||||
/* Defined since glibc-2.36.
|
/* Defined since glibc-2.36.
|
||||||
* Supported since kernel v5.1 (3eb39f47934f9d5a3027fe00d906a45fe3a15fad). */
|
* Supported since kernel v5.1 (3eb39f47934f9d5a3027fe00d906a45fe3a15fad). */
|
||||||
int pidfd_send_signal_shim(int fd, int sig, siginfo_t *info, unsigned flags);
|
int pidfd_send_signal_shim(int fd, int sig, siginfo_t *info, unsigned flags);
|
||||||
|
|||||||
+25
-3
@@ -1,5 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <poll.h>
|
||||||
#include <sys/pidfd.h>
|
#include <sys/pidfd.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
@@ -10,7 +11,8 @@ DEFINE_SYSCALL_SHIM(pidfd_open, int,
|
|||||||
unsigned, flags)
|
unsigned, flags)
|
||||||
|
|
||||||
/* ANCIENT-MOD: vendor kernels < 5.4 (e.g. Android 4.19) may backport pidfd_open() without
|
/* ANCIENT-MOD: vendor kernels < 5.4 (e.g. Android 4.19) may backport pidfd_open() without
|
||||||
* waitid(P_PIDFD); report pidfds as unsupported there so the plain-PID fallbacks are used. */
|
* waitid(P_PIDFD). Pidfds are reported usable only if they can be signalled and polled (both needed
|
||||||
|
* by logind and sd-event); waits go through pidfd_waitid(), which falls back to waitid(P_PID). */
|
||||||
int pidfd_open_checked(pid_t pid, unsigned flags) {
|
int pidfd_open_checked(pid_t pid, unsigned flags) {
|
||||||
static int usable = -1;
|
static int usable = -1;
|
||||||
|
|
||||||
@@ -22,8 +24,9 @@ int pidfd_open_checked(pid_t pid, unsigned flags) {
|
|||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
siginfo_t si = {};
|
/* Without pidfd poll support the default poll mask reports a live process as readable */
|
||||||
usable = waitid(P_PIDFD, fd, &si, WEXITED|WNOHANG) >= 0 || errno != EINVAL;
|
struct pollfd pfd = { .fd = fd, .events = POLLIN };
|
||||||
|
usable = pidfd_send_signal_shim(fd, 0, NULL, 0) >= 0 && poll(&pfd, 1, 0) == 0;
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,6 +38,25 @@ int pidfd_open_checked(pid_t pid, unsigned flags) {
|
|||||||
return pidfd_open_shim(pid, flags);
|
return pidfd_open_shim(pid, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int pidfd_waitid(int fd, pid_t pid, siginfo_t *info, int options) {
|
||||||
|
static int supported = -1;
|
||||||
|
|
||||||
|
if (supported < 0) {
|
||||||
|
int self = pidfd_open_shim(getpid(), 0);
|
||||||
|
if (self < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
siginfo_t si = {};
|
||||||
|
supported = waitid(P_PIDFD, self, &si, WEXITED|WNOHANG) >= 0 || errno != EINVAL;
|
||||||
|
close(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supported)
|
||||||
|
return waitid(P_PIDFD, fd, info, options);
|
||||||
|
|
||||||
|
return waitid(P_PID, pid, info, options);
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_SYSCALL_SHIM(pidfd_send_signal, int,
|
DEFINE_SYSCALL_SHIM(pidfd_send_signal, int,
|
||||||
int, fd,
|
int, fd,
|
||||||
int, sig,
|
int, sig,
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ static int child_waitid(sd_event_source *s, siginfo_t *si, int options) {
|
|||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
if (s->child.pidfd >= 0)
|
if (s->child.pidfd >= 0)
|
||||||
return waitid(P_PIDFD, s->child.pidfd, si, options);
|
return pidfd_waitid(s->child.pidfd, s->child.pid, si, options);
|
||||||
|
|
||||||
return waitid(P_PID, s->child.pid, si, options);
|
return waitid(P_PID, s->child.pid, si, options);
|
||||||
}
|
}
|
||||||
@@ -3867,7 +3867,7 @@ static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) {
|
|||||||
* be set to pending, and we would have returned early above. */
|
* be set to pending, and we would have returned early above. */
|
||||||
|
|
||||||
zero(s->child.siginfo);
|
zero(s->child.siginfo);
|
||||||
if (waitid(P_PIDFD, s->child.pidfd, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0)
|
if (pidfd_waitid(s->child.pidfd, s->child.pid, &s->child.siginfo, WNOHANG | WNOWAIT | s->child.options) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if (s->child.siginfo.si_pid == 0)
|
if (s->child.siginfo.si_pid == 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user