oomd drop-in: arm user@.service, not user.slice
oomd kills a descendant of what it monitors, choosing among that cgroup's children. Armed on user.slice the only candidate is user-$UID.slice -- the entire login session, compositor included -- so the backstop's kill action was "log the user out" rather than "kill the hog". Move it to user@.service, where the candidates are app.slice, session.slice and background.slice. This is the same trap as the session-3.scope victim that eligible_cgroup() exists to block; it just arrived via a different mechanism. Applied and verified: oomctl shows user@1000.service monitored at 60% over oomd's 20s window, with app.slice and descendants as candidates. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
df1c928 parent: 937fc8b modified
optional/10-user-pressure.conf +10 -3 | @@ -1,12 +1,19 @@ | ||
| 1 | -# Drop-in for user.slice: /etc/systemd/system/user.slice.d/10-user-pressure.conf | |
| 1 | +# Drop-in for user@.service: /etc/systemd/system/user@.service.d/10-user-pressure.conf | |
| 2 | 2 | # |
| 3 | 3 | # Out of the box user.slice has ManagedOOMMemoryPressure=auto, which inherits |
| 4 | 4 | # from the root slice, which is off. The result is that systemd-oomd watches |
| 5 | 5 | # system.slice and completely ignores every application you actually run. |
| 6 | 6 | # |
| 7 | -# This arms it at 60% pressure sustained over oomd's default 30s window. It is | |
| 7 | +# This arms it at 60% pressure sustained over oomd's default 20s window. It is | |
| 8 | 8 | # deliberately slower and dumber than memwatchd -- it is the backstop for the |
| 9 | 9 | # case where memwatchd is dead, wedged, or wrong. It kills without asking. |
| 10 | -[Slice] | |
| 10 | +# | |
| 11 | +# Note the placement. oomd kills a *descendant* of what it monitors, picking | |
| 12 | +# among that cgroup's children. Armed on user.slice, the only candidate is | |
| 13 | +# user-$UID.slice -- the whole login session, compositor included, so firing | |
| 14 | +# means a logout. Armed here on user@.service the candidates are app.slice, | |
| 15 | +# session.slice and background.slice, so it takes out applications and leaves | |
| 16 | +# the session standing. Same reasoning as eligible_cgroup() in memwatchd. | |
| 17 | +[Service] | |
| 11 | 18 | ManagedOOMMemoryPressure=kill |
| 12 | 19 | ManagedOOMMemoryPressureLimit=60% |
| @@ -1,12 +1,19 @@ | |||
| 1 | -# Drop-in for user.slice: /etc/systemd/system/user.slice.d/10-user-pressure.conf | 1 | +# Drop-in for user@.service: /etc/systemd/system/user@.service.d/10-user-pressure.conf |
| 2 | # | 2 | # |
| 3 | # Out of the box user.slice has ManagedOOMMemoryPressure=auto, which inherits | 3 | # Out of the box user.slice has ManagedOOMMemoryPressure=auto, which inherits |
| 4 | # from the root slice, which is off. The result is that systemd-oomd watches | 4 | # from the root slice, which is off. The result is that systemd-oomd watches |
| 5 | # system.slice and completely ignores every application you actually run. | 5 | # system.slice and completely ignores every application you actually run. |
| 6 | # | 6 | # |
| 7 | -# This arms it at 60% pressure sustained over oomd's default 30s window. It is | 7 | +# This arms it at 60% pressure sustained over oomd's default 20s window. It is |
| 8 | # deliberately slower and dumber than memwatchd -- it is the backstop for the | 8 | # deliberately slower and dumber than memwatchd -- it is the backstop for the |
| 9 | # case where memwatchd is dead, wedged, or wrong. It kills without asking. | 9 | # case where memwatchd is dead, wedged, or wrong. It kills without asking. |
| 10 | -[Slice] | 10 | +# |
| 11 | +# Note the placement. oomd kills a *descendant* of what it monitors, picking | ||
| 12 | +# among that cgroup's children. Armed on user.slice, the only candidate is | ||
| 13 | +# user-$UID.slice -- the whole login session, compositor included, so firing | ||
| 14 | +# means a logout. Armed here on user@.service the candidates are app.slice, | ||
| 15 | +# session.slice and background.slice, so it takes out applications and leaves | ||
| 16 | +# the session standing. Same reasoning as eligible_cgroup() in memwatchd. | ||
| 17 | +[Service] | ||
| 11 | ManagedOOMMemoryPressure=kill | 18 | ManagedOOMMemoryPressure=kill |
| 12 | ManagedOOMMemoryPressureLimit=60% | 19 | ManagedOOMMemoryPressureLimit=60% |