From f4321154ebdd2235e704f5e5866e8647fa81c9f4 Mon Sep 17 00:00:00 2001 From: basebuilder_pel7x64builder0 Date: Tue, 18 Aug 2020 01:48:21 +0200 Subject: [PATCH] systemd add another set of missing patches Signed-off-by: basebuilder_pel7x64builder0 --- ...ng-path-specs-once-we-triggered-the-.patch | 35 ++ ...al-use-of-cgroup_path-after-free-whe.patch | 39 ++ ...-restarting-services-don-t-close-fds.patch | 112 ++++++ ...t-how-we-keep-the-service-fdstore-fr.patch | 170 +++++++++ .../0804-tests-add-basic-journal-test.patch | 145 ++++++++ ...sion-test-for-systemctl-restart-syst.patch | 54 +++ ...hat-journald-keeps-fds-over-terminat.patch | 33 ++ ...rigger-assertion-when-journal_file_c.patch | 50 +++ ...agate-errors-from-mount_setup_unit-f.patch | 53 +++ ...ating-a-Mount-object-based-on-proc-s.patch | 35 ++ ...atelimiter-when-stopping-units-due-t.patch | 60 +++ ...1-core-rework-StopWhenUnneeded-logic.patch | 343 ++++++++++++++++++ SOURCES/0812-fix-the-fix-for-1691511.patch | 53 +++ ...ched-to-an-sd-event-loop-disconnect-.patch | 106 ++++++ ...-journal-files-that-were-deleted-by-.patch | 75 ++++ ...e-the-dead-code-and-actually-fix-146.patch | 42 +++ ....c-in-a-similar-way-to-what-we-just-.patch | 260 +++++++++++++ ...secondary-swap-units-jobs-if-deactiv.patch | 80 ++++ ...tape-changers-also-apprear-in-dev-ta.patch | 57 +++ ...o-restore-the-control-command-id-too.patch | 30 ++ 20 files changed, 1832 insertions(+) create mode 100644 SOURCES/0800-path-stop-watching-path-specs-once-we-triggered-the-.patch create mode 100644 SOURCES/0801-unit-fix-potential-use-of-cgroup_path-after-free-whe.patch create mode 100644 SOURCES/0802-core-when-restarting-services-don-t-close-fds.patch create mode 100644 SOURCES/0803-unit-rework-a-bit-how-we-keep-the-service-fdstore-fr.patch create mode 100644 SOURCES/0804-tests-add-basic-journal-test.patch create mode 100644 SOURCES/0805-tests-add-regression-test-for-systemctl-restart-syst.patch create mode 100644 SOURCES/0806-tests-add-test-that-journald-keeps-fds-over-terminat.patch create mode 100644 SOURCES/0807-journal-do-not-trigger-assertion-when-journal_file_c.patch create mode 100644 SOURCES/0808-mount-don-t-propagate-errors-from-mount_setup_unit-f.patch create mode 100644 SOURCES/0809-mount-when-allocating-a-Mount-object-based-on-proc-s.patch create mode 100644 SOURCES/0810-core-enforce-a-ratelimiter-when-stopping-units-due-t.patch create mode 100644 SOURCES/0811-core-rework-StopWhenUnneeded-logic.patch create mode 100644 SOURCES/0812-fix-the-fix-for-1691511.patch create mode 100644 SOURCES/0813-sd-bus-when-attached-to-an-sd-event-loop-disconnect-.patch create mode 100644 SOURCES/0814-sd-journal-close-journal-files-that-were-deleted-by-.patch create mode 100644 SOURCES/0815-sd-journal-remove-the-dead-code-and-actually-fix-146.patch create mode 100644 SOURCES/0816-swap-adjust-swap.c-in-a-similar-way-to-what-we-just-.patch create mode 100644 SOURCES/0817-swap-finish-the-secondary-swap-units-jobs-if-deactiv.patch create mode 100644 SOURCES/0818-udev-rules-make-tape-changers-also-apprear-in-dev-ta.patch create mode 100644 SOURCES/0819-core-make-sure-to-restore-the-control-command-id-too.patch diff --git a/SOURCES/0800-path-stop-watching-path-specs-once-we-triggered-the-.patch b/SOURCES/0800-path-stop-watching-path-specs-once-we-triggered-the-.patch new file mode 100644 index 00000000..8a4c8079 --- /dev/null +++ b/SOURCES/0800-path-stop-watching-path-specs-once-we-triggered-the-.patch @@ -0,0 +1,35 @@ +From 6a0d21a508e43ca7a89b700e98fd86a08eff4fee Mon Sep 17 00:00:00 2001 +From: Michal Sekletar +Date: Mon, 9 Sep 2019 14:38:35 +0200 +Subject: [PATCH] path: stop watching path specs once we triggered the target + unit + +We start watching them again once we get a notification that triggered +unit entered inactive or failed state. + +Fixes: #10503 +(cherry picked from commit 8fca6944c2ee20c63d62154c8badddc77170b176) + +Resolves: #1641777 +--- + src/core/path.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/src/core/path.c b/src/core/path.c +index 0533bb4e21..a74cbf2372 100644 +--- a/src/core/path.c ++++ b/src/core/path.c +@@ -497,11 +497,9 @@ static void path_enter_running(Path *p) { + + p->inotify_triggered = false; + +- r = path_watch(p); +- if (r < 0) +- goto fail; +- + path_set_state(p, PATH_RUNNING); ++ path_unwatch(p); ++ + return; + + fail: diff --git a/SOURCES/0801-unit-fix-potential-use-of-cgroup_path-after-free-whe.patch b/SOURCES/0801-unit-fix-potential-use-of-cgroup_path-after-free-whe.patch new file mode 100644 index 00000000..f41540ae --- /dev/null +++ b/SOURCES/0801-unit-fix-potential-use-of-cgroup_path-after-free-whe.patch @@ -0,0 +1,39 @@ +From 98234ad6e16e868bd1fa3e4622c43a182fdee75c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Renaud=20M=C3=A9trich?= +Date: Sat, 23 Nov 2019 13:37:02 +0100 +Subject: [PATCH] unit: fix potential use of cgroup_path after free() when + freeing unit + +Resolves: #1760149 +--- + src/core/cgroup.c | 3 +-- + src/core/unit.c | 2 +- + 2 files changed, 2 insertions(+), 3 deletions(-) + +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index 0ce265dbf4..9af8126957 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -874,8 +874,7 @@ void unit_destroy_cgroup_if_empty(Unit *u) { + + hashmap_remove(u->manager->cgroup_unit, u->cgroup_path); + +- free(u->cgroup_path); +- u->cgroup_path = NULL; ++ u->cgroup_path = mfree(u->cgroup_path); + u->cgroup_realized = false; + u->cgroup_realized_mask = 0; + } +diff --git a/src/core/unit.c b/src/core/unit.c +index 294c9eb70f..0dc66203a4 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -515,7 +515,7 @@ void unit_free(Unit *u) { + + if (u->cgroup_path) { + hashmap_remove(u->manager->cgroup_unit, u->cgroup_path); +- free(u->cgroup_path); ++ u->cgroup_path = mfree(u->cgroup_path); + } + + set_remove(u->manager->failed_units, u); diff --git a/SOURCES/0802-core-when-restarting-services-don-t-close-fds.patch b/SOURCES/0802-core-when-restarting-services-don-t-close-fds.patch new file mode 100644 index 00000000..91ef3149 --- /dev/null +++ b/SOURCES/0802-core-when-restarting-services-don-t-close-fds.patch @@ -0,0 +1,112 @@ +From 017d1bc2a34946336dbafcc1c9c390ea45a2a3bd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Sat, 22 Oct 2016 22:16:02 -0400 +Subject: [PATCH] core: when restarting services, don't close fds + +We would close all the stored fds in service_release_resources(), which of +course broke the whole concept of storing fds over service restart. + +Fixes #4408. + +(cherry picked from commit f0bfbfac43b7faa68ef1bb2ad659c191b9ec85d2) +(cherry picked from commit 4c271437cd695c31e76adb191013009689a7797c) +Resolves: #1803802 +--- + src/core/service.c | 22 +++++++++++++++------- + src/core/unit.c | 6 ++++-- + src/core/unit.h | 2 +- + 3 files changed, 20 insertions(+), 10 deletions(-) + +diff --git a/src/core/service.c b/src/core/service.c +index e538280bad..3c2f69a003 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -258,7 +258,17 @@ static void service_fd_store_unlink(ServiceFDStore *fs) { + free(fs); + } + +-static void service_release_resources(Unit *u) { ++static void service_release_fd_store(Service *s) { ++ assert(s); ++ ++ log_unit_debug(UNIT(s)->id, "Releasing all stored fds"); ++ while (s->fd_store) ++ service_fd_store_unlink(s->fd_store); ++ ++ assert(s->n_fd_store == 0); ++} ++ ++static void service_release_resources(Unit *u, bool inactive) { + Service *s = SERVICE(u); + + assert(s); +@@ -266,12 +276,10 @@ static void service_release_resources(Unit *u) { + if (!s->fd_store) + return; + +- log_debug("Releasing all resources for %s", u->id); +- +- while (s->fd_store) +- service_fd_store_unlink(s->fd_store); ++ log_unit_debug(u->id, "Releasing resources."); + +- assert(s->n_fd_store == 0); ++ if (inactive) ++ service_release_fd_store(s); + } + + static void service_done(Unit *u) { +@@ -319,7 +327,7 @@ static void service_done(Unit *u) { + + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + +- service_release_resources(u); ++ service_release_resources(u, true); + } + + static int on_fd_store_io(sd_event_source *e, int fd, uint32_t revents, void *userdata) { +diff --git a/src/core/unit.c b/src/core/unit.c +index 0dc66203a4..22e31a76b3 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -285,6 +285,7 @@ int unit_set_description(Unit *u, const char *description) { + + bool unit_may_gc(Unit *u) { + UnitActiveState state; ++ bool inactive; + assert(u); + + /* Checks whether the unit is ready to be unloaded for garbage collection. +@@ -302,16 +303,17 @@ bool unit_may_gc(Unit *u) { + return false; + + state = unit_active_state(u); ++ inactive = state == UNIT_INACTIVE; + + /* If the unit is inactive and failed and no job is queued for + * it, then release its runtime resources */ + if (UNIT_IS_INACTIVE_OR_FAILED(state) && + UNIT_VTABLE(u)->release_resources) +- UNIT_VTABLE(u)->release_resources(u); ++ UNIT_VTABLE(u)->release_resources(u, inactive); + + /* But we keep the unit object around for longer when it is + * referenced or configured to not be gc'ed */ +- if (state != UNIT_INACTIVE) ++ if (!inactive) + return false; + + if (UNIT_VTABLE(u)->no_gc) +diff --git a/src/core/unit.h b/src/core/unit.h +index 719fc95260..232be8164f 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -360,7 +360,7 @@ struct UnitVTable { + + /* When the unit is not running and no job for it queued we + * shall release its runtime resources */ +- void (*release_resources)(Unit *u); ++ void (*release_resources)(Unit *u, bool inactive); + + /* Return true when this unit is suitable for snapshotting */ + bool (*check_snapshot)(Unit *u); diff --git a/SOURCES/0803-unit-rework-a-bit-how-we-keep-the-service-fdstore-fr.patch b/SOURCES/0803-unit-rework-a-bit-how-we-keep-the-service-fdstore-fr.patch new file mode 100644 index 00000000..3dc70e2c --- /dev/null +++ b/SOURCES/0803-unit-rework-a-bit-how-we-keep-the-service-fdstore-fr.patch @@ -0,0 +1,170 @@ +From 9684908410868cb590ad74f4747bdbf9b5790abb Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 13 Nov 2017 15:08:49 +0100 +Subject: [PATCH] unit: rework a bit how we keep the service fdstore from being + destroyed during service restart + +When preparing for a restart we quickly go through the DEAD/INACTIVE +service state before entering AUTO_RESTART. When doing this, we need to +make sure we don't destroy the FD store. Previously this was done by +checking the failure state of the unit, and keeping the FD store around +when the unit failed, under the assumption that the restart logic will +then get into action. + +This is not entirely correct howver, as there might be failure states +that will no result in restarts. + +With this commit we slightly alter the logic: a ref counter for the fd +store is added, that is increased right before we handle the restart +logic, and decreased again right-after. + +This should ensure that the fdstore lives exactly as long as it needs. + +Follow-up for f0bfbfac43b7faa68ef1bb2ad659c191b9ec85d2. + +(cherry picked from commit 7eb2a8a1259043e107ebec94e30ed160a93f40a7) +(cherry picked from commit e2636bde0f07319d0d35262dac6ff2638ba4e598) +Resolves: #1803802 +--- + src/core/service.c | 23 ++++++++++++++++++----- + src/core/service.h | 1 + + src/core/unit.c | 12 ++++-------- + src/core/unit.h | 5 ++--- + 4 files changed, 25 insertions(+), 16 deletions(-) + +diff --git a/src/core/service.c b/src/core/service.c +index 3c2f69a003..e32cdf4594 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -261,6 +261,9 @@ static void service_fd_store_unlink(ServiceFDStore *fs) { + static void service_release_fd_store(Service *s) { + assert(s); + ++ if (s->n_keep_fd_store > 0) ++ return; ++ + log_unit_debug(UNIT(s)->id, "Releasing all stored fds"); + while (s->fd_store) + service_fd_store_unlink(s->fd_store); +@@ -268,7 +271,7 @@ static void service_release_fd_store(Service *s) { + assert(s->n_fd_store == 0); + } + +-static void service_release_resources(Unit *u, bool inactive) { ++static void service_release_resources(Unit *u) { + Service *s = SERVICE(u); + + assert(s); +@@ -278,8 +281,7 @@ static void service_release_resources(Unit *u, bool inactive) { + + log_unit_debug(u->id, "Releasing resources."); + +- if (inactive) +- service_release_fd_store(s); ++ service_release_fd_store(s); + } + + static void service_done(Unit *u) { +@@ -327,7 +329,7 @@ static void service_done(Unit *u) { + + s->timer_event_source = sd_event_source_unref(s->timer_event_source); + +- service_release_resources(u, true); ++ service_release_resources(u); + } + + static int on_fd_store_io(sd_event_source *e, int fd, uint32_t revents, void *userdata) { +@@ -1330,6 +1332,10 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) + if (f != SERVICE_SUCCESS) + s->result = f; + ++ /* Make sure service_release_resources() doesn't destroy our FD store, while we are changing through ++ * SERVICE_FAILED/SERVICE_DEAD before entering into SERVICE_AUTO_RESTART. */ ++ s->n_keep_fd_store++; ++ + service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD); + + if (s->result != SERVICE_SUCCESS) { +@@ -1351,12 +1357,19 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) + (!IN_SET(s->main_exec_status.code, CLD_KILLED, CLD_DUMPED) || !set_contains(s->restart_prevent_status.signal, INT_TO_PTR(s->main_exec_status.status)))) { + + r = service_arm_timer(s, s->restart_usec); +- if (r < 0) ++ if (r < 0) { ++ s->n_keep_fd_store--; + goto fail; ++ } + + service_set_state(s, SERVICE_AUTO_RESTART); + } + ++ /* The new state is in effect, let's decrease the fd store ref counter again. Let's also readd us to the GC ++ * queue, so that the fd store is possibly gc'ed again */ ++ s->n_keep_fd_store--; ++ unit_add_to_gc_queue(UNIT(s)); ++ + s->forbid_restart = false; + + /* We want fresh tmpdirs in case service is started again immediately */ +diff --git a/src/core/service.h b/src/core/service.h +index 82938a1fc4..e5753f1f4c 100644 +--- a/src/core/service.h ++++ b/src/core/service.h +@@ -215,6 +215,7 @@ struct Service { + ServiceFDStore *fd_store; + unsigned n_fd_store; + unsigned n_fd_store_max; ++ unsigned n_keep_fd_store; + }; + + extern const UnitVTable service_vtable; +diff --git a/src/core/unit.c b/src/core/unit.c +index 22e31a76b3..eff9fdbe70 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -285,7 +285,6 @@ int unit_set_description(Unit *u, const char *description) { + + bool unit_may_gc(Unit *u) { + UnitActiveState state; +- bool inactive; + assert(u); + + /* Checks whether the unit is ready to be unloaded for garbage collection. +@@ -303,17 +302,14 @@ bool unit_may_gc(Unit *u) { + return false; + + state = unit_active_state(u); +- inactive = state == UNIT_INACTIVE; + +- /* If the unit is inactive and failed and no job is queued for +- * it, then release its runtime resources */ ++ /* If the unit is inactive and failed and no job is queued for it, then release its runtime resources */ + if (UNIT_IS_INACTIVE_OR_FAILED(state) && + UNIT_VTABLE(u)->release_resources) +- UNIT_VTABLE(u)->release_resources(u, inactive); ++ UNIT_VTABLE(u)->release_resources(u); + +- /* But we keep the unit object around for longer when it is +- * referenced or configured to not be gc'ed */ +- if (!inactive) ++ /* But we keep the unit object around for longer when it is referenced or configured to not be gc'ed */ ++ if (state != UNIT_INACTIVE) + return false; + + if (UNIT_VTABLE(u)->no_gc) +diff --git a/src/core/unit.h b/src/core/unit.h +index 232be8164f..3b0fd8d9df 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -358,9 +358,8 @@ struct UnitVTable { + * even though nothing references it and it isn't active in any way. */ + bool (*may_gc)(Unit *u); + +- /* When the unit is not running and no job for it queued we +- * shall release its runtime resources */ +- void (*release_resources)(Unit *u, bool inactive); ++ /* When the unit is not running and no job for it queued we shall release its runtime resources */ ++ void (*release_resources)(Unit *u); + + /* Return true when this unit is suitable for snapshotting */ + bool (*check_snapshot)(Unit *u); diff --git a/SOURCES/0804-tests-add-basic-journal-test.patch b/SOURCES/0804-tests-add-basic-journal-test.patch new file mode 100644 index 00000000..1455a616 --- /dev/null +++ b/SOURCES/0804-tests-add-basic-journal-test.patch @@ -0,0 +1,145 @@ +From c53791854050661d34417f12755837abd74d213a Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Tue, 17 Nov 2015 11:21:23 +0000 +Subject: [PATCH] tests: add basic journal test + +(cherry picked from commit 1c36b4a73b876258fbe01fbe9bc9b750b7dcc9ce) +(cherry picked from commit e974b9915ccc7bf56d23fd6fc67631990d893c89) +Resolves: #1803802 +--- + test/TEST-04-JOURNAL/Makefile | 1 + + test/TEST-04-JOURNAL/test-journal.sh | 18 +++++++ + test/TEST-04-JOURNAL/test.sh | 76 ++++++++++++++++++++++++++++ + test/test-functions | 2 +- + 4 files changed, 96 insertions(+), 1 deletion(-) + create mode 120000 test/TEST-04-JOURNAL/Makefile + create mode 100755 test/TEST-04-JOURNAL/test-journal.sh + create mode 100755 test/TEST-04-JOURNAL/test.sh + +diff --git a/test/TEST-04-JOURNAL/Makefile b/test/TEST-04-JOURNAL/Makefile +new file mode 120000 +index 0000000000..e9f93b1104 +--- /dev/null ++++ b/test/TEST-04-JOURNAL/Makefile +@@ -0,0 +1 @@ ++../TEST-01-BASIC/Makefile +\ No newline at end of file +diff --git a/test/TEST-04-JOURNAL/test-journal.sh b/test/TEST-04-JOURNAL/test-journal.sh +new file mode 100755 +index 0000000000..c75f396ceb +--- /dev/null ++++ b/test/TEST-04-JOURNAL/test-journal.sh +@@ -0,0 +1,18 @@ ++#!/bin/bash ++ ++set -x ++set -e ++set -o pipefail ++ ++# Test stdout stream ++ ++# Skip empty lines ++ID=$(journalctl --new-id128 | sed -n 2p) ++>/expected ++printf $'\n\n\n' | systemd-cat -t "$ID" --level-prefix false ++journalctl --flush ++journalctl -b -o cat -t "$ID" >/output ++cmp /expected /output ++ ++touch /testok ++exit 0 +diff --git a/test/TEST-04-JOURNAL/test.sh b/test/TEST-04-JOURNAL/test.sh +new file mode 100755 +index 0000000000..e37cb7d412 +--- /dev/null ++++ b/test/TEST-04-JOURNAL/test.sh +@@ -0,0 +1,76 @@ ++#!/bin/bash ++# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- ++# ex: ts=8 sw=4 sts=4 et filetype=sh ++TEST_DESCRIPTION="Journal-related tests" ++ ++. $TEST_BASE_DIR/test-functions ++ ++check_result_qemu() { ++ ret=1 ++ mkdir -p $TESTDIR/root ++ mount ${LOOPDEV}p1 $TESTDIR/root ++ [[ -e $TESTDIR/root/testok ]] && ret=0 ++ [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR ++ cp -a $TESTDIR/root/var/log/journal $TESTDIR ++ umount $TESTDIR/root ++ [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed ++ ls -l $TESTDIR/journal/*/*.journal ++ test -s $TESTDIR/failed && ret=$(($ret+1)) ++ return $ret ++} ++ ++test_run() { ++ if run_qemu; then ++ check_result_qemu || return 1 ++ else ++ dwarn "can't run QEMU, skipping" ++ fi ++ if check_nspawn; then ++ run_nspawn ++ check_result_nspawn || return 1 ++ else ++ dwarn "can't run systemd-nspawn, skipping" ++ fi ++ return 0 ++} ++ ++test_setup() { ++ create_empty_image ++ mkdir -p $TESTDIR/root ++ mount ${LOOPDEV}p1 $TESTDIR/root ++ ++ # Create what will eventually be our root filesystem onto an overlay ++ ( ++ LOG_LEVEL=5 ++ eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) ++ ++ setup_basic_environment ++ ++ # setup the testsuite service ++ cat >$initdir/etc/systemd/system/testsuite.service </dev/null ++ [[ $LOOPDEV ]] && losetup -d $LOOPDEV ++ return 0 ++} ++ ++do_test "$@" +diff --git a/test/test-functions b/test/test-functions +index e50ce556fd..d5e9650903 100644 +--- a/test/test-functions ++++ b/test/test-functions +@@ -12,7 +12,7 @@ if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then + ROOTLIBDIR=/usr/lib/systemd + fi + +-BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe chmod chown ln" ++BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe chmod chown ln sed cmp tee" + DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname" + + function find_qemu_bin() { diff --git a/SOURCES/0805-tests-add-regression-test-for-systemctl-restart-syst.patch b/SOURCES/0805-tests-add-regression-test-for-systemctl-restart-syst.patch new file mode 100644 index 00000000..725665c0 --- /dev/null +++ b/SOURCES/0805-tests-add-regression-test-for-systemctl-restart-syst.patch @@ -0,0 +1,54 @@ +From e3468af46bd16e3550c25a0770f47f0bf21780f3 Mon Sep 17 00:00:00 2001 +From: Evgeny Vereshchagin +Date: Wed, 30 Dec 2015 03:33:43 +0000 +Subject: [PATCH] tests: add regression test for `systemctl restart + systemd-journald` + +See https://github.com/systemd/systemd/issues/2236 + +(cherry picked from commit 3889613ec6bc54b9e02955f62b9d5c5b571c3d4b) +(cherry picked from commit 4dc893c03fe9c56a3d3070fb8583f5584014aa49) +Resolves: #1803802 +--- + test/TEST-04-JOURNAL/test-journal.sh | 8 ++++++++ + test/TEST-04-JOURNAL/test.sh | 9 +++++++++ + 2 files changed, 17 insertions(+) + +diff --git a/test/TEST-04-JOURNAL/test-journal.sh b/test/TEST-04-JOURNAL/test-journal.sh +index c75f396ceb..701b0cf724 100755 +--- a/test/TEST-04-JOURNAL/test-journal.sh ++++ b/test/TEST-04-JOURNAL/test-journal.sh +@@ -14,5 +14,13 @@ journalctl --flush + journalctl -b -o cat -t "$ID" >/output + cmp /expected /output + ++# Don't lose streams on restart ++systemctl start forever-print-hola ++sleep 3 ++systemctl restart systemd-journald ++sleep 3 ++systemctl stop forever-print-hola ++[[ ! -f "/i-lose-my-logs" ]] ++ + touch /testok + exit 0 +diff --git a/test/TEST-04-JOURNAL/test.sh b/test/TEST-04-JOURNAL/test.sh +index e37cb7d412..6aea67ba4e 100755 +--- a/test/TEST-04-JOURNAL/test.sh ++++ b/test/TEST-04-JOURNAL/test.sh +@@ -55,6 +55,15 @@ After=multi-user.target + [Service] + ExecStart=/test-journal.sh + Type=oneshot ++EOF ++ ++ cat >$initdir/etc/systemd/system/forever-print-hola.service < +Date: Thu, 20 Oct 2016 13:18:12 +0000 +Subject: [PATCH] tests: add test that journald keeps fds over termination by + signal + +This test fails before previous commit, and passes with it. + +(cherry picked from commit bff653e3970bb79832568ae86b095ee530b62302) +(cherry picked from commit ee8f69ae5ddac6f05c56ea7dbcb76fbbb2e355ee) +Resolves: #1803802 +--- + test/TEST-04-JOURNAL/test-journal.sh | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/test/TEST-04-JOURNAL/test-journal.sh b/test/TEST-04-JOURNAL/test-journal.sh +index 701b0cf724..d0b05c46d6 100755 +--- a/test/TEST-04-JOURNAL/test-journal.sh ++++ b/test/TEST-04-JOURNAL/test-journal.sh +@@ -22,5 +22,13 @@ sleep 3 + systemctl stop forever-print-hola + [[ ! -f "/i-lose-my-logs" ]] + ++# https://github.com/systemd/systemd/issues/4408 ++rm -f /i-lose-my-logs ++systemctl start forever-print-hola ++sleep 3 ++systemctl kill --signal=SIGKILL systemd-journald ++sleep 3 ++[[ ! -f "/i-lose-my-logs" ]] ++ + touch /testok + exit 0 diff --git a/SOURCES/0807-journal-do-not-trigger-assertion-when-journal_file_c.patch b/SOURCES/0807-journal-do-not-trigger-assertion-when-journal_file_c.patch new file mode 100644 index 00000000..0910c9f7 --- /dev/null +++ b/SOURCES/0807-journal-do-not-trigger-assertion-when-journal_file_c.patch @@ -0,0 +1,50 @@ +From d8c33d7a4e0d9b4375159776913f5c3fd2905c21 Mon Sep 17 00:00:00 2001 +From: Jan Synacek +Date: Tue, 7 Jan 2020 11:22:26 +0100 +Subject: [PATCH] journal: do not trigger assertion when journal_file_close() + get NULL + +We generally expect destructors to not complain if a NULL argument is passed. + +Closes #12400. + +(cherry picked from commit c377a6f3ad3d9bed4ce7e873e8e9ec6b1650c57d) +(cherry picked from commit 248925c68092bab7ce0231449176db153f55d818) +Resolves: #1807798 +--- + src/journal/journal-file.c | 3 ++- + src/journal/journald-server.c | 7 ++----- + 2 files changed, 4 insertions(+), 6 deletions(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index 586f620e21..cf8dad3fcd 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -129,7 +129,8 @@ int journal_file_set_offline(JournalFile *f) { + } + + void journal_file_close(JournalFile *f) { +- assert(f); ++ if (!f) ++ return; + + #ifdef HAVE_GCRYPT + /* Write the final tag */ +diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c +index aaabb2f7ab..ffe2daa7be 100644 +--- a/src/journal/journald-server.c ++++ b/src/journal/journald-server.c +@@ -1933,11 +1933,8 @@ void server_done(Server *s) { + while (s->stdout_streams) + stdout_stream_free(s->stdout_streams); + +- if (s->system_journal) +- journal_file_close(s->system_journal); +- +- if (s->runtime_journal) +- journal_file_close(s->runtime_journal); ++ (void) journal_file_close(s->system_journal); ++ (void) journal_file_close(s->runtime_journal); + + while ((f = ordered_hashmap_steal_first(s->user_journals))) + journal_file_close(f); diff --git a/SOURCES/0808-mount-don-t-propagate-errors-from-mount_setup_unit-f.patch b/SOURCES/0808-mount-don-t-propagate-errors-from-mount_setup_unit-f.patch new file mode 100644 index 00000000..a8de3354 --- /dev/null +++ b/SOURCES/0808-mount-don-t-propagate-errors-from-mount_setup_unit-f.patch @@ -0,0 +1,53 @@ +From 5b7b538fcd268288cea8d8b7f16f839afbf74f39 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 28 Nov 2018 12:41:44 +0100 +Subject: [PATCH] mount: don't propagate errors from mount_setup_unit() further + up + +If we can't process a specific line in /proc/self/mountinfo we should +log about it (which we do), but this should not affect other lines, nor +further processing of mount units. Let's keep these failures local. + +Fixes: #10874 +(cherry picked from commit ba0d56f55f2073164799be714b5bd1aad94d059a) +Resolves: #1809159 +--- + src/core/mount.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index 3167bd6bb1..126038c27f 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -1571,7 +1571,7 @@ fail: + static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { + _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL; + _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL; +- int r = 0; ++ int r; + + assert(m); + +@@ -1587,7 +1587,6 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { + if (r < 0) + return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m"); + +- r = 0; + for (;;) { + const char *device, *path, *options, *fstype; + _cleanup_free_ const char *d = NULL, *p = NULL; +@@ -1615,12 +1614,10 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { + + (void) device_found_node(m, d, true, DEVICE_FOUND_MOUNT, set_flags); + +- k = mount_setup_unit(m, d, p, options, fstype, set_flags); +- if (r == 0 && k < 0) +- r = k; ++ (void) mount_setup_unit(m, d, p, options, fstype, set_flags); + } + +- return r; ++ return 0; + } + + static void mount_shutdown(Manager *m) { diff --git a/SOURCES/0809-mount-when-allocating-a-Mount-object-based-on-proc-s.patch b/SOURCES/0809-mount-when-allocating-a-Mount-object-based-on-proc-s.patch new file mode 100644 index 00000000..d689d1ab --- /dev/null +++ b/SOURCES/0809-mount-when-allocating-a-Mount-object-based-on-proc-s.patch @@ -0,0 +1,35 @@ +From 58407f55ccfc83eef2bd14e672d13213ef93069d Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 28 Nov 2018 14:51:04 +0100 +Subject: [PATCH] mount: when allocating a Mount object based on + /proc/self/mountinfo mark it so + +Let's set 'from_proc_self_mountinfo' right away, since we know its from +there. This is important so that when the load queue is dispatched (and +thus mount_load() called) this +fact is already known. + +(cherry picked from commit 6d7e89b07065b8c49af47aaf1ccc336d017fc3a2) +Related: #1809159 +--- + src/core/mount.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/core/mount.c b/src/core/mount.c +index 126038c27f..34c4b548ad 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -1480,6 +1480,13 @@ static int mount_setup_unit( + } + } + ++ /* This unit was generated because /proc/self/mountinfo reported it. Remember this, so that by the time we load ++ * the unit file for it (and thus add in extra deps right after) we know what source to attributes the deps ++ * to.*/ ++ MOUNT(u)->from_proc_self_mountinfo = true; ++ ++ /* We have only allocated the stub now, let's enqueue this unit for loading now, so that everything else is ++ * loaded in now. */ + unit_add_to_load_queue(u); + changed = true; + } else { diff --git a/SOURCES/0810-core-enforce-a-ratelimiter-when-stopping-units-due-t.patch b/SOURCES/0810-core-enforce-a-ratelimiter-when-stopping-units-due-t.patch new file mode 100644 index 00000000..3d94ec41 --- /dev/null +++ b/SOURCES/0810-core-enforce-a-ratelimiter-when-stopping-units-due-t.patch @@ -0,0 +1,60 @@ +From f57ee0c7862260f3c7054b224f360cdef5140685 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Tue, 19 May 2015 16:00:24 +0200 +Subject: [PATCH] core: enforce a ratelimiter when stopping units due to + StopWhenUnneeded=1 + +Otherwise we might end up in an endless stop loop. + +http://lists.freedesktop.org/archives/systemd-devel/2015-April/030224.html +(cherry picked from commit bea355dac94e82697aa98e25d80ee4248263bf92) +(cherry picked from commit 6c72a575c7c61e17c8e96b23042f7b4a5ac39339) + +Related: #1810576 +--- + src/core/unit.c | 10 ++++++++++ + src/core/unit.h | 3 +++ + 2 files changed, 13 insertions(+) + +diff --git a/src/core/unit.c b/src/core/unit.c +index eff9fdbe70..583b9fae28 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -97,6 +97,8 @@ Unit *unit_new(Manager *m, size_t size) { + u->on_failure_job_mode = JOB_REPLACE; + u->sigchldgen = 0; + ++ RATELIMIT_INIT(u->check_unneeded_ratelimit, 10 * USEC_PER_SEC, 16); ++ + return u; + } + +@@ -1594,6 +1596,14 @@ static void unit_check_unneeded(Unit *u) { + if (unit_active_or_pending(other)) + return; + ++ /* If stopping a unit fails continously we might enter a stop ++ * loop here, hence stop acting on the service being ++ * unnecessary after a while. */ ++ if (!ratelimit_test(&u->check_unneeded_ratelimit)) { ++ log_unit_warning(u->id, "Unit not needed anymore, but not stopping since we tried this too often recently."); ++ return; ++ } ++ + log_unit_info(u->id, "Unit %s is not needed anymore. Stopping.", u->id); + + /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */ +diff --git a/src/core/unit.h b/src/core/unit.h +index 3b0fd8d9df..29353ea81c 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -185,6 +185,9 @@ struct Unit { + /* Error code when we didn't manage to load the unit (negative) */ + int load_error; + ++ /* Make sure we never enter endless loops with the check unneeded logic */ ++ RateLimit check_unneeded_ratelimit; ++ + /* Cached unit file state and preset */ + UnitFileState unit_file_state; + int unit_file_preset; diff --git a/SOURCES/0811-core-rework-StopWhenUnneeded-logic.patch b/SOURCES/0811-core-rework-StopWhenUnneeded-logic.patch new file mode 100644 index 00000000..cc78e667 --- /dev/null +++ b/SOURCES/0811-core-rework-StopWhenUnneeded-logic.patch @@ -0,0 +1,343 @@ +From c7c8a7648623a25c00dc585bd42b9037a20396c8 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Thu, 9 Aug 2018 16:26:27 +0200 +Subject: [PATCH] core: rework StopWhenUnneeded= logic + +Previously, we'd act immediately on StopWhenUnneeded= when a unit state +changes. With this rework we'll maintain a queue instead: whenever +there's the chance that StopWhenUneeded= might have an effect we enqueue +the unit, and process it later when we have nothing better to do. + +This should make the implementation a bit more reliable, as the unit notify event +cannot immediately enqueue tons of side-effect jobs that might +contradict each other, but we do so only in a strictly ordered fashion, +from the main event loop. + +This slightly changes the check when to consider a unit "unneeded". +Previously, we'd assume that a unit in "deactivating" state could also +be cleaned up. With this new logic we'll only consider units unneeded +that are fully up and have no job queued. This means that whenever +there's something pending for a unit we won't clean it up. + +(cherry picked from commit a3c1168ac293f16d9343d248795bb4c246aaff4a) +(cherry picked from commit 65ebf5e453846e29ab5894670a83b5d8b942c858) + +Resolves: #1810576 +--- + src/core/manager.c | 43 +++++++++++++++ + src/core/manager.h | 3 ++ + src/core/unit.c | 132 ++++++++++++++++++++++++--------------------- + src/core/unit.h | 7 +++ + 4 files changed, 124 insertions(+), 61 deletions(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 4c87ad8a2f..f0553b4df9 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -961,6 +961,45 @@ static unsigned manager_dispatch_gc_queue(Manager *m) { + return n; + } + ++static unsigned manager_dispatch_stop_when_unneeded_queue(Manager *m) { ++ unsigned n = 0; ++ Unit *u; ++ int r; ++ ++ assert(m); ++ ++ while ((u = m->stop_when_unneeded_queue)) { ++ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; ++ assert(m->stop_when_unneeded_queue); ++ ++ assert(u->in_stop_when_unneeded_queue); ++ LIST_REMOVE(stop_when_unneeded_queue, m->stop_when_unneeded_queue, u); ++ u->in_stop_when_unneeded_queue = false; ++ ++ n++; ++ ++ if (!unit_is_unneeded(u)) ++ continue; ++ ++ log_unit_debug(u->id, "Unit is not needed anymore."); ++ ++ /* If stopping a unit fails continuously we might enter a stop loop here, hence stop acting on the ++ * service being unnecessary after a while. */ ++ ++ if (!ratelimit_test(&u->check_unneeded_ratelimit)) { ++ log_unit_warning(u->id, "Unit not needed anymore, but not stopping since we tried this too often recently."); ++ continue; ++ } ++ ++ /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */ ++ r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, &error, NULL); ++ if (r < 0) ++ log_unit_warning_errno(u->id, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r)); ++ } ++ ++ return n; ++} ++ + static void manager_clear_jobs_and_units(Manager *m) { + Unit *u; + +@@ -977,6 +1016,7 @@ static void manager_clear_jobs_and_units(Manager *m) { + assert(!m->dbus_job_queue); + assert(!m->cleanup_queue); + assert(!m->gc_queue); ++ assert(!m->stop_when_unneeded_queue); + + assert(hashmap_isempty(m->jobs)); + assert(hashmap_isempty(m->units)); +@@ -2259,6 +2299,9 @@ int manager_loop(Manager *m) { + if (manager_dispatch_cgroup_queue(m) > 0) + continue; + ++ if (manager_dispatch_stop_when_unneeded_queue(m) > 0) ++ continue; ++ + if (manager_dispatch_dbus_queue(m) > 0) + continue; + +diff --git a/src/core/manager.h b/src/core/manager.h +index cfc564dfb6..f9280956e9 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -117,6 +117,9 @@ struct Manager { + /* Target units whose default target dependencies haven't been set yet */ + LIST_HEAD(Unit, target_deps_queue); + ++ /* Units that might be subject to StopWhenUnneeded= clean-up */ ++ LIST_HEAD(Unit, stop_when_unneeded_queue); ++ + sd_event *event; + + /* We use two hash tables here, since the same PID might be +diff --git a/src/core/unit.c b/src/core/unit.c +index 583b9fae28..dc2df4c89c 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -380,6 +380,22 @@ void unit_add_to_dbus_queue(Unit *u) { + u->in_dbus_queue = true; + } + ++void unit_add_to_stop_when_unneeded_queue(Unit *u) { ++ assert(u); ++ ++ if (u->in_stop_when_unneeded_queue) ++ return; ++ ++ if (!u->stop_when_unneeded) ++ return; ++ ++ if (!UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) ++ return; ++ ++ LIST_PREPEND(stop_when_unneeded_queue, u->manager->stop_when_unneeded_queue, u); ++ u->in_stop_when_unneeded_queue = true; ++} ++ + static void bidi_set_free(Unit *u, Set *s) { + Iterator i; + Unit *other; +@@ -544,6 +560,9 @@ void unit_free(Unit *u) { + u->manager->n_in_gc_queue--; + } + ++ if (u->in_stop_when_unneeded_queue) ++ LIST_REMOVE(stop_when_unneeded_queue, u->manager->stop_when_unneeded_queue, u); ++ + if (u->on_console) + manager_unref_console(u->manager); + +@@ -1565,49 +1584,68 @@ bool unit_can_reload(Unit *u) { + return UNIT_VTABLE(u)->can_reload(u); + } + +-static void unit_check_unneeded(Unit *u) { +- Iterator i; +- Unit *other; ++bool unit_is_unneeded(Unit *u) { ++ static const UnitDependency deps[] = { ++ UNIT_REQUIRED_BY, ++ UNIT_REQUIRED_BY_OVERRIDABLE, ++ UNIT_WANTED_BY, ++ UNIT_BOUND_BY, ++ }; ++ size_t j; + + assert(u); + +- /* If this service shall be shut down when unneeded then do +- * so. */ +- + if (!u->stop_when_unneeded) +- return; ++ return false; + +- if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) +- return; ++ /* Don't clean up while the unit is transitioning or is even inactive. */ ++ if (!UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) ++ return false; ++ if (u->job) ++ return false; + +- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i) +- if (unit_active_or_pending(other)) +- return; ++ for (j = 0; j < ELEMENTSOF(deps); j++) { ++ Unit *other; ++ Iterator i; + +- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i) +- if (unit_active_or_pending(other)) +- return; ++ /* If a dependending unit has a job queued, or is active (or in transitioning), or is marked for ++ * restart, then don't clean this one up. */ + +- SET_FOREACH(other, u->dependencies[UNIT_WANTED_BY], i) +- if (unit_active_or_pending(other)) +- return; ++ SET_FOREACH(other, u->dependencies[deps[j]], i) { ++ if (u->job) ++ return false; + +- SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i) +- if (unit_active_or_pending(other)) +- return; +- +- /* If stopping a unit fails continously we might enter a stop +- * loop here, hence stop acting on the service being +- * unnecessary after a while. */ +- if (!ratelimit_test(&u->check_unneeded_ratelimit)) { +- log_unit_warning(u->id, "Unit not needed anymore, but not stopping since we tried this too often recently."); +- return; ++ if (!UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) ++ return false; ++ } + } + +- log_unit_info(u->id, "Unit %s is not needed anymore. Stopping.", u->id); ++ return true; ++} + +- /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */ +- manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL); ++static void check_unneeded_dependencies(Unit *u) { ++ ++ static const UnitDependency deps[] = { ++ UNIT_REQUIRES, ++ UNIT_REQUIRES_OVERRIDABLE, ++ UNIT_REQUISITE, ++ UNIT_REQUISITE_OVERRIDABLE, ++ UNIT_WANTS, ++ UNIT_BINDS_TO, ++ }; ++ size_t j; ++ ++ assert(u); ++ ++ /* Add all units this unit depends on to the queue that processes StopWhenUnneeded= behaviour. */ ++ ++ for (j = 0; j < ELEMENTSOF(deps); j++) { ++ Unit *other; ++ Iterator i; ++ ++ SET_FOREACH(other, u->dependencies[deps[j]], i) ++ unit_add_to_stop_when_unneeded_queue(other); ++ } + } + + static void unit_check_binds_to(Unit *u) { +@@ -1693,34 +1731,6 @@ static void retroactively_stop_dependencies(Unit *u) { + manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL); + } + +-static void check_unneeded_dependencies(Unit *u) { +- Iterator i; +- Unit *other; +- +- assert(u); +- assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u))); +- +- /* Garbage collect services that might not be needed anymore, if enabled */ +- SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i) +- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) +- unit_check_unneeded(other); +- SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) +- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) +- unit_check_unneeded(other); +- SET_FOREACH(other, u->dependencies[UNIT_WANTS], i) +- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) +- unit_check_unneeded(other); +- SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i) +- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) +- unit_check_unneeded(other); +- SET_FOREACH(other, u->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) +- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) +- unit_check_unneeded(other); +- SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i) +- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) +- unit_check_unneeded(other); +-} +- + void unit_start_on_failure(Unit *u) { + Unit *other; + Iterator i; +@@ -1898,7 +1908,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su + } + + /* stop unneeded units regardless if going down was expected or not */ +- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(ns)) ++ if (UNIT_IS_INACTIVE_OR_FAILED(ns)) + check_unneeded_dependencies(u); + + if (ns != os && ns == UNIT_FAILED) { +@@ -1959,7 +1969,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su + if (u->manager->n_reloading <= 0) { + /* Maybe we finished startup and are now ready for + * being stopped because unneeded? */ +- unit_check_unneeded(u); ++ unit_add_to_stop_when_unneeded_queue(u); + + /* Maybe we finished startup, but something we needed + * has vanished? Let's die then. (This happens when +diff --git a/src/core/unit.h b/src/core/unit.h +index 29353ea81c..38c97397ee 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -165,6 +165,9 @@ struct Unit { + /* Target dependencies queue */ + LIST_FIELDS(Unit, target_deps_queue); + ++ /* Queue of units with StopWhenUnneeded set that shell be checked for clean-up. */ ++ LIST_FIELDS(Unit, stop_when_unneeded_queue); ++ + /* PIDs we keep an eye on. Note that a unit might have many + * more, but these are the ones we care enough about to + * process SIGCHLD for */ +@@ -235,6 +238,7 @@ struct Unit { + bool in_gc_queue:1; + bool in_cgroup_queue:1; + bool in_target_deps_queue:1; ++ bool in_stop_when_unneeded_queue:1; + + bool sent_dbus_new_signal:1; + +@@ -508,6 +512,7 @@ void unit_add_to_dbus_queue(Unit *u); + void unit_add_to_cleanup_queue(Unit *u); + void unit_add_to_gc_queue(Unit *u); + void unit_add_to_target_deps_queue(Unit *u); ++void unit_add_to_stop_when_unneeded_queue(Unit *u); + + int unit_merge(Unit *u, Unit *other); + int unit_merge_by_name(Unit *u, const char *other); +@@ -627,6 +632,8 @@ int unit_make_transient(Unit *u); + + int unit_require_mounts_for(Unit *u, const char *path); + ++bool unit_is_unneeded(Unit *u); ++ + pid_t unit_control_pid(Unit *u); + pid_t unit_main_pid(Unit *u); + diff --git a/SOURCES/0812-fix-the-fix-for-1691511.patch b/SOURCES/0812-fix-the-fix-for-1691511.patch new file mode 100644 index 00000000..95f38e77 --- /dev/null +++ b/SOURCES/0812-fix-the-fix-for-1691511.patch @@ -0,0 +1,53 @@ +From 659b97b93d93ad05732831f6f097cf6f2a9c6410 Mon Sep 17 00:00:00 2001 +From: David Tardon +Date: Mon, 16 Mar 2020 09:37:22 +0100 +Subject: [PATCH] fix the fix for #1691511 + +The fix for #1691511 should have been used only for existing mounts +(mount_setup_existing_unit() in current master). + +(cherry picked from commit 4584818bea998d257a166c238b829025b6138e55) + +Related: #1809159 +--- + src/core/mount.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/core/mount.c b/src/core/mount.c +index 34c4b548ad..56fda1b73f 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -1416,6 +1416,7 @@ static int mount_setup_unit( + bool load_extras = false; + MountParameters *p; + bool delete, changed = false; ++ bool just_mounted; + Unit *u; + int r; + +@@ -1489,6 +1490,7 @@ static int mount_setup_unit( + * loaded in now. */ + unit_add_to_load_queue(u); + changed = true; ++ just_mounted = true; + } else { + delete = false; + +@@ -1518,6 +1520,8 @@ static int mount_setup_unit( + load_extras = true; + changed = true; + } ++ ++ just_mounted = !MOUNT(u)->from_proc_self_mountinfo || MOUNT(u)->just_mounted; + } + + w = strdup(what); +@@ -1537,7 +1541,7 @@ static int mount_setup_unit( + + if (set_flags) { + MOUNT(u)->is_mounted = true; +- MOUNT(u)->just_mounted = !MOUNT(u)->from_proc_self_mountinfo || MOUNT(u)->just_mounted; ++ MOUNT(u)->just_mounted = just_mounted; + MOUNT(u)->just_changed = changed; + } + diff --git a/SOURCES/0813-sd-bus-when-attached-to-an-sd-event-loop-disconnect-.patch b/SOURCES/0813-sd-bus-when-attached-to-an-sd-event-loop-disconnect-.patch new file mode 100644 index 00000000..32d6eb2a --- /dev/null +++ b/SOURCES/0813-sd-bus-when-attached-to-an-sd-event-loop-disconnect-.patch @@ -0,0 +1,106 @@ +From e525ce5713f8263258c2cdf687adc67108425f6a Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 15 Dec 2017 22:24:16 +0100 +Subject: [PATCH] sd-bus: when attached to an sd-event loop, disconnect on + processing errors + +If we can't process the bus for some reason we shouldn't just disable +the event source, but log something and give up on the connection. Hence +do that, and disconnect. + +(cherry-picked from commit 5ae37ad833583e6c1c7765767b7f8360afca3b07) + +Resolves: #1817504 +--- + src/libsystemd/sd-bus/sd-bus.c | 45 +++++++++++++++++++++------------- + 1 file changed, 28 insertions(+), 17 deletions(-) + +diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c +index 44ed2c7497..2c8cc66367 100644 +--- a/src/libsystemd/sd-bus/sd-bus.c ++++ b/src/libsystemd/sd-bus/sd-bus.c +@@ -3037,8 +3037,10 @@ static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userd + assert(bus); + + r = sd_bus_process(bus, NULL); +- if (r < 0) +- return r; ++ if (r < 0) { ++ log_debug_errno(r, "Processing of bus failed, closing down: %m"); ++ bus_enter_closing(bus); ++ } + + return 1; + } +@@ -3050,8 +3052,10 @@ static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) { + assert(bus); + + r = sd_bus_process(bus, NULL); +- if (r < 0) +- return r; ++ if (r < 0) { ++ log_debug_errno(r, "Processing of bus failed, closing down: %m"); ++ bus_enter_closing(bus); ++ } + + return 1; + } +@@ -3065,38 +3069,45 @@ static int prepare_callback(sd_event_source *s, void *userdata) { + assert(bus); + + e = sd_bus_get_events(bus); +- if (e < 0) +- return e; ++ if (e < 0) { ++ r = e; ++ goto fail; ++ } + + if (bus->output_fd != bus->input_fd) { + + r = sd_event_source_set_io_events(bus->input_io_event_source, e & POLLIN); + if (r < 0) +- return r; ++ goto fail; + + r = sd_event_source_set_io_events(bus->output_io_event_source, e & POLLOUT); +- if (r < 0) +- return r; +- } else { ++ } else + r = sd_event_source_set_io_events(bus->input_io_event_source, e); +- if (r < 0) +- return r; +- } ++ if (r < 0) ++ goto fail; + + r = sd_bus_get_timeout(bus, &until); + if (r < 0) +- return r; ++ goto fail; + if (r > 0) { + int j; + + j = sd_event_source_set_time(bus->time_event_source, until); +- if (j < 0) +- return j; ++ if (j < 0) { ++ r = j; ++ goto fail; ++ } + } + + r = sd_event_source_set_enabled(bus->time_event_source, r > 0); + if (r < 0) +- return r; ++ goto fail; ++ ++ return 1; ++ ++fail: ++ log_debug_errno(r, "Preparing of bus events failed, closing down: %m"); ++ bus_enter_closing(bus); + + return 1; + } diff --git a/SOURCES/0814-sd-journal-close-journal-files-that-were-deleted-by-.patch b/SOURCES/0814-sd-journal-close-journal-files-that-were-deleted-by-.patch new file mode 100644 index 00000000..03e1dd2d --- /dev/null +++ b/SOURCES/0814-sd-journal-close-journal-files-that-were-deleted-by-.patch @@ -0,0 +1,75 @@ +From f813fe0bebb2dddf0fe961527c6e840b88d49dc3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= +Date: Tue, 4 Feb 2020 14:23:14 +0100 +Subject: [PATCH] sd-journal: close journal files that were deleted by journald + before we've setup inotify watch + +(cherry-picked from commit 28ca867abdb20d0e4ac1901e2ed669cdb41ea3f6) + +Fixes #14695 + +Related: #1820073 +--- + src/journal/journal-file.c | 2 +- + src/journal/journal-file.h | 1 + + src/journal/sd-journal.c | 15 +++++++++++++++ + 3 files changed, 17 insertions(+), 1 deletion(-) + +diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c +index cf8dad3fcd..86a7e2642a 100644 +--- a/src/journal/journal-file.c ++++ b/src/journal/journal-file.c +@@ -337,7 +337,7 @@ static int journal_file_verify_header(JournalFile *f) { + return 0; + } + +-static int journal_file_fstat(JournalFile *f) { ++int journal_file_fstat(JournalFile *f) { + assert(f); + assert(f->fd >= 0); + +diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h +index 37749c4459..ee9772b9bb 100644 +--- a/src/journal/journal-file.h ++++ b/src/journal/journal-file.h +@@ -139,6 +139,7 @@ int journal_file_open( + + int journal_file_set_offline(JournalFile *f); + void journal_file_close(JournalFile *j); ++int journal_file_fstat(JournalFile *j); + + int journal_file_open_reliably( + const char *fname, +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index 004fe646d4..09466df810 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -2386,6 +2386,8 @@ _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) { + assert_return(!journal_pid_changed(j), -ECHILD); + + if (j->inotify_fd < 0) { ++ Iterator i; ++ JournalFile *f; + + /* This is the first invocation, hence create the + * inotify watch */ +@@ -2393,6 +2395,19 @@ _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) { + if (r < 0) + return r; + ++ /* Server might have done some vacuuming while we weren't watching. ++ Get rid of the deleted files now so they don't stay around indefinitely. */ ++ ORDERED_HASHMAP_FOREACH(f, j->files, i) { ++ r = journal_file_fstat(f); ++ if (r < 0) { ++ log_error("Failed to fstat() journal file '%s' : %m", f->path); ++ continue; ++ } ++ ++ if (f->last_stat.st_nlink <= 0) ++ remove_file_real(j, f); ++ } ++ + /* The journal might have changed since the context + * object was created and we weren't watching before, + * hence don't wait for anything, and return diff --git a/SOURCES/0815-sd-journal-remove-the-dead-code-and-actually-fix-146.patch b/SOURCES/0815-sd-journal-remove-the-dead-code-and-actually-fix-146.patch new file mode 100644 index 00000000..b083bc73 --- /dev/null +++ b/SOURCES/0815-sd-journal-remove-the-dead-code-and-actually-fix-146.patch @@ -0,0 +1,42 @@ +From fadf2a316458ac262f3d5f690bd481fac2d4e566 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= +Date: Fri, 27 Mar 2020 17:01:59 +0100 +Subject: [PATCH] sd-journal: remove the dead code and actually fix #14695 + +journal_file_fstat() returns an error if we call it on already unlinked +journal file and hence we never reach remove_file_real() which is the +entire point. + +I must have made some mistake while testing the fix that got me thinking +the issue is gone while opposite was true. + +Fixes #14695 + +(cherry-picked from commit 8581b9f9732d4c158bb5f773230a65ce77f2c292) + +Resolves: #1820073 +--- + src/journal/sd-journal.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c +index 09466df810..1f03c8e8ba 100644 +--- a/src/journal/sd-journal.c ++++ b/src/journal/sd-journal.c +@@ -2399,13 +2399,12 @@ _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) { + Get rid of the deleted files now so they don't stay around indefinitely. */ + ORDERED_HASHMAP_FOREACH(f, j->files, i) { + r = journal_file_fstat(f); +- if (r < 0) { ++ if (r == -EIDRM) ++ remove_file_real(j, f); ++ else if (r < 0) { + log_error("Failed to fstat() journal file '%s' : %m", f->path); + continue; + } +- +- if (f->last_stat.st_nlink <= 0) +- remove_file_real(j, f); + } + + /* The journal might have changed since the context diff --git a/SOURCES/0816-swap-adjust-swap.c-in-a-similar-way-to-what-we-just-.patch b/SOURCES/0816-swap-adjust-swap.c-in-a-similar-way-to-what-we-just-.patch new file mode 100644 index 00000000..f15b4d8c --- /dev/null +++ b/SOURCES/0816-swap-adjust-swap.c-in-a-similar-way-to-what-we-just-.patch @@ -0,0 +1,260 @@ +From 6181124fac6fbfd83e12fbe5f0068da826ab5772 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Mon, 25 Sep 2017 19:53:19 +0200 +Subject: [PATCH] swap: adjust swap.c in a similar way to what we just did to + mount.c + +Also drop the redundant states and make all similar changes too. +Thankfully the swap.c state engine is much simpler than mount.c's, hence +this should be easier to digest. + +(cherry picked from commit 50864457e1bc5f7a4ab2fd02e1565bc5d135d2f3) +(cherry picked from commit 714dbded2ac725e1e2e6b61a289c118dae555dee) + +Related: #1821261 +--- + src/core/swap.c | 96 +++++++++++++++++++++++-------------------------- + src/core/swap.h | 2 -- + 2 files changed, 44 insertions(+), 54 deletions(-) + +diff --git a/src/core/swap.c b/src/core/swap.c +index 4a5e882332..c9cce3d945 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -49,8 +49,6 @@ static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = { + [SWAP_ACTIVATING_DONE] = UNIT_ACTIVE, + [SWAP_ACTIVE] = UNIT_ACTIVE, + [SWAP_DEACTIVATING] = UNIT_DEACTIVATING, +- [SWAP_ACTIVATING_SIGTERM] = UNIT_DEACTIVATING, +- [SWAP_ACTIVATING_SIGKILL] = UNIT_DEACTIVATING, + [SWAP_DEACTIVATING_SIGTERM] = UNIT_DEACTIVATING, + [SWAP_DEACTIVATING_SIGKILL] = UNIT_DEACTIVATING, + [SWAP_FAILED] = UNIT_FAILED +@@ -490,8 +488,6 @@ static void swap_set_state(Swap *s, SwapState state) { + s->state = state; + + if (state != SWAP_ACTIVATING && +- state != SWAP_ACTIVATING_SIGTERM && +- state != SWAP_ACTIVATING_SIGKILL && + state != SWAP_ACTIVATING_DONE && + state != SWAP_DEACTIVATING && + state != SWAP_DEACTIVATING_SIGTERM && +@@ -538,8 +534,6 @@ static int swap_coldplug(Unit *u, Hashmap *deferred_work) { + return 0; + + if (new_state == SWAP_ACTIVATING || +- new_state == SWAP_ACTIVATING_SIGTERM || +- new_state == SWAP_ACTIVATING_SIGKILL || + new_state == SWAP_ACTIVATING_DONE || + new_state == SWAP_DEACTIVATING || + new_state == SWAP_DEACTIVATING_SIGTERM || +@@ -682,6 +676,15 @@ static void swap_enter_active(Swap *s, SwapResult f) { + swap_set_state(s, SWAP_ACTIVE); + } + ++static void swap_enter_dead_or_active(Swap *s, SwapResult f) { ++ assert(s); ++ ++ if (s->from_proc_swaps) ++ swap_enter_active(s, f); ++ else ++ swap_enter_dead(s, f); ++} ++ + static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) { + int r; + +@@ -693,8 +696,7 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) { + r = unit_kill_context( + UNIT(s), + &s->kill_context, +- (state != SWAP_ACTIVATING_SIGTERM && state != SWAP_DEACTIVATING_SIGTERM) ? +- KILL_KILL : KILL_TERMINATE, ++ state != SWAP_DEACTIVATING_SIGTERM ? KILL_KILL : KILL_TERMINATE, + -1, + s->control_pid, + false); +@@ -707,18 +709,16 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) { + goto fail; + + swap_set_state(s, state); +- } else if (state == SWAP_ACTIVATING_SIGTERM) +- swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_SUCCESS); +- else if (state == SWAP_DEACTIVATING_SIGTERM) ++ } else if (state == SWAP_DEACTIVATING_SIGTERM && s->kill_context.send_sigkill) + swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_SUCCESS); + else +- swap_enter_dead(s, SWAP_SUCCESS); ++ swap_enter_dead_or_active(s, SWAP_SUCCESS); + + return; + + fail: + log_unit_warning_errno(UNIT(s)->id, r, "%s failed to kill processes: %m", UNIT(s)->id); +- swap_enter_dead(s, SWAP_FAILURE_RESOURCES); ++ swap_enter_dead_or_active(s, SWAP_FAILURE_RESOURCES); + } + + static void swap_enter_activating(Swap *s) { +@@ -781,7 +781,7 @@ static void swap_enter_activating(Swap *s) { + + fail: + log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'swapon' task: %m", UNIT(s)->id); +- swap_enter_dead(s, SWAP_FAILURE_RESOURCES); ++ swap_enter_dead_or_active(s, SWAP_FAILURE_RESOURCES); + } + + static void swap_enter_deactivating(Swap *s) { +@@ -811,7 +811,7 @@ static void swap_enter_deactivating(Swap *s) { + + fail: + log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'swapoff' task: %m", UNIT(s)->id); +- swap_enter_active(s, SWAP_FAILURE_RESOURCES); ++ swap_enter_dead_or_active(s, SWAP_FAILURE_RESOURCES); + } + + static int swap_start(Unit *u) { +@@ -824,11 +824,10 @@ static int swap_start(Unit *u) { + + if (s->state == SWAP_DEACTIVATING || + s->state == SWAP_DEACTIVATING_SIGTERM || +- s->state == SWAP_DEACTIVATING_SIGKILL || +- s->state == SWAP_ACTIVATING_SIGTERM || +- s->state == SWAP_ACTIVATING_SIGKILL) ++ s->state == SWAP_DEACTIVATING_SIGKILL) + return -EAGAIN; + ++ /* Already on it! */ + if (s->state == SWAP_ACTIVATING) + return 0; + +@@ -854,22 +853,30 @@ static int swap_stop(Unit *u) { + + assert(s); + +- if (s->state == SWAP_DEACTIVATING || +- s->state == SWAP_DEACTIVATING_SIGTERM || +- s->state == SWAP_DEACTIVATING_SIGKILL || +- s->state == SWAP_ACTIVATING_SIGTERM || +- s->state == SWAP_ACTIVATING_SIGKILL) ++ switch (s->state) { ++ ++ case SWAP_DEACTIVATING: ++ case SWAP_DEACTIVATING_SIGTERM: ++ case SWAP_DEACTIVATING_SIGKILL: ++ /* Already on it */ ++ return 0; ++ ++ case SWAP_ACTIVATING: ++ case SWAP_ACTIVATING_DONE: ++ /* There's a control process pending, directly enter kill mode */ ++ swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_SUCCESS); + return 0; + +- assert(s->state == SWAP_ACTIVATING || +- s->state == SWAP_ACTIVATING_DONE || +- s->state == SWAP_ACTIVE); ++ case SWAP_ACTIVE: ++ if (detect_container(NULL) > 0) ++ return -EPERM; + +- if (detect_container(NULL) > 0) +- return -EPERM; ++ swap_enter_deactivating(s); ++ return 1; + +- swap_enter_deactivating(s); +- return 1; ++ default: ++ assert_not_reached("Unexpected state."); ++ } + } + + static int swap_serialize(Unit *u, FILE *f, FDSet *fds) { +@@ -1002,10 +1009,8 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) { + + case SWAP_ACTIVATING: + case SWAP_ACTIVATING_DONE: +- case SWAP_ACTIVATING_SIGTERM: +- case SWAP_ACTIVATING_SIGKILL: + +- if (f == SWAP_SUCCESS) ++ if (f == SWAP_SUCCESS || s->from_proc_swaps) + swap_enter_active(s, f); + else + swap_enter_dead(s, f); +@@ -1015,7 +1020,7 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) { + case SWAP_DEACTIVATING_SIGKILL: + case SWAP_DEACTIVATING_SIGTERM: + +- swap_enter_dead(s, f); ++ swap_enter_dead_or_active(s, f); + break; + + default: +@@ -1037,7 +1042,7 @@ static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userd + case SWAP_ACTIVATING: + case SWAP_ACTIVATING_DONE: + log_unit_warning(UNIT(s)->id, "%s activation timed out. Stopping.", UNIT(s)->id); +- swap_enter_signal(s, SWAP_ACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT); ++ swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT); + break; + + case SWAP_DEACTIVATING: +@@ -1045,30 +1050,19 @@ static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userd + swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT); + break; + +- case SWAP_ACTIVATING_SIGTERM: +- if (s->kill_context.send_sigkill) { +- log_unit_warning(UNIT(s)->id, "%s activation timed out. Killing.", UNIT(s)->id); +- swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT); +- } else { +- log_unit_warning(UNIT(s)->id, "%s activation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id); +- swap_enter_dead(s, SWAP_FAILURE_TIMEOUT); +- } +- break; +- + case SWAP_DEACTIVATING_SIGTERM: + if (s->kill_context.send_sigkill) { +- log_unit_warning(UNIT(s)->id, "%s deactivation timed out. Killing.", UNIT(s)->id); ++ log_unit_warning(UNIT(s)->id, "Swap process timed out. Killing."); + swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT); + } else { +- log_unit_warning(UNIT(s)->id, "%s deactivation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id); +- swap_enter_dead(s, SWAP_FAILURE_TIMEOUT); ++ log_unit_warning(UNIT(s)->id, "Swap process timed out. Skipping SIGKILL. Ignoring."); ++ swap_enter_dead_or_active(s, SWAP_FAILURE_TIMEOUT); + } + break; + +- case SWAP_ACTIVATING_SIGKILL: + case SWAP_DEACTIVATING_SIGKILL: + log_unit_warning(UNIT(s)->id, "%s swap process still around after SIGKILL. Ignoring.", UNIT(s)->id); +- swap_enter_dead(s, SWAP_FAILURE_TIMEOUT); ++ swap_enter_dead_or_active(s, SWAP_FAILURE_TIMEOUT); + break; + + default: +@@ -1428,8 +1422,6 @@ static const char* const swap_state_table[_SWAP_STATE_MAX] = { + [SWAP_ACTIVATING_DONE] = "activating-done", + [SWAP_ACTIVE] = "active", + [SWAP_DEACTIVATING] = "deactivating", +- [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm", +- [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill", + [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm", + [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill", + [SWAP_FAILED] = "failed" +diff --git a/src/core/swap.h b/src/core/swap.h +index 914a2dbccd..f46873b5e1 100644 +--- a/src/core/swap.h ++++ b/src/core/swap.h +@@ -34,8 +34,6 @@ typedef enum SwapState { + SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */ + SWAP_ACTIVE, + SWAP_DEACTIVATING, +- SWAP_ACTIVATING_SIGTERM, +- SWAP_ACTIVATING_SIGKILL, + SWAP_DEACTIVATING_SIGTERM, + SWAP_DEACTIVATING_SIGKILL, + SWAP_FAILED, diff --git a/SOURCES/0817-swap-finish-the-secondary-swap-units-jobs-if-deactiv.patch b/SOURCES/0817-swap-finish-the-secondary-swap-units-jobs-if-deactiv.patch new file mode 100644 index 00000000..4c1fbc31 --- /dev/null +++ b/SOURCES/0817-swap-finish-the-secondary-swap-units-jobs-if-deactiv.patch @@ -0,0 +1,80 @@ +From 8877bffec31185b58ffa867d59ae0da213fae080 Mon Sep 17 00:00:00 2001 +From: HATAYAMA Daisuke +Date: Wed, 24 Jul 2019 23:54:48 -0400 +Subject: [PATCH] swap: finish the secondary swap units' jobs if deactivation + of the primary swap unit fails + +Currently, if deactivation of the primary swap unit fails: + + # LANG=C systemctl --no-pager stop dev-mapper-fedora\\x2dswap.swap + Job for dev-mapper-fedora\x2dswap.swap failed. + See "systemctl status "dev-mapper-fedora\\x2dswap.swap"" and "journalctl -xe" for details. + +then there are still the running stop jobs for all the secondary swap units +that follow the primary one: + + # systemctl list-jobs + JOB UNIT TYPE STATE + 3233 dev-disk-by\x2duuid-2dc8b9b1\x2da0a5\x2d44d8\x2d89c4\x2d6cdd26cd5ce0.swap stop running + 3232 dev-dm\x2d1.swap stop running + 3231 dev-disk-by\x2did-dm\x2duuid\x2dLVM\x2dyuXWpCCIurGzz2nkGCVnUFSi7GH6E3ZcQjkKLnF0Fil0RJmhoLN8fcOnDybWCMTj.swap stop running + 3230 dev-disk-by\x2did-dm\x2dname\x2dfedora\x2dswap.swap stop running + 3234 dev-fedora-swap.swap stop running + + 5 jobs listed. + +This remains endlessly because their JobTimeoutUSec is infinity: + + # LANG=C systemctl show -p JobTimeoutUSec dev-fedora-swap.swap + JobTimeoutUSec=infinity + +If this issue happens during system shutdown, the system shutdown appears to +get hang and the system will be forcibly shutdown or rebooted 30 minutes later +by the following configuration: + + # grep -E "^JobTimeout" /usr/lib/systemd/system/reboot.target + JobTimeoutSec=30min + JobTimeoutAction=reboot-force + +The scenario in the real world seems that there is some service unit with +KillMode=none, processes whose memory is being swapped out are not killed +during stop operation in the service unit and then swapoff command fails. + +On the other hand, it works well in successful case of swapoff command because +the secondary jobs monitor /proc/swaps file and can detect deletion of the +corresponding swap file. + +This commit fixes the issue by finishing the secondary swap units' jobs if +deactivation of the primary swap unit fails. + +Fixes: #11577 +(cherry picked from commit 9c1f969d40f84d5cc98d810bab8b24148b2d8928) +(cherry picked from commit 1e5b6b9930db88c3a5fb464bad13853885ea82f1) + +Resolves: #1821261 +--- + src/core/swap.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/core/swap.c b/src/core/swap.c +index c9cce3d945..ff27936142 100644 +--- a/src/core/swap.c ++++ b/src/core/swap.c +@@ -679,9 +679,15 @@ static void swap_enter_active(Swap *s, SwapResult f) { + static void swap_enter_dead_or_active(Swap *s, SwapResult f) { + assert(s); + +- if (s->from_proc_swaps) ++ if (s->from_proc_swaps) { ++ Swap *other; ++ + swap_enter_active(s, f); +- else ++ ++ LIST_FOREACH_OTHERS(same_devnode, other, s) ++ if (UNIT(other)->job) ++ swap_enter_dead_or_active(other, f); ++ } else + swap_enter_dead(s, f); + } + diff --git a/SOURCES/0818-udev-rules-make-tape-changers-also-apprear-in-dev-ta.patch b/SOURCES/0818-udev-rules-make-tape-changers-also-apprear-in-dev-ta.patch new file mode 100644 index 00000000..8c748f59 --- /dev/null +++ b/SOURCES/0818-udev-rules-make-tape-changers-also-apprear-in-dev-ta.patch @@ -0,0 +1,57 @@ +From 13f9e172d4a3576efa1ddacaca26286266866d2d Mon Sep 17 00:00:00 2001 +From: Joerg Steffens +Date: Tue, 21 Nov 2017 12:21:49 +0100 +Subject: [PATCH] udev-rules: make tape-changers also apprear in + /dev/tape/by-path/ + +It is important to be able to access tape changer ("Medium Changers") by +persistant name. +While tape devices can be accessed via /dev/tape/by-id/ and +/dev/tape/by-path/, tape-changers could only be accessed by +/dev/tape/by-id/. +However, in some cases, especially when accessing Amazon Webservice +Storage Gateway VTLs (or accessing iSCSI VTLs in general?) this does not +work, as all tape devices and the tape changer have the same ENV{ID_SERIAL}. +The results is, that only the last device is available in +/dev/tape/by-id/, as the former devices have been overwritten. + +As this behavior is hard to change without breaking consistentcy, +this additional device in /dev/tape/by-path/ can be used to access the medium changes. +The tape devices can also be accessed by this path. + +The content of the directory will now look like: + + # SCSI tape device, rewind (unchanged) + /dev/tape/by-path/$env{ID_PATH} -> ../../st* + + # SCSI tape device, no-rewind (unchanged) + /dev/tape/by-path/$env{ID_PATH}-nst -> ../../nst* + + # SCSI tape changer device (newly added) + /dev/tape/by-path/$env{ID_PATH}-changer -> ../../sg* + +Tape devices and tape changer have different ID_PATHs. +SCSI tape changer get the suffix "-changer" +to make them better distinguishable from tape devices. + +(cherry-picked from commit 7f8ddf96a25162f06bd94a684cf700c128d18142) +(cherry picked from commit 1b723aea42e29becd0be2fdef990401803dbfba6) +Resolves: #1814028 +--- + rules/60-persistent-storage-tape.rules | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/rules/60-persistent-storage-tape.rules b/rules/60-persistent-storage-tape.rules +index f2eabd92a8..99898c147b 100644 +--- a/rules/60-persistent-storage-tape.rules ++++ b/rules/60-persistent-storage-tape.rules +@@ -8,6 +8,9 @@ ACTION=="remove", GOTO="persistent_storage_tape_end" + SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="8", IMPORT{program}="scsi_id --sg-version=3 --export --whitelisted -d $devnode", \ + SYMLINK+="tape/by-id/scsi-$env{ID_SERIAL}" + ++SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="8", IMPORT{builtin}="path_id", \ ++ SYMLINK+="tape/by-path/$env{ID_PATH}-changer" ++ + SUBSYSTEM!="scsi_tape", GOTO="persistent_storage_tape_end" + + KERNEL=="st*[0-9]|nst*[0-9]", ATTRS{ieee1394_id}=="?*", ENV{ID_SERIAL}="$attr{ieee1394_id}", ENV{ID_BUS}="ieee1394" diff --git a/SOURCES/0819-core-make-sure-to-restore-the-control-command-id-too.patch b/SOURCES/0819-core-make-sure-to-restore-the-control-command-id-too.patch new file mode 100644 index 00000000..65e591de --- /dev/null +++ b/SOURCES/0819-core-make-sure-to-restore-the-control-command-id-too.patch @@ -0,0 +1,30 @@ +From 714d1c41100be669bd106df9a0efa76e49182e69 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 22 Apr 2020 20:34:02 +0200 +Subject: [PATCH] core: make sure to restore the control command id, too + +Fixes: #15356 +(cherry picked from commit e9da62b18af647bfa73807e1c7fc3bfa4bb4b2ac) + +Resolves: #1837973 +--- + src/core/service.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/core/service.c b/src/core/service.c +index e32cdf4594..df64fbaf60 100644 +--- a/src/core/service.c ++++ b/src/core/service.c +@@ -2263,9 +2263,10 @@ static int service_deserialize_exec_command(Unit *u, const char *key, const char + break; + } + +- if (command && control) ++ if (command && control) { + s->control_command = command; +- else if (command) ++ s->control_command_id = id; ++ } else if (command) + s->main_command = command; + else + log_unit_warning(u->id, "Current command vanished from the unit file, execution of the command list won't be resumed.");