diff --git a/Retry-to-handle-the-uevent-when-worker-is-terminated.patch b/Retry-to-handle-the-uevent-when-worker-is-terminated.patch new file mode 100644 index 0000000000000000000000000000000000000000..4d15ad51fe07fd0808c8899f9a7f4ddb5a7d0f5a --- /dev/null +++ b/Retry-to-handle-the-uevent-when-worker-is-terminated.patch @@ -0,0 +1,93 @@ +From a3d2f4261ef9a953904e3e21abafba0dad7daa77 Mon Sep 17 00:00:00 2001 +From: gaoyi +Date: Mon, 28 Sep 2020 22:36:37 +0800 +Subject: [PATCH] Retry to handle the uevent when worker is terminated abnormal + +When processing uevent events fails, retry it. +--- + src/udev/udevd.c | 41 ++++++++++++++++++++++++++++++++++++----- + 1 file changed, 36 insertions(+), 5 deletions(-) + +diff --git a/src/udev/udevd.c b/src/udev/udevd.c +index eb94ed3..5b743ad 100644 +--- a/src/udev/udevd.c ++++ b/src/udev/udevd.c +@@ -70,6 +70,7 @@ + #include "version.h" + + #define WORKER_NUM_MAX 2048U ++#define UEVENT_MAX_RETRY_TIMES 3 + + static bool arg_debug = false; + static int arg_daemonize = false; +@@ -114,6 +115,7 @@ typedef struct Event { + Manager *manager; + Worker *worker; + EventState state; ++ int retry; + + sd_device *dev; + sd_device *dev_kernel; /* clone of originally received device */ +@@ -148,6 +150,32 @@ typedef struct Worker { + typedef struct WorkerMessage { + } WorkerMessage; + ++static bool event_retry(Event *event) { ++ if (!event) ++ return false; ++ ++ assert(event->manager); ++ ++ if (--event->retry < 0) { ++ log_device_error(event->dev, "Retry failed."); ++ return false; ++ } ++ ++ log_device_info(event->dev, "Retry %d times.", UEVENT_MAX_RETRY_TIMES - event->retry); ++ ++ event->timeout_warning_event = sd_event_source_unref(event->timeout_warning_event); ++ event->timeout_event = sd_event_source_unref(event->timeout_event); ++ ++ if (event->worker) { ++ event->worker->event = NULL; ++ event->worker = NULL; ++ } ++ ++ event->state = EVENT_QUEUED; ++ ++ return true; ++} ++ + static void event_free(Event *event) { + if (!event) + return; +@@ -638,6 +666,7 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { + .dev_kernel = TAKE_PTR(clone), + .seqnum = seqnum, + .state = EVENT_QUEUED, ++ .retry = UEVENT_MAX_RETRY_TIMES, + }; + + if (LIST_IS_EMPTY(manager->events)) { +@@ -1314,11 +1343,13 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi + device_delete_db(worker->event->dev); + device_tag_index(worker->event->dev, NULL, false); + +- if (manager->monitor) { +- /* forward kernel event without amending it */ +- r = device_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel); +- if (r < 0) +- log_device_error_errno(worker->event->dev_kernel, r, "Failed to send back device to kernel: %m"); ++ if (event_retry(worker->event) == false) { ++ if (manager->monitor) { ++ /* forward kernel event without amending it */ ++ r = device_monitor_send_device(manager->monitor, NULL, worker->event->dev_kernel); ++ if (r < 0) ++ log_device_error_errno(worker->event->dev_kernel, r, "Failed to send back device to kernel: %m"); ++ } + } + } + +-- +2.23.0 + diff --git a/backport-analyze-add-forgotten-return-statement.patch b/backport-analyze-add-forgotten-return-statement.patch new file mode 100644 index 0000000000000000000000000000000000000000..c0c95b202057edf53fa5dc3cb3d72b4aeddb8bc0 --- /dev/null +++ b/backport-analyze-add-forgotten-return-statement.patch @@ -0,0 +1,33 @@ +From 53fd101c2144cb104d34aea8e68c7c24443107bd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 7 Oct 2022 15:52:33 +0200 +Subject: [PATCH] analyze: add forgotten return statement + +We would fail with an assert in sd_bus_message_enter_container() afterwards. + +(cherry picked from commit 5475e963c5e6ade35404384ba03caf79cb1bc2e5) +(cherry picked from commit e0ba044985ac33d5eb2fb0d09fc2ff1b2f9b73dc) +(cherry picked from commit 1316666e98accf6b8ab8cb0fb5ef73d275049a34) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/53fd101c2144cb104d34aea8e68c7c24443107bd +--- + src/analyze/analyze.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c +index 62c0ccbdfe..6452d23331 100644 +--- a/src/analyze/analyze.c ++++ b/src/analyze/analyze.c +@@ -1274,7 +1274,7 @@ static int dot(int argc, char *argv[], void *userdata) { + + r = bus_call_method(bus, bus_systemd_mgr, "ListUnits", &error, &reply, NULL); + if (r < 0) +- log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r)); ++ return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r)); + + r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)"); + if (r < 0) +-- +2.27.0 + diff --git a/backport-cgroups-agent-connect-stdin-stdout-stderr-to-dev-nul.patch b/backport-cgroups-agent-connect-stdin-stdout-stderr-to-dev-nul.patch new file mode 100644 index 0000000000000000000000000000000000000000..67decec2ebf672bb96498c522c40c23bde005e4b --- /dev/null +++ b/backport-cgroups-agent-connect-stdin-stdout-stderr-to-dev-nul.patch @@ -0,0 +1,41 @@ +From a59a7227a29a73e8e1b0d80153f258e20354c0d7 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 15 Jul 2022 11:02:40 +0200 +Subject: [PATCH] cgroups-agent: connect stdin/stdout/stderr to /dev/null + +Inspired by https://github.com/systemd/systemd/pull/24024 this is +another user mode helper, where this might be an issue. hence let's +rather be safe than sorry, and also connect stdin/stdout/stderr +explicitly with /dev/null. + +(cherry picked from commit 50492ce81589773df2d82b4fc8047778e86c6edf) +(cherry picked from commit 689487785f776815e71642f89685ff01f0bc4fde) +(cherry picked from commit d8464304f03e6644bfc6ed42e13fb3a460b9ff60) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/a59a7227a29a73e8e1b0d80153f258e20354c0d7 +--- + src/cgroups-agent/cgroups-agent.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c +index 071cba3099..9126736235 100644 +--- a/src/cgroups-agent/cgroups-agent.c ++++ b/src/cgroups-agent/cgroups-agent.c +@@ -16,6 +16,13 @@ int main(int argc, char *argv[]) { + _cleanup_close_ int fd = -1; + ssize_t n; + size_t l; ++ int r; ++ ++ r = rearrange_stdio(-1, -1, -1); ++ if (r < 0) { ++ log_error_errno(r, "Failed to connect stdin/stdout/stderr with /dev/null: %m"); ++ return EXIT_FAILURE; ++ } + + if (argc != 2) { + log_error("Incorrect number of arguments."); +-- +2.27.0 + diff --git a/backport-condition-fix-device-tree-firmware-path.patch b/backport-condition-fix-device-tree-firmware-path.patch new file mode 100644 index 0000000000000000000000000000000000000000..fbfced58c2700b73ef40b10b84a875f308132910 --- /dev/null +++ b/backport-condition-fix-device-tree-firmware-path.patch @@ -0,0 +1,41 @@ +From 2065d03c1592ff0e9027e1c06b40f55fb3e1d1ae Mon Sep 17 00:00:00 2001 +From: Daniel Braunwarth +Date: Sun, 28 Aug 2022 20:02:50 +0200 +Subject: [PATCH] condition: fix device-tree firmware path + +The path /sys/firmware/device-tree doesn't exist. This should be either +/proc/device-tree or /sys/firmware/devicetree. + +The first path is only a link. So lets use the second path. + +See https://github.com/torvalds/linux/blob/v4.14/drivers/of/base.c#L218. + +(cherry picked from commit 1037178acfd093fb10d8f5e74f3072f78afdf7e8) +(cherry picked from commit 254b77e73cb81265146de653563a7fe3f9936b56) +(cherry picked from commit ba29bb342deb4eeb55debfa7abb4ba97d50df076) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/2065d03c1592ff0e9027e1c06b40f55fb3e1d1ae +--- + src/shared/condition.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/shared/condition.c b/src/shared/condition.c +index 6645f771dd..b0520566ed 100644 +--- a/src/shared/condition.c ++++ b/src/shared/condition.c +@@ -555,9 +555,9 @@ static int condition_test_firmware(Condition *c, char **env) { + assert(c->type == CONDITION_FIRMWARE); + + if (streq(c->parameter, "device-tree")) { +- if (access("/sys/firmware/device-tree/", F_OK) < 0) { ++ if (access("/sys/firmware/devicetree/", F_OK) < 0) { + if (errno != ENOENT) +- log_debug_errno(errno, "Unexpected error when checking for /sys/firmware/device-tree/: %m"); ++ log_debug_errno(errno, "Unexpected error when checking for /sys/firmware/devicetree/: %m"); + return false; + } else + return true; +-- +2.27.0 + diff --git a/backport-coredump-Connect-stdout-stderr-to-dev-null-before-do.patch b/backport-coredump-Connect-stdout-stderr-to-dev-null-before-do.patch new file mode 100644 index 0000000000000000000000000000000000000000..f6f3bcb54299a2421929975746073802661ac327 --- /dev/null +++ b/backport-coredump-Connect-stdout-stderr-to-dev-null-before-do.patch @@ -0,0 +1,45 @@ +From 098a25754b0835ffe078b12f75a1862cf528a986 Mon Sep 17 00:00:00 2001 +From: Daan De Meyer +Date: Fri, 15 Jul 2022 01:49:25 +0200 +Subject: [PATCH] coredump: Connect stdout/stderr to /dev/null before doing + anything + +When invoked as the coredump handler by the kernel, systemd-coredump's +stdout and stderr streams are closed. This is dangerous as this means +the fd's can get reallocated, leading to hard to debug errors such as +log messages ending up being appended to a compressed coredump file. + +To avoid such issues in the future, let's bind stdout/stderr to +/dev/null so the file descriptors can't get used for anything else. + +(cherry picked from commit 1f9d2a8199c261593aa6a11df9cce5d31e23c714) +(cherry picked from commit fba50bc0fc5a69e5573ceadb5d6224f365d3c3f5) +(cherry picked from commit 3e1224d4ac3f44558c7bc3ceec2d6080afe21dc3) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/098a25754b0835ffe078b12f75a1862cf528a986 +--- + src/coredump/coredump.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c +index c6639c0100..72df958bc3 100644 +--- a/src/coredump/coredump.c ++++ b/src/coredump/coredump.c +@@ -1268,6 +1268,13 @@ static int process_kernel(int argc, char* argv[]) { + struct iovec_wrapper *iovw; + int r; + ++ /* When we're invoked by the kernel, stdout/stderr are closed which is dangerous because the fds ++ * could get reallocated. To avoid hard to debug issues, let's instead bind stdout/stderr to ++ * /dev/null. */ ++ r = rearrange_stdio(STDIN_FILENO, -1, -1); ++ if (r < 0) ++ return log_error_errno(r, "Failed to connect stdout/stderr to /dev/null: %m"); ++ + log_debug("Processing coredump received from the kernel..."); + + iovw = iovw_new(); +-- +2.27.0 + diff --git a/backport-dhcp-fix-potential-buffer-overflow.patch b/backport-dhcp-fix-potential-buffer-overflow.patch new file mode 100644 index 0000000000000000000000000000000000000000..d704e41d22ce9aeb30a7ed3ff23d8dc267f911ce --- /dev/null +++ b/backport-dhcp-fix-potential-buffer-overflow.patch @@ -0,0 +1,102 @@ +From d903e94e8ea532d2128c5c4686ae440ebf17a07d Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sat, 6 Aug 2022 13:05:59 +0900 +Subject: [PATCH] dhcp: fix potential buffer overflow + +Fixes a bug introduced by 324f818781a250b60f2fcfa74ff1c9101d2d1315. + +This also renames several macros for DHCP packet size. + +(cherry picked from commit 4473cd7f61b9eb0860f2daab81491ad2145d554b) +(cherry picked from commit 037b1a8acc50cbeeebb82f95594a4909375577c2) +(cherry picked from commit 887837a5a9425945b91488db661122459af94c52) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/d903e94e8ea532d2128c5c4686ae440ebf17a07d +--- + src/libsystemd-network/dhcp-protocol.h | 7 ++++--- + src/libsystemd-network/sd-dhcp-client.c | 11 +++++------ + src/libsystemd-network/sd-dhcp-lease.c | 6 +++--- + 3 files changed, 12 insertions(+), 12 deletions(-) + +diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h +index 11f4201ab2..686cf67e84 100644 +--- a/src/libsystemd-network/dhcp-protocol.h ++++ b/src/libsystemd-network/dhcp-protocol.h +@@ -43,9 +43,10 @@ typedef struct DHCPPacket DHCPPacket; + + #define DHCP_IP_SIZE (int32_t)(sizeof(struct iphdr)) + #define DHCP_IP_UDP_SIZE (int32_t)(sizeof(struct udphdr) + DHCP_IP_SIZE) +-#define DHCP_MESSAGE_SIZE (int32_t)(sizeof(DHCPMessage)) +-#define DHCP_DEFAULT_MIN_SIZE 576 /* the minimum internet hosts must be able to receive */ +-#define DHCP_MIN_OPTIONS_SIZE (DHCP_DEFAULT_MIN_SIZE - DHCP_IP_UDP_SIZE - DHCP_MESSAGE_SIZE) ++#define DHCP_HEADER_SIZE (int32_t)(sizeof(DHCPMessage)) ++#define DHCP_MIN_MESSAGE_SIZE 576 /* the minimum internet hosts must be able to receive, see RFC 2132 Section 9.10 */ ++#define DHCP_MIN_OPTIONS_SIZE (DHCP_MIN_MESSAGE_SIZE - DHCP_HEADER_SIZE) ++#define DHCP_MIN_PACKET_SIZE (DHCP_MIN_MESSAGE_SIZE + DHCP_IP_UDP_SIZE) + #define DHCP_MAGIC_COOKIE (uint32_t)(0x63825363) + + enum { +diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c +index 46191e58f5..b9c5748fed 100644 +--- a/src/libsystemd-network/sd-dhcp-client.c ++++ b/src/libsystemd-network/sd-dhcp-client.c +@@ -637,7 +637,7 @@ int sd_dhcp_client_set_client_port( + + int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) { + assert_return(client, -EINVAL); +- assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE); ++ assert_return(mtu >= DHCP_MIN_PACKET_SIZE, -ERANGE); + + client->mtu = mtu; + +@@ -804,7 +804,6 @@ static int client_message_init( + + _cleanup_free_ DHCPPacket *packet = NULL; + size_t optlen, optoffset, size; +- be16_t max_size; + usec_t time_now; + uint16_t secs; + int r; +@@ -955,9 +954,9 @@ static int client_message_init( + */ + /* RFC7844 section 3: + SHOULD NOT contain any other option. */ +- if (!client->anonymize && type != DHCP_RELEASE) { +- max_size = htobe16(size); +- r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0, ++ if (!client->anonymize && IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST)) { ++ be16_t max_size = htobe16(MIN(client->mtu - DHCP_IP_UDP_SIZE, (uint32_t) UINT16_MAX)); ++ r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, + SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, + 2, &max_size); + if (r < 0) +@@ -2267,7 +2266,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) { + .state = DHCP_STATE_INIT, + .ifindex = -1, + .fd = -1, +- .mtu = DHCP_DEFAULT_MIN_SIZE, ++ .mtu = DHCP_MIN_PACKET_SIZE, + .port = DHCP_PORT_CLIENT, + .anonymize = !!anonymize, + .max_attempts = UINT64_MAX, +diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c +index 89386f6809..b818020589 100644 +--- a/src/libsystemd-network/sd-dhcp-lease.c ++++ b/src/libsystemd-network/sd-dhcp-lease.c +@@ -621,9 +621,9 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void + r = lease_parse_u16(option, len, &lease->mtu, 68); + if (r < 0) + log_debug_errno(r, "Failed to parse MTU, ignoring: %m"); +- if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) { +- log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE); +- lease->mtu = DHCP_DEFAULT_MIN_SIZE; ++ if (lease->mtu < DHCP_MIN_PACKET_SIZE) { ++ log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_MIN_PACKET_SIZE); ++ lease->mtu = DHCP_MIN_PACKET_SIZE; + } + + break; +-- +2.27.0 + diff --git a/backport-dns-domain-make-each-label-nul-terminated.patch b/backport-dns-domain-make-each-label-nul-terminated.patch new file mode 100644 index 0000000000000000000000000000000000000000..11d9d70ebe712554f71c57d32a4d366bcba9bb42 --- /dev/null +++ b/backport-dns-domain-make-each-label-nul-terminated.patch @@ -0,0 +1,50 @@ +From ec5a6e5a3011f095e739fa0636c3273fe868f2cf Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sat, 11 Jun 2022 05:51:03 +0900 +Subject: [PATCH] dns-domain: make each label nul-terminated + +dns_label_unescape() does not nul-terminate the buffer if it does not +have enough space. Hence, if a lable is enough long, then strjoin() +triggers buffer-overflow. + +Fixes #23705. + +(cherry picked from commit 9db01ca5b0322bc035e1ccd6b8a0d98a26533b4a) +(cherry picked from commit 25158b294482f793f962e8ee5f34e99a01214321) +(cherry picked from commit ac4e64939d05ed81739028c0a45c3f99d2f91ba4) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/ec5a6e5a3011f095e739fa0636c3273fe868f2cf +--- + src/shared/dns-domain.c | 2 +- + src/test/test-dns-domain.c | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c +index 787bb8fec9..517fe85600 100644 +--- a/src/shared/dns-domain.c ++++ b/src/shared/dns-domain.c +@@ -1035,7 +1035,7 @@ static bool dns_service_name_label_is_valid(const char *label, size_t n) { + int dns_service_split(const char *joined, char **_name, char **_type, char **_domain) { + _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL; + const char *p = joined, *q = NULL, *d = NULL; +- char a[DNS_LABEL_MAX], b[DNS_LABEL_MAX], c[DNS_LABEL_MAX]; ++ char a[DNS_LABEL_MAX+1], b[DNS_LABEL_MAX+1], c[DNS_LABEL_MAX+1]; + int an, bn, cn, r; + unsigned x = 0; + +diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c +index 2df2380de4..10916dd057 100644 +--- a/src/test/test-dns-domain.c ++++ b/src/test/test-dns-domain.c +@@ -560,6 +560,7 @@ static void test_dns_service_split(void) { + test_dns_service_split_one("_foo._bar", NULL, "_foo._bar", ".", 0); + test_dns_service_split_one("_meh._foo._bar", "_meh", "_foo._bar", ".", 0); + test_dns_service_split_one("Wuff\\032Wuff._foo._bar.waldo.com", "Wuff Wuff", "_foo._bar", "waldo.com", 0); ++ test_dns_service_split_one("_Q._Q-------------------------------------------------------------", NULL, "_Q._Q-------------------------------------------------------------", ".", 0); + } + + static void test_dns_name_change_suffix_one(const char *name, const char *old_suffix, const char *new_suffix, int r, const char *result) { +-- +2.27.0 + diff --git a/backport-growfs-don-t-actually-resize-on-dry-run.patch b/backport-growfs-don-t-actually-resize-on-dry-run.patch new file mode 100644 index 0000000000000000000000000000000000000000..4e2b23737b9c93886f03da1b7ed476dc1a8bb614 --- /dev/null +++ b/backport-growfs-don-t-actually-resize-on-dry-run.patch @@ -0,0 +1,37 @@ +From e9a1f6237f281b4bf05386bd9b2c921ea999232f Mon Sep 17 00:00:00 2001 +From: undef +Date: Thu, 14 Jul 2022 05:53:15 +0000 +Subject: [PATCH] growfs: don't actually resize on dry-run + +This causes systemd-growfs to exit before resizing the partition when +`--dry-run` is passed. Resizing during a dry run of a change breaks the +users expectations. + +(cherry picked from commit d26c0f7243a709cfa7b8bdc87e8131746bb0e2d0) +(cherry picked from commit 00c6c62845c560ef09f845aeedabdc9027be5678) +(cherry picked from commit e39019fd1065c8e2eb078b72359c5e755b013493) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/e9a1f6237f281b4bf05386bd9b2c921ea999232f +--- + src/partition/growfs.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/partition/growfs.c b/src/partition/growfs.c +index 15c56d0584..a7e745208b 100644 +--- a/src/partition/growfs.c ++++ b/src/partition/growfs.c +@@ -241,6 +241,10 @@ static int run(int argc, char *argv[]) { + return log_error_errno(errno, "Failed to query size of \"%s\": %m", devpath); + + log_debug("Resizing \"%s\" to %"PRIu64" bytes...", arg_target, size); ++ ++ if (arg_dry_run) ++ return 0; ++ + r = resize_fs(mountfd, size, &newsize); + if (r < 0) + return log_error_errno(r, "Failed to resize \"%s\" to %"PRIu64" bytes: %m", +-- +2.27.0 + diff --git a/backport-log-don-t-attempt-to-duplicate-closed-fd.patch b/backport-log-don-t-attempt-to-duplicate-closed-fd.patch new file mode 100644 index 0000000000000000000000000000000000000000..d8cf41375a2f6f2c605e448a52c32a5eb9323982 --- /dev/null +++ b/backport-log-don-t-attempt-to-duplicate-closed-fd.patch @@ -0,0 +1,39 @@ +From 417f37c1455fe770d96559205b864766188d9866 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Fri, 2 Sep 2022 18:35:03 +0200 +Subject: [PATCH] log: don't attempt to duplicate closed fd +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +if the console fd is not open we shouldn#t try to move it out of the 0…2 +range. + +Fixes: #24535 +Alternative-for: #24537 +(cherry picked from commit f1ee066840eea748ad4074ac2bc859bb897953b9) +(cherry picked from commit e0dde8a14f8b05b88e1add1abdb68c364913346b) +(cherry picked from commit 40cedddab7e5c84c8fa4738de423971997d9aef5) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/417f37c1455fe770d96559205b864766188d9866 +--- + src/basic/log.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/basic/log.c b/src/basic/log.c +index 1d68b49963..4a1d3c0d6d 100644 +--- a/src/basic/log.c ++++ b/src/basic/log.c +@@ -1477,7 +1477,7 @@ int log_dup_console(void) { + /* Duplicate the fd we use for fd logging if it's < 3 and use the copy from now on. This call is useful + * whenever we want to continue logging through the original fd, but want to rearrange stderr. */ + +- if (console_fd >= 3) ++ if (console_fd < 0 || console_fd >= 3) + return 0; + + copy = fcntl(console_fd, F_DUPFD_CLOEXEC, 3); +-- +2.27.0 + diff --git a/backport-logind-fix-getting-property-OnExternalPower-via-D-Bu.patch b/backport-logind-fix-getting-property-OnExternalPower-via-D-Bu.patch new file mode 100644 index 0000000000000000000000000000000000000000..562f73946569b1e12264d9a5ea70dcd6d334fbe4 --- /dev/null +++ b/backport-logind-fix-getting-property-OnExternalPower-via-D-Bu.patch @@ -0,0 +1,45 @@ +From 848586f6f46e58c4960c2675102757d8c11ce046 Mon Sep 17 00:00:00 2001 +From: Michael Biebl +Date: Wed, 12 Oct 2022 11:07:57 +0200 +Subject: [PATCH] logind: fix getting property OnExternalPower via D-Bus + +The BUS_DEFINE_PROPERTY_GET_GLOBAL macro requires a value as third +argument, so we need to call manager_is_on_external_power(). Otherwise +the function pointer is interpreted as a boolean and always returns +true: + +``` +$ busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager OnExternalPower +b true +$ /lib/systemd/systemd-ac-power --verbose +no +``` + +Thanks: Helmut Grohne +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1021644 +(cherry picked from commit 63168cb517a556b2f4f175b365f5a4b4c7e85150) +(cherry picked from commit 3028e05955f1d1a43d57bbbe05321546d56c70a9) +(cherry picked from commit c622de4c9d474c2b666881ccbf60c7e2bf1fb484) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/848586f6f46e58c4960c2675102757d8c11ce046 +--- + src/login/logind-dbus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c +index b3c204f0b0..1d0cf904bc 100644 +--- a/src/login/logind-dbus.c ++++ b/src/login/logind-dbus.c +@@ -353,7 +353,7 @@ static int property_get_scheduled_shutdown( + static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_handle_action, handle_action, HandleAction); + static BUS_DEFINE_PROPERTY_GET(property_get_docked, "b", Manager, manager_is_docked_or_external_displays); + static BUS_DEFINE_PROPERTY_GET(property_get_lid_closed, "b", Manager, manager_is_lid_closed); +-static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_on_external_power, "b", manager_is_on_external_power); ++static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_on_external_power, "b", manager_is_on_external_power()); + static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_compat_user_tasks_max, "t", CGROUP_LIMIT_MAX); + static BUS_DEFINE_PROPERTY_GET_REF(property_get_hashmap_size, "t", Hashmap *, (uint64_t) hashmap_size); + +-- +2.27.0 + diff --git a/backport-mount-util-fix-error-code.patch b/backport-mount-util-fix-error-code.patch new file mode 100644 index 0000000000000000000000000000000000000000..d4dc3b491aed72559d379db2460c8c4cc9d4c7d8 --- /dev/null +++ b/backport-mount-util-fix-error-code.patch @@ -0,0 +1,52 @@ +From 561205a9c4fd0db341a93e227d249a6b6d03e2e1 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sun, 4 Sep 2022 22:34:38 +0900 +Subject: [PATCH] mount-util: fix error code + +If multiple service is starting simultaneously with a shared image, +then one of the service may fail to create a mount node: + +systemd[695]: Bind-mounting /usr/lib/os-release on /run/systemd/unit-root/run/host/os-release (MS_BIND|MS_REC "")... +systemd[696]: Bind-mounting /usr/lib/os-release on /run/systemd/unit-root/run/host/os-release (MS_BIND|MS_REC "")... +systemd[695]: Failed to mount /usr/lib/os-release (type n/a) on /run/systemd/unit-root/run/host/os-release (MS_BIND|MS_REC ""): No such file or directory +systemd[696]: Failed to mount /usr/lib/os-release (type n/a) on /run/systemd/unit-root/run/host/os-release (MS_BIND|MS_REC ""): No such file or directory +systemd[695]: Bind-mounting /usr/lib/os-release on /run/systemd/unit-root/run/host/os-release (MS_BIND|MS_REC "")... +systemd[696]: Failed to create destination mount point node '/run/systemd/unit-root/run/host/os-release': Operation not permitted +systemd[695]: Successfully mounted /usr/lib/os-release to /run/systemd/unit-root/run/host/os-release + +The function apply_one_mount() in src/core/namespace.c gracefully +handles -EEXIST from make_mount_point_inode_from_path(), but it erroneously +returned -EPERM previously. This fixes the issue. + +Fixes one of the issues in #24147, especially reported at +https://github.com/systemd/systemd/issues/24147#issuecomment-1236194671. + +(cherry picked from commit b6ca2b281eff254dce2293990360e799af806ad4) +(cherry picked from commit 24238be484e6d7633bc68c784f7b3180299a80d4) +(cherry picked from commit 260633c50b5da5522b714d7989a138ecd73febd6) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/561205a9c4fd0db341a93e227d249a6b6d03e2e1 +--- + src/shared/mount-util.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c +index 26618bb113..199ff6163d 100644 +--- a/src/shared/mount-util.c ++++ b/src/shared/mount-util.c +@@ -1089,8 +1089,10 @@ int make_mount_point_inode_from_stat(const struct stat *st, const char *dest, mo + + if (S_ISDIR(st->st_mode)) + return mkdir_label(dest, mode); ++ else if (mknod(dest, S_IFREG|(mode & ~0111), 0) < 0) ++ return -errno; + else +- return mknod(dest, S_IFREG|(mode & ~0111), 0); ++ return 0; + } + + int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t mode) { +-- +2.27.0 + diff --git a/backport-resolve-fix-heap-buffer-overflow-reported-by-ASAN-wi.patch b/backport-resolve-fix-heap-buffer-overflow-reported-by-ASAN-wi.patch new file mode 100644 index 0000000000000000000000000000000000000000..eef6c0e1301e798ba6f2d8c99746c4a4abe49a83 --- /dev/null +++ b/backport-resolve-fix-heap-buffer-overflow-reported-by-ASAN-wi.patch @@ -0,0 +1,34 @@ +From c285d500d0fe356f74f34846bc2ac0e25fe6ae42 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 8 Jul 2022 22:00:58 +0900 +Subject: [PATCH] resolve: fix heap-buffer-overflow reported by ASAN with + strict_string_checks=1 + +Fixes #23942. + +(cherry picked from commit beeab352de413e1c04de0a67ee36525fcf6e99dd) +(cherry picked from commit feb244676baa246e660b713544c2cb8766c25b34) +(cherry picked from commit 63c0ce2346cb70a2959bd539541119866223a619) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/c285d500d0fe356f74f34846bc2ac0e25fe6ae42 +--- + src/resolve/resolved-dns-packet.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c +index b37f57fe67..c4cfbf7820 100644 +--- a/src/resolve/resolved-dns-packet.c ++++ b/src/resolve/resolved-dns-packet.c +@@ -1393,7 +1393,7 @@ int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) { + if (memchr(d, 0, c)) + return -EBADMSG; + +- t = strndup(d, c); ++ t = memdup_suffix0(d, c); + if (!t) + return -ENOMEM; + +-- +2.27.0 + diff --git a/backport-resolve-mdns_packet_extract_matching_rrs-may-return-.patch b/backport-resolve-mdns_packet_extract_matching_rrs-may-return-.patch new file mode 100644 index 0000000000000000000000000000000000000000..1a9209cd923df16eea43fbf04ac4d96a7f7e68a4 --- /dev/null +++ b/backport-resolve-mdns_packet_extract_matching_rrs-may-return-.patch @@ -0,0 +1,42 @@ +From 9b1f4d855aa7b16b425545fdd888dbef918d1daa Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Mon, 4 Jul 2022 11:23:33 +0900 +Subject: [PATCH] resolve: mdns_packet_extract_matching_rrs() may return 0 + +Fixes the following assertion: + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/9b1f4d855aa7b16b425545fdd888dbef918d1daa +--- +Assertion 'r > 0' failed at src/resolve/resolved-mdns.c:180, function mdns_do_tiebreak(). Aborting. + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/9b1f4d855aa7b16b425545fdd888dbef918d1daa +--- + +(cherry picked from commit f2605af1f2e770818bbc6bad2561acdbd25a38ad) +(cherry picked from commit 0070302b3cdc1350bf7bfd5d032dbea420f4ed40) +(cherry picked from commit 30d24c8df600545d1878a868bcd409e65479af77) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/9b1f4d855aa7b16b425545fdd888dbef918d1daa +--- + src/resolve/resolved-mdns.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c +index 24241249b1..8c8ee81da1 100644 +--- a/src/resolve/resolved-mdns.c ++++ b/src/resolve/resolved-mdns.c +@@ -165,8 +165,6 @@ static int mdns_do_tiebreak(DnsResourceKey *key, DnsAnswer *answer, DnsPacket *p + if (r < 0) + return r; + +- assert(r > 0); +- + if (proposed_rrs_cmp(remote, r, our, size) > 0) + return 1; + +-- +2.27.0 + diff --git a/backport-sd-bus-do-not-pass-NULL-when-received-message-with-i.patch b/backport-sd-bus-do-not-pass-NULL-when-received-message-with-i.patch new file mode 100644 index 0000000000000000000000000000000000000000..a7d756b0c2d0bdc4cfaeaafbc89945096947a109 --- /dev/null +++ b/backport-sd-bus-do-not-pass-NULL-when-received-message-with-i.patch @@ -0,0 +1,34 @@ +From bc3d5f31bf8af840d3f4c1f66ea5d7ec6dcfcb1b Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Thu, 14 Jul 2022 10:53:54 +0900 +Subject: [PATCH] sd-bus: do not pass NULL when received message with invalid + type + +Fixes #24003. + +(cherry picked from commit 3f0dbb0f0c4e3c0013fa5fe54441ca7f969555a7) +(cherry picked from commit e56bfc8a417d1877c25b943b75cd73163246fbf2) +(cherry picked from commit a6aa5b2f7262ba67acfddd6dfa304144639a9ca4) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/bc3d5f31bf8af840d3f4c1f66ea5d7ec6dcfcb1b +--- + src/libsystemd/sd-bus/sd-bus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c +index e85a409871..7a58c560d5 100644 +--- a/src/libsystemd/sd-bus/sd-bus.c ++++ b/src/libsystemd/sd-bus/sd-bus.c +@@ -48,7 +48,7 @@ + do { \ + sd_bus_message *_mm = (m); \ + log_debug("Got message type=%s sender=%s destination=%s path=%s interface=%s member=%s cookie=%" PRIu64 " reply_cookie=%" PRIu64 " signature=%s error-name=%s error-message=%s", \ +- bus_message_type_to_string(_mm->header->type), \ ++ strna(bus_message_type_to_string(_mm->header->type)), \ + strna(sd_bus_message_get_sender(_mm)), \ + strna(sd_bus_message_get_destination(_mm)), \ + strna(sd_bus_message_get_path(_mm)), \ +-- +2.27.0 + diff --git a/backport-sd-device-monitor-actually-refuse-to-send-invalid-de.patch b/backport-sd-device-monitor-actually-refuse-to-send-invalid-de.patch new file mode 100644 index 0000000000000000000000000000000000000000..78173f3d6d781668b14c20b2e714e125bbab2a0b --- /dev/null +++ b/backport-sd-device-monitor-actually-refuse-to-send-invalid-de.patch @@ -0,0 +1,35 @@ +From b1b19cfdd22892ecc11e27206c3eab138c719e13 Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Fri, 12 Aug 2022 04:19:27 +0900 +Subject: [PATCH] sd-device-monitor: actually refuse to send invalid devices + +Fixes an issue introduced by 9e79123884a36ce095b98d1c0fe247dddf02dbec. + +(cherry picked from commit 8bb4989906a1659b0f6adfa03dc7585e294a392b) +(cherry picked from commit 6e1acfe81823b67b6b830d3ae8d0f0184eab8b2f) +(cherry picked from commit b48a17f13fb85145c17ee1dd3beb450d1dcc4b08) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/b1b19cfdd22892ecc11e27206c3eab138c719e13 +--- + src/libsystemd/sd-device/device-monitor.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/libsystemd/sd-device/device-monitor.c b/src/libsystemd/sd-device/device-monitor.c +index 2cb35951de..d7c6c69640 100644 +--- a/src/libsystemd/sd-device/device-monitor.c ++++ b/src/libsystemd/sd-device/device-monitor.c +@@ -577,8 +577,8 @@ int device_monitor_send_device( + if (r < 0) + return log_device_debug_errno(device, r, "sd-device-monitor: Failed to get device properties: %m"); + if (blen < 32) +- log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL), +- "sd-device-monitor: Length of device property nulstr is too small to contain valid device information"); ++ return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL), ++ "sd-device-monitor: Length of device property nulstr is too small to contain valid device information"); + + /* fill in versioned header */ + r = sd_device_get_subsystem(device, &val); +-- +2.27.0 + diff --git a/backport-shared-condition-avoid-nss-lookup-in-PID1.patch b/backport-shared-condition-avoid-nss-lookup-in-PID1.patch new file mode 100644 index 0000000000000000000000000000000000000000..273f8b8d7cf36006c7c3c7d1056fcc8164f5f78f --- /dev/null +++ b/backport-shared-condition-avoid-nss-lookup-in-PID1.patch @@ -0,0 +1,76 @@ +From 03101b5186a43b893165f44726f4865702005d8e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= +Date: Fri, 7 Oct 2022 17:34:53 +0200 +Subject: [PATCH] shared/condition: avoid nss lookup in PID1 + +PID 1 is not allowed to do nss lookups because this may take a long time or +even deadlock. + +While at it, the comparisons are reordered to do the "easy" comparisons which +only require a string comparison first. Delay parsing of the UID until it is +really necessary. The result is the same, because we know that "root" and +"nobody" parse as valid. + +(cherry picked from commit 734f96b8490a2c48712ff6754a84fcaeac3d53c1) +(cherry picked from commit 5da595db39e8c6b229dfe388130683ff9a32eda5) +(cherry picked from commit 4ddeea92faf69291449af95dc9ba6440ad06ec1b) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/03101b5186a43b893165f44726f4865702005d8e +--- + src/shared/condition.c | 23 ++++++++++++++--------- + 1 file changed, 14 insertions(+), 9 deletions(-) + +diff --git a/src/shared/condition.c b/src/shared/condition.c +index b0520566ed..ed7de273bf 100644 +--- a/src/shared/condition.c ++++ b/src/shared/condition.c +@@ -373,31 +373,36 @@ static int condition_test_cpus(Condition *c, char **env) { + static int condition_test_user(Condition *c, char **env) { + uid_t id; + int r; +- _cleanup_free_ char *username = NULL; +- const char *u; + + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_USER); + ++ /* Do the quick&easy comparisons first, and only parse the UID later. */ ++ if (streq(c->parameter, "root")) ++ return getuid() == 0 || geteuid() == 0; ++ if (streq(c->parameter, NOBODY_USER_NAME)) ++ return getuid() == UID_NOBODY || geteuid() == UID_NOBODY; ++ if (streq(c->parameter, "@system")) ++ return uid_is_system(getuid()) || uid_is_system(geteuid()); ++ + r = parse_uid(c->parameter, &id); + if (r >= 0) + return id == getuid() || id == geteuid(); + +- if (streq("@system", c->parameter)) +- return uid_is_system(getuid()) || uid_is_system(geteuid()); ++ if (getpid_cached() == 1) /* We already checked for "root" above, and we know that ++ * PID 1 is running as root, hence we know it cannot match. */ ++ return false; + +- username = getusername_malloc(); ++ /* getusername_malloc() may do an nss lookup, which is not allowed in PID 1. */ ++ _cleanup_free_ char *username = getusername_malloc(); + if (!username) + return -ENOMEM; + + if (streq(username, c->parameter)) + return 1; + +- if (getpid_cached() == 1) +- return streq(c->parameter, "root"); +- +- u = c->parameter; ++ const char *u = c->parameter; + r = get_user_creds(&u, &id, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING); + if (r < 0) + return 0; +-- +2.27.0 + diff --git a/backport-stat-util-replace-is_dir-is_dir_fd-by-single-is_dir_.patch b/backport-stat-util-replace-is_dir-is_dir_fd-by-single-is_dir_.patch new file mode 100644 index 0000000000000000000000000000000000000000..489088fa67b2b7bab565fda856d868ec11d1394a --- /dev/null +++ b/backport-stat-util-replace-is_dir-is_dir_fd-by-single-is_dir_.patch @@ -0,0 +1,85 @@ +From ab77d5f0c18783c273d1b3b0e8126c7019ddb1f8 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 13 Jul 2022 23:43:36 +0200 +Subject: [PATCH] stat-util: replace is_dir() + is_dir_fd() by single + is_dir_full() call + +This new call can execute both of the old operations, but also do +generic fstatat() like behaviour. + +(cherry picked from commit a586dc791ca465f4087473d2ad6794b7776aee2d) +(cherry picked from commit 9255fa3a15c5c7dea9ddb2ce5399d3b675f8368b) +(cherry picked from commit a77b81f1240ff7e0ea5d084d61875e1bdefc075d) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/ab77d5f0c18783c273d1b3b0e8126c7019ddb1f8 +--- + src/basic/stat-util.c | 20 ++++++-------------- + src/basic/stat-util.h | 9 +++++++-- + 2 files changed, 13 insertions(+), 16 deletions(-) + +diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c +index 56f7652cec..652cfd1485 100644 +--- a/src/basic/stat-util.c ++++ b/src/basic/stat-util.c +@@ -31,31 +31,23 @@ int is_symlink(const char *path) { + return !!S_ISLNK(info.st_mode); + } + +-int is_dir(const char* path, bool follow) { ++int is_dir_full(int atfd, const char* path, bool follow) { + struct stat st; + int r; + +- assert(path); ++ assert(atfd >= 0 || atfd == AT_FDCWD); ++ assert(atfd >= 0 || path); + +- if (follow) +- r = stat(path, &st); ++ if (path) ++ r = fstatat(atfd, path, &st, follow ? 0 : AT_SYMLINK_NOFOLLOW); + else +- r = lstat(path, &st); ++ r = fstat(atfd, &st); + if (r < 0) + return -errno; + + return !!S_ISDIR(st.st_mode); + } + +-int is_dir_fd(int fd) { +- struct stat st; +- +- if (fstat(fd, &st) < 0) +- return -errno; +- +- return !!S_ISDIR(st.st_mode); +-} +- + int is_device_node(const char *path) { + struct stat info; + +diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h +index a566114f7c..f9a24c8775 100644 +--- a/src/basic/stat-util.h ++++ b/src/basic/stat-util.h +@@ -13,8 +13,13 @@ + #include "missing_stat.h" + + int is_symlink(const char *path); +-int is_dir(const char *path, bool follow); +-int is_dir_fd(int fd); ++int is_dir_full(int atfd, const char *fname, bool follow); ++static inline int is_dir(const char *path, bool follow) { ++ return is_dir_full(AT_FDCWD, path, follow); ++} ++static inline int is_dir_fd(int fd) { ++ return is_dir_full(fd, NULL, false); ++} + int is_device_node(const char *path); + + int dir_is_empty_at(int dir_fd, const char *path); +-- +2.27.0 + diff --git a/backport-sysusers-add-fsync-for-passwd-24324.patch b/backport-sysusers-add-fsync-for-passwd-24324.patch new file mode 100644 index 0000000000000000000000000000000000000000..be5bec5cf1322d8b700aa069eb69b6dd1d5acf5a --- /dev/null +++ b/backport-sysusers-add-fsync-for-passwd-24324.patch @@ -0,0 +1,37 @@ +From 3982142116871b3eead4d5833d898f077e7942d4 Mon Sep 17 00:00:00 2001 +From: Avram Lubkin +Date: Tue, 16 Aug 2022 08:51:21 -0400 +Subject: [PATCH] sysusers: add fsync for passwd (#24324) + +https://github.com/systemd/systemd/pull/6636 added `fsync()` when +temporary shadow, group, and gshadow files are created, but it was +not added for passwd. As far as I can tell, this seems to have been +an oversight. I'm seeing real world issues where a blank /etc/passwd +file is being created if a machine loses power early in the boot process. + +(cherry picked from commit 19193b489841a7bcccda7122ac0849cf6efe59fd) +(cherry picked from commit 9f2f3911539c453037aecd51f875dfd75ed04113) +(cherry picked from commit 7ca021b87e92a4e775af22c04a2ab2bf404ae313) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/3982142116871b3eead4d5833d898f077e7942d4 +--- + src/sysusers/sysusers.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c +index 669efe4a1d..055eb6775e 100644 +--- a/src/sysusers/sysusers.c ++++ b/src/sysusers/sysusers.c +@@ -487,7 +487,7 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char + break; + } + +- r = fflush_and_check(passwd); ++ r = fflush_sync_and_check(passwd); + if (r < 0) + return log_debug_errno(r, "Failed to flush %s: %m", passwd_tmp); + +-- +2.27.0 + diff --git a/backport-tmpfiles-check-the-directory-we-were-supposed-to-cre.patch b/backport-tmpfiles-check-the-directory-we-were-supposed-to-cre.patch new file mode 100644 index 0000000000000000000000000000000000000000..d7b65377fbe45aad763de7d22466211a94975f16 --- /dev/null +++ b/backport-tmpfiles-check-the-directory-we-were-supposed-to-cre.patch @@ -0,0 +1,58 @@ +From 675dd1039c69ff28ce9c7e617fcede80e998b3e9 Mon Sep 17 00:00:00 2001 +From: Lennart Poettering +Date: Wed, 13 Jul 2022 23:44:45 +0200 +Subject: [PATCH] tmpfiles: check the directory we were supposed to create, not + its parent + +This current code checks the wrong directory. This was broken in +4c39d899ff00e90b7290e4985696f321d7f2726f which converted the previous +code incorrectly. + +(cherry picked from commit 92631578fff1568fa8e99f96de05baae5b258ffe) +(cherry picked from commit 625472b219a4b1ac64534d38cf6e64b51ab22bbb) +(cherry picked from commit 8b674cf43f1ba8137da3a90c67826f13c865838c) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/675dd1039c69ff28ce9c7e617fcede80e998b3e9 +--- + src/tmpfiles/tmpfiles.c | 17 +++++++---------- + 1 file changed, 7 insertions(+), 10 deletions(-) + +diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c +index 7e85c50634..1bfb1cbe16 100644 +--- a/src/tmpfiles/tmpfiles.c ++++ b/src/tmpfiles/tmpfiles.c +@@ -1666,15 +1666,12 @@ static int create_directory_or_subvolume(const char *path, mode_t mode, bool sub + r = btrfs_is_subvol(empty_to_root(arg_root)) > 0; + } + if (!r) +- /* Don't create a subvolume unless the root directory is +- * one, too. We do this under the assumption that if the +- * root directory is just a plain directory (i.e. very +- * light-weight), we shouldn't try to split it up into +- * subvolumes (i.e. more heavy-weight). Thus, chroot() +- * environments and suchlike will get a full brtfs +- * subvolume set up below their tree only if they +- * specifically set up a btrfs subvolume for the root +- * dir too. */ ++ /* Don't create a subvolume unless the root directory is one, too. We do this under ++ * the assumption that if the root directory is just a plain directory (i.e. very ++ * light-weight), we shouldn't try to split it up into subvolumes (i.e. more ++ * heavy-weight). Thus, chroot() environments and suchlike will get a full brtfs ++ * subvolume set up below their tree only if they specifically set up a btrfs ++ * subvolume for the root dir too. */ + + subvol = false; + else { +@@ -1694,7 +1691,7 @@ static int create_directory_or_subvolume(const char *path, mode_t mode, bool sub + if (!IN_SET(r, -EEXIST, -EROFS)) + return log_error_errno(r, "Failed to create directory or subvolume \"%s\": %m", path); + +- k = is_dir_fd(pfd); ++ k = is_dir_full(pfd, basename(path), /* follow= */ false); + if (k == -ENOENT && r == -EROFS) + return log_error_errno(r, "%s does not exist and cannot be created as the file system is read-only.", path); + if (k < 0) +-- +2.27.0 + diff --git a/backport-unit-file-avoid-null-in-debugging-logs.patch b/backport-unit-file-avoid-null-in-debugging-logs.patch new file mode 100644 index 0000000000000000000000000000000000000000..5abc1894aed545b62dccc3407c84702a4c3c1849 --- /dev/null +++ b/backport-unit-file-avoid-null-in-debugging-logs.patch @@ -0,0 +1,43 @@ +From e58e1472edc97ff2b234fda60fd0f977f12659fb Mon Sep 17 00:00:00 2001 +From: Yu Watanabe +Date: Sat, 23 Jul 2022 12:48:35 +0900 +Subject: [PATCH] unit-file: avoid (null) in debugging logs + +The variable `inst` was set to NULL by TAKE_PTR(). + +This fixes the following log message: +``` +systemd[1]: Unit getty@tty2.service has alias (null). +``` + +(cherry picked from commit 7c35b78a0b96085e3d634542212c5521bc2a2f21) +(cherry picked from commit 9ac0ad80fe97c22ec3dc4670e859abaae9a1f8bf) +(cherry picked from commit 0e7214c8b5c95bc378ad6b9353e944ec0fba4e21) + +Conflict:NA +Reference:https://github.com/systemd/systemd/commit/e58e1472edc97ff2b234fda60fd0f977f12659fb +--- + src/basic/unit-file.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c +index d1e997ec9f..7b0c932654 100644 +--- a/src/basic/unit-file.c ++++ b/src/basic/unit-file.c +@@ -520,12 +520,9 @@ static int add_names( + continue; + } + +- r = set_consume(*names, TAKE_PTR(inst)); +- if (r > 0) +- log_debug("Unit %s has alias %s.", unit_name, inst); ++ r = add_name(unit_name, names, inst); + } else + r = add_name(unit_name, names, *alias); +- + if (r < 0) + return r; + } +-- +2.27.0 + diff --git a/bugfix-also-stop-machine-when-a-machine-un.patch b/bugfix-also-stop-machine-when-a-machine-un.patch new file mode 100644 index 0000000000000000000000000000000000000000..39eebb28f88aa6d242ec8ad6360040dec7caf0ca --- /dev/null +++ b/bugfix-also-stop-machine-when-a-machine-un.patch @@ -0,0 +1,145 @@ +From 89110c823f246d3d2c398652999826107da446bf Mon Sep 17 00:00:00 2001 +From: yangbin +Date: Tue, 7 Apr 2020 12:01:39 +0800 +Subject: [PATCH] systemd-machined: Also stop machine when a machine unit is + active but the leader process is exited + +When a VM machine is created in a scenario as below, it will remain in systemd-machined even though it has already been terminated by libvirtd. +1. libvirtd sends a request to systemd-machined with the leader(the PID of the vm) to create a machine. +2. systemd-machined directs the request to systemd +3. systemd constructs a scope and creates cgroup for the machine. the scope unit is then added to job queue and will be started later. +4. the leader process(the PID of the vm) is terminated by libvirtd(due some reason) before the scope is started. +5. Since the scope unit is yet not started, systemd will not destroy the scope althrough it is noticed with the signal event. +6. systemd starts the scope, and now the scope and machine is in active but no leader process exist. +7. systemd-machined will not stop and destroy the machine, and remains in system until the scope is stopped by others or the OS is restarted. + +This patch fix this problem by ansering yes to stop machine in machine_check_gc +when the machine unit is active but the leader process has already exited. + +Change-Id: I80e3c32832f4ecf08b6cb149735978730ce1d1c0 +--- + src/machine/machine.c | 37 ++++++++++++++++++++++++++++++++++++- + src/machine/machined-dbus.c | 35 +++++++++++++++++++++++++++++++++++ + src/machine/machined.h | 1 + + 3 files changed, 72 insertions(+), 1 deletion(-) + +diff --git a/src/machine/machine.c b/src/machine/machine.c +index c0ed24b..b48aee6 100644 +--- a/src/machine/machine.c ++++ b/src/machine/machine.c +@@ -32,6 +32,7 @@ + #include "unit-name.h" + #include "user-util.h" + #include "util.h" ++#include "cgroup-util.h" + + Machine* machine_new(Manager *manager, MachineClass class, const char *name) { + Machine *m; +@@ -523,6 +524,40 @@ int machine_finalize(Machine *m) { + return 0; + } + ++static bool machine_validate_unit(Machine *m) { ++ int r; ++ _cleanup_free_ char *unit = NULL; ++ _cleanup_free_ char *cgroup = NULL; ++ ++ r = cg_pid_get_unit(m->leader, &unit); ++ if (!r && streq(m->unit, unit)) ++ return true; ++ ++ if (r == -ESRCH) { ++ /* the original leader may exit and be replaced with a new leader when qemu hotreplace is performed. ++ * so we don't return true here, otherwise the vm will be added to the gc list. ++ * */ ++ log_info("Machine unit is in active, but the leader process is exited. " ++ "machine: %s, leader: "PID_FMT", unit: %s.", m->name, m->leader, m->unit); ++ } else if (r) { ++ log_info_errno(r, "Can not get unit from cgroup. " ++ "machine: %s, leader: "PID_FMT", unit: %s, error: %m", m->name, m->leader, m->unit); ++ } else if (unit && !streq(m->unit, unit)) { ++ log_info("Machine unit name not match. " ++ "machine: %s, leader: "PID_FMT", machine unit: %s, real unit: %s", m->name, m->leader, m->unit, unit); ++ } ++ ++ r = manager_get_unit_cgroup_path(m->manager, m->unit, &cgroup); ++ if (!r && !isempty(cgroup) && cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) > 0) { ++ log_info("Cgroup is empty in the machine unit. " ++ "machine: %s, leader: "PID_FMT", machine unit: %s.", m->name, m->leader, m->unit); ++ /*The vm will be added to gc list only when there is no any process in the scope*/ ++ return false; ++ } ++ ++ return true; ++} ++ + bool machine_may_gc(Machine *m, bool drop_not_started) { + assert(m); + +@@ -535,7 +570,7 @@ bool machine_may_gc(Machine *m, bool drop_not_started) { + if (m->scope_job && manager_job_is_active(m->manager, m->scope_job)) + return false; + +- if (m->unit && manager_unit_is_active(m->manager, m->unit)) ++ if (m->unit && manager_unit_is_active(m->manager, m->unit) && machine_validate_unit(m)) + return false; + + return true; +diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c +index 342b18a..dcc2253 100644 +--- a/src/machine/machined-dbus.c ++++ b/src/machine/machined-dbus.c +@@ -1614,3 +1614,38 @@ int manager_add_machine(Manager *m, const char *name, Machine **_machine) { + + return 0; + } ++ ++int manager_get_unit_cgroup_path(Manager *manager, const char *unit, char **cgroup) { ++ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; ++ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; ++ _cleanup_free_ char *path = NULL; ++ const char *cgroup_path = NULL; ++ int r; ++ ++ assert(manager); ++ assert(unit); ++ ++ path = unit_dbus_path_from_name(unit); ++ if (!path) ++ return -ENOMEM; ++ ++ r = sd_bus_get_property( ++ manager->bus, ++ "org.freedesktop.systemd1", ++ path, ++ endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service", ++ "ControlGroup", ++ &error, ++ &reply, ++ "s"); ++ if (r < 0) { ++ return r; ++ } ++ ++ r = sd_bus_message_read(reply, "s", &cgroup_path); ++ if (r < 0) ++ return -EINVAL; ++ *cgroup = strdup(cgroup_path); ++ ++ return 0; ++} +diff --git a/src/machine/machined.h b/src/machine/machined.h +index 280c32b..6b8d98b 100644 +--- a/src/machine/machined.h ++++ b/src/machine/machined.h +@@ -58,6 +58,7 @@ int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_erro + int manager_unref_unit(Manager *m, const char *unit, sd_bus_error *error); + int manager_unit_is_active(Manager *manager, const char *unit); + int manager_job_is_active(Manager *manager, const char *path); ++int manager_get_unit_cgroup_path(Manager *manager, const char *unit, char **cgroup); + + #if ENABLE_NSCD + int manager_enqueue_nscd_cache_flush(Manager *m); +-- +2.23.0 + diff --git a/bugfix-for-cgroup-Swap-cgroup-v1-deletion-and-migration.patch b/bugfix-for-cgroup-Swap-cgroup-v1-deletion-and-migration.patch new file mode 100644 index 0000000000000000000000000000000000000000..f1c63b46e39d48fe8b9c5b367bf3796808b83174 --- /dev/null +++ b/bugfix-for-cgroup-Swap-cgroup-v1-deletion-and-migration.patch @@ -0,0 +1,40 @@ +From c003873099e47dccf2e57816291bd6b7de4a5790 Mon Sep 17 00:00:00 2001 +From: jiangchuangang +Date: Wed, 13 Jul 2022 21:39:06 +0800 +Subject: [PATCH] bugfix for cpuset and Delegate + +--- + src/core/cgroup.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index 0e4c94d..e887d49 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -1963,6 +1963,8 @@ static int unit_update_cgroup( + u->cgroup_enabled_mask = result_mask; + + migrate_mask = u->cgroup_realized_mask ^ target_mask; ++ if (u->type != UNIT_SLICE && FLAGS_SET(target_mask, CGROUP_MASK_CPUSET)) ++ migrate_mask |= CGROUP_MASK_CPUSET; + } + + /* Keep track that this is now realized */ +@@ -1977,9 +1979,11 @@ static int unit_update_cgroup( + * delegated units. + */ + if (cg_all_unified() == 0) { +- r = cg_migrate_v1_controllers(u->manager->cgroup_supported, migrate_mask, u->cgroup_path, migrate_callback, u); +- if (r < 0) +- log_unit_warning_errno(u, r, "Failed to migrate controller cgroups from %s, ignoring: %m", empty_to_root(u->cgroup_path)); ++ if (!unit_cgroup_delegate(u)) { ++ r = cg_migrate_v1_controllers(u->manager->cgroup_supported, migrate_mask, u->cgroup_path, migrate_callback, u); ++ if (r < 0) ++ log_unit_warning_errno(u, r, "Failed to migrate controller cgroups from %s, ignoring: %m", empty_to_root(u->cgroup_path)); ++ } + + is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE); + r = cg_trim_v1_controllers(u->manager->cgroup_supported, ~target_mask, u->cgroup_path, !is_root_slice); +-- +2.33.0 + diff --git a/core-add-OptionalLog-to-allow-users-change-log-level.patch b/core-add-OptionalLog-to-allow-users-change-log-level.patch new file mode 100644 index 0000000000000000000000000000000000000000..4a8870561177adfcce659e044c3e8c2917fd2aa1 --- /dev/null +++ b/core-add-OptionalLog-to-allow-users-change-log-level.patch @@ -0,0 +1,144 @@ +From 637310cf1903f9072a391074a65855fc1c41ae2b Mon Sep 17 00:00:00 2001 +From: licunlong +Date: Fri, 15 Apr 2022 09:28:15 +0800 +Subject: [PATCH] core: add OptionalLog to allow users change log level. +This adds log_optional* log_unit_optional* to log messages in LOG_INFO +or LOG_DEBUG. Set "OptionalLog=yes" to log in LOG_INFO. Defaults to no. + +--- + src/basic/log.h | 2 ++ + src/core/dbus-manager.c | 1 + + src/core/main.c | 4 ++++ + src/core/manager.h | 1 + + src/core/mount.c | 2 +- + src/core/system.conf.in | 1 + + src/core/unit.h | 2 ++ + 7 files changed, 12 insertions(+), 1 deletion(-) + +diff --git a/src/basic/log.h b/src/basic/log.h +index 625be22..6ff143f 100644 +--- a/src/basic/log.h ++++ b/src/basic/log.h +@@ -239,6 +239,7 @@ int log_emergency_level(void); + #define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__) + #define log_error(...) log_full(LOG_ERR, __VA_ARGS__) + #define log_emergency(...) log_full(log_emergency_level(), __VA_ARGS__) ++#define log_optional(use_info, ...) log_full(((use_info) ? LOG_INFO : LOG_DEBUG), __VA_ARGS__) + + /* Logging triggered by an errno-like error */ + #define log_debug_errno(error, ...) log_full_errno(LOG_DEBUG, error, __VA_ARGS__) +@@ -235,6 +236,7 @@ int log_emergency_level(void); + #define log_warning_errno(error, ...) log_full_errno(LOG_WARNING, error, __VA_ARGS__) + #define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__) + #define log_emergency_errno(error, ...) log_full_errno(log_emergency_level(), error, __VA_ARGS__) ++#define log_optional_errno(error, use_info, ...) log_full_errno(((use_info) ? LOG_INFO : LOG_DEBUG), error, __VA_ARGS__) + + /* This logs at the specified level the first time it is called, and then + * logs at debug. If the specified level is debug, this logs only the first +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 184df9d..acf782d 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -2656,6 +2656,7 @@ const sd_bus_vtable bus_manager_vtable[] = { + BUS_PROPERTY_DUAL_TIMESTAMP("InitRDUnitsLoadFinishTimestamp", offsetof(Manager, timestamps[MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_FINISH]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_WRITABLE_PROPERTY("LogLevel", "s", bus_property_get_log_level, property_set_log_level, 0, 0), + SD_BUS_WRITABLE_PROPERTY("LogTarget", "s", bus_property_get_log_target, property_set_log_target, 0, 0), ++ SD_BUS_PROPERTY("OptionalLog", "b", bus_property_get_bool, offsetof(Manager, optional_log), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NNames", "u", property_get_hashmap_size, offsetof(Manager, units), 0), + SD_BUS_PROPERTY("NFailedUnits", "u", property_get_set_size, offsetof(Manager, failed_units), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("NJobs", "u", property_get_hashmap_size, offsetof(Manager, jobs), 0), +diff --git a/src/core/main.c b/src/core/main.c +index 2a6b9b8..15a3cb9 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -110,6 +110,7 @@ static const char *arg_bus_introspect = NULL; + * defaults are assigned in reset_arguments() below. */ + static char *arg_default_unit; + static bool arg_system; ++static bool arg_optional_log; + static bool arg_dump_core; + static int arg_crash_chvt; + static bool arg_crash_shell; +@@ -641,6 +642,7 @@ static int parse_config_file(void) { + { "Manager", "LogColor", config_parse_color, 0, NULL }, + { "Manager", "LogLocation", config_parse_location, 0, NULL }, + { "Manager", "LogTime", config_parse_time, 0, NULL }, ++ { "Manager", "OptionalLog", config_parse_bool, 0, &arg_optional_log }, + { "Manager", "DumpCore", config_parse_bool, 0, &arg_dump_core }, + { "Manager", "CrashChVT", /* legacy */ config_parse_crash_chvt, 0, &arg_crash_chvt }, + { "Manager", "CrashChangeVT", config_parse_crash_chvt, 0, &arg_crash_chvt }, +@@ -748,6 +750,7 @@ static void set_manager_defaults(Manager *m) { + * affect the manager itself, but are just what newly allocated units will have set if they haven't set + * anything else. (Also see set_manager_settings() for the settings that affect the manager's own behaviour) */ + ++ m->optional_log = arg_optional_log; + m->default_timer_accuracy_usec = arg_default_timer_accuracy_usec; + m->default_std_output = arg_default_std_output; + m->default_std_error = arg_default_std_error; +@@ -2327,6 +2330,7 @@ static void reset_arguments(void) { + + /* arg_system — ignore */ + ++ arg_optional_log = false; + arg_dump_core = true; + arg_crash_chvt = -1; + arg_crash_shell = false; +diff --git a/src/core/manager.h b/src/core/manager.h +index c20abd5..543f30c 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -378,6 +378,7 @@ struct Manager { + LogTarget original_log_target; + bool log_level_overridden; + bool log_target_overridden; ++ bool optional_log; + + struct rlimit *rlimit[_RLIMIT_MAX]; + +diff --git a/src/core/mount.c b/src/core/mount.c +index 9d676c2..dba8566 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -674,7 +674,7 @@ static void mount_set_state(Mount *m, MountState state) { + } + + if (state != old_state) +- log_unit_debug(UNIT(m), "Changed %s -> %s", mount_state_to_string(old_state), mount_state_to_string(state)); ++ log_unit_optional(UNIT(m), UNIT(m)->manager->optional_log, "Changed %s -> %s", mount_state_to_string(old_state), mount_state_to_string(state)); + + unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state], + m->reload_result == MOUNT_SUCCESS ? 0 : UNIT_NOTIFY_RELOAD_FAILURE); +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index d6cc751..f521f3e 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -20,6 +20,7 @@ + #LogColor=yes + #LogLocation=no + #LogTime=no ++#OptionalLog=no + #DumpCore=yes + #ShowStatus=yes + #CrashChangeVT=no +diff --git a/src/core/unit.h b/src/core/unit.h +index 759104f..02f4cb2 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -990,12 +990,14 @@ int unit_thaw_vtable_common(Unit *u); + #define log_unit_notice(unit, ...) log_unit_full(unit, LOG_NOTICE, __VA_ARGS__) + #define log_unit_warning(unit, ...) log_unit_full(unit, LOG_WARNING, __VA_ARGS__) + #define log_unit_error(unit, ...) log_unit_full(unit, LOG_ERR, __VA_ARGS__) ++#define log_unit_optional(unit, use_info, ...) log_unit_full(unit, ((use_info) ? LOG_INFO : LOG_DEBUG), __VA_ARGS__) + + #define log_unit_debug_errno(unit, error, ...) log_unit_full_errno(unit, LOG_DEBUG, error, __VA_ARGS__) + #define log_unit_info_errno(unit, error, ...) log_unit_full_errno(unit, LOG_INFO, error, __VA_ARGS__) + #define log_unit_notice_errno(unit, error, ...) log_unit_full_errno(unit, LOG_NOTICE, error, __VA_ARGS__) + #define log_unit_warning_errno(unit, error, ...) log_unit_full_errno(unit, LOG_WARNING, error, __VA_ARGS__) + #define log_unit_error_errno(unit, error, ...) log_unit_full_errno(unit, LOG_ERR, error, __VA_ARGS__) ++#define log_unit_optional_errno(unit, use_info, error, ...) log_unit_full_errno(unit, ((use_info) ? LOG_INFO : LOG_DEBUG), error, __VA_ARGS__) + + #define log_unit_struct_errno(unit, level, error, ...) \ + ({ \ +-- +2.23.0 + diff --git a/core-add-invalidate-cgroup-config.patch b/core-add-invalidate-cgroup-config.patch new file mode 100644 index 0000000000000000000000000000000000000000..3b122faaae196d75faa2cd23510861f2e56d9f47 --- /dev/null +++ b/core-add-invalidate-cgroup-config.patch @@ -0,0 +1,117 @@ +From d56b3978bbcd28246b3e3ce3f8c958ac95785dd7 Mon Sep 17 00:00:00 2001 +From: fangxiuning +Date: Wed, 22 Apr 2020 11:55:18 +0800 +Subject: + After systemd 239 version, a new feature is added to cgroups. +The processes started by users default to the cgroup group belonging +to user.slice, and the processes started by the system default to +system.slice. This is the direction of github systemd evolution. +However, there are still a large number of operations downstream +that systemd does not perceive to modify the cgroup group, +such as directly echo the process number to system.slice. + +For example: +1. sleep 1000 & +2. echo sleep pid > /sys/fs/cgroup/memory/system.slice/task +3. systemctl daemon-reload +4. cat /proc/sleep pid/cgroup +this kind of operation, systemd is not aware of it. +When systemctl disable service or systemctl daemon-reload operation +is executed, systemd will re-attach each process to its original +Under the group(user.slice). + +--- + src/core/main.c | 4 ++++ + src/core/manager.c | 1 + + src/core/manager.h | 1 + + src/core/system.conf.in | 1 + + src/core/unit-serialize.c | 2 +- + 5 files changed, 8 insertions(+), 1 deletion(-) + +diff --git a/src/core/main.c b/src/core/main.c +index 09075ef..a39d7d3 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -154,6 +154,7 @@ static bool arg_default_cpuset_accounting; + static bool arg_default_freezer_accounting; + static bool arg_default_tasks_accounting; + static TasksMax arg_default_tasks_max; ++static bool arg_default_invalidate_cgroup; + static sd_id128_t arg_machine_id; + static EmergencyAction arg_cad_burst_action; + static OOMPolicy arg_default_oom_policy; +@@ -704,6 +705,7 @@ static int parse_config_file(void) { + { "Manager", "DefaultFreezerAccounting", config_parse_bool, 0, &arg_default_freezer_accounting }, + { "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting }, + { "Manager", "DefaultTasksMax", config_parse_tasks_max, 0, &arg_default_tasks_max }, ++ { "Manager", "DefaultInvalidateCgroup", config_parse_bool, 0, &arg_default_invalidate_cgroup }, + { "Manager", "CtrlAltDelBurstAction", config_parse_emergency_action, 0, &arg_cad_burst_action }, + { "Manager", "DefaultOOMPolicy", config_parse_oom_policy, 0, &arg_default_oom_policy }, + { "Manager", "DefaultUnitSlice", config_parse_string, 0, &arg_default_unit_slice }, +@@ -780,6 +782,7 @@ static void set_manager_defaults(Manager *m) { + m->default_freezer_accounting = arg_default_freezer_accounting; + m->default_tasks_accounting = arg_default_tasks_accounting; + m->default_tasks_max = arg_default_tasks_max; ++ m->default_invalidate_cgroup = arg_default_invalidate_cgroup; + m->default_oom_policy = arg_default_oom_policy; + + (void) manager_set_default_rlimits(m, arg_default_rlimit); +@@ -2401,6 +2404,7 @@ static void reset_arguments(void) { + arg_default_freezer_accounting = false; + arg_default_tasks_accounting = true; + arg_default_tasks_max = DEFAULT_TASKS_MAX; ++ arg_default_invalidate_cgroup = true; + arg_machine_id = (sd_id128_t) {}; + arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE; + arg_default_oom_policy = OOM_STOP; +diff --git a/src/core/manager.c b/src/core/manager.c +index 29ef96b..740bad5 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -780,6 +780,7 @@ int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager + .default_cpuset_accounting = false, + .default_tasks_accounting = true, + .default_tasks_max = TASKS_MAX_UNSET, ++ .default_invalidate_cgroup = true, + .default_timeout_start_usec = DEFAULT_TIMEOUT_USEC, + .default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC, + .default_restart_usec = DEFAULT_RESTART_USEC, +diff --git a/src/core/manager.h b/src/core/manager.h +index 9a38737..485bab1 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -371,6 +371,7 @@ struct Manager { + + TasksMax default_tasks_max; + usec_t default_timer_accuracy_usec; ++ bool default_invalidate_cgroup; + + OOMPolicy default_oom_policy; + +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index f521f3e..c1fd308 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -74,5 +74,6 @@ DefaultLimitMEMLOCK=64M + #DefaultLimitNICE= + #DefaultLimitRTPRIO= + #DefaultLimitRTTIME= ++#DefaultInvalidateCgroup=yes + #DefaultOOMPolicy=stop + DefaultDFXReboot=yes +diff --git a/src/core/unit-serialize.c b/src/core/unit-serialize.c +index 689a536..f3b3e70 100644 +--- a/src/core/unit-serialize.c ++++ b/src/core/unit-serialize.c +@@ -526,7 +526,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { + /* Let's make sure that everything that is deserialized also gets any potential new cgroup settings + * applied after we are done. For that we invalidate anything already realized, so that we can + * realize it again. */ +- if (u->cgroup_realized) { ++ if (u->cgroup_realized && u->manager->default_invalidate_cgroup) { + unit_invalidate_cgroup(u, _CGROUP_MASK_ALL); + unit_invalidate_cgroup_bpf(u); + } +-- +2.27.0 + diff --git a/core-cgroup-support-cpuset.patch b/core-cgroup-support-cpuset.patch new file mode 100644 index 0000000000000000000000000000000000000000..79029945f388c0b0adff76d96ae3f87d60666c1c --- /dev/null +++ b/core-cgroup-support-cpuset.patch @@ -0,0 +1,872 @@ +From 2ea8175b3d8ec118fa0f42392485ce0f4308456a Mon Sep 17 00:00:00 2001 +From: licunlong +Date: Thu, 6 May 2021 09:38:54 +0800 +Subject: [PATCH] core-cgroup: support cpuset + +This patch add support for cpuset subsystem. +--- + src/basic/cgroup-util.c | 3 +- + src/basic/cgroup-util.h | 10 ++- + src/basic/string-util.c | 42 +++++++++ + src/basic/string-util.h | 2 + + src/core/cgroup.c | 86 ++++++++++++++++--- + src/core/cgroup.h | 10 ++- + src/core/dbus-cgroup.c | 52 +++++++++-- + src/core/dbus-manager.c | 1 + + src/core/load-fragment-gperf.gperf.in | 5 ++ + src/core/load-fragment.c | 73 +++++++++++++++- + src/core/load-fragment.h | 1 + + src/core/main.c | 4 + + src/core/manager.c | 1 + + src/core/manager.h | 1 + + src/core/system.conf.in | 1 + + src/core/unit.c | 1 + + src/shared/bus-unit-util.c | 15 +++- + src/shared/cpu-set-util.c | 1 + + src/test/test-cgroup-mask.c | 5 +- + .../fuzz-unit-file/directives-all.service | 5 ++ + test/fuzz/fuzz-unit-file/directives.mount | 5 ++ + test/fuzz/fuzz-unit-file/directives.scope | 5 ++ + test/fuzz/fuzz-unit-file/directives.service | 5 ++ + test/fuzz/fuzz-unit-file/directives.slice | 5 ++ + test/fuzz/fuzz-unit-file/directives.socket | 5 ++ + test/fuzz/fuzz-unit-file/directives.swap | 5 ++ + 26 files changed, 319 insertions(+), 30 deletions(-) + +diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c +index 1ff6160..01a4181 100644 +--- a/src/basic/cgroup-util.c ++++ b/src/basic/cgroup-util.c +@@ -2155,12 +2155,13 @@ bool fd_is_cgroup_fs(int fd) { + static const char *const cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = { + [CGROUP_CONTROLLER_CPU] = "cpu", + [CGROUP_CONTROLLER_CPUACCT] = "cpuacct", +- [CGROUP_CONTROLLER_CPUSET] = "cpuset", ++ [CGROUP_CONTROLLER_CPUSET2] = "cpuset2", + [CGROUP_CONTROLLER_IO] = "io", + [CGROUP_CONTROLLER_BLKIO] = "blkio", + [CGROUP_CONTROLLER_MEMORY] = "memory", + [CGROUP_CONTROLLER_DEVICES] = "devices", + [CGROUP_CONTROLLER_PIDS] = "pids", ++ [CGROUP_CONTROLLER_CPUSET] = "cpuset", + [CGROUP_CONTROLLER_BPF_FIREWALL] = "bpf-firewall", + [CGROUP_CONTROLLER_BPF_DEVICES] = "bpf-devices", + [CGROUP_CONTROLLER_BPF_FOREIGN] = "bpf-foreign", +diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h +index ce2f4c6..06a23ff 100644 +--- a/src/basic/cgroup-util.h ++++ b/src/basic/cgroup-util.h +@@ -20,12 +20,13 @@ typedef enum CGroupController { + /* Original cgroup controllers */ + CGROUP_CONTROLLER_CPU, + CGROUP_CONTROLLER_CPUACCT, /* v1 only */ +- CGROUP_CONTROLLER_CPUSET, /* v2 only */ ++ CGROUP_CONTROLLER_CPUSET2, /* v2 only */ + CGROUP_CONTROLLER_IO, /* v2 only */ + CGROUP_CONTROLLER_BLKIO, /* v1 only */ + CGROUP_CONTROLLER_MEMORY, + CGROUP_CONTROLLER_DEVICES, /* v1 only */ + CGROUP_CONTROLLER_PIDS, ++ CGROUP_CONTROLLER_CPUSET, + + /* BPF-based pseudo-controllers, v2 only */ + CGROUP_CONTROLLER_BPF_FIREWALL, +@@ -43,22 +44,23 @@ typedef enum CGroupController { + typedef enum CGroupMask { + CGROUP_MASK_CPU = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPU), + CGROUP_MASK_CPUACCT = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUACCT), +- CGROUP_MASK_CPUSET = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET), ++ CGROUP_MASK_CPUSET2 = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET2), + CGROUP_MASK_IO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_IO), + CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO), + CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY), + CGROUP_MASK_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICES), + CGROUP_MASK_PIDS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_PIDS), ++ CGROUP_MASK_CPUSET = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET), + CGROUP_MASK_BPF_FIREWALL = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_FIREWALL), + CGROUP_MASK_BPF_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_DEVICES), + CGROUP_MASK_BPF_FOREIGN = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_FOREIGN), + CGROUP_MASK_BPF_SOCKET_BIND = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_SOCKET_BIND), + + /* All real cgroup v1 controllers */ +- CGROUP_MASK_V1 = CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT|CGROUP_MASK_BLKIO|CGROUP_MASK_MEMORY|CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS, ++ CGROUP_MASK_V1 = CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT|CGROUP_MASK_BLKIO|CGROUP_MASK_MEMORY|CGROUP_MASK_CPUSET|CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS, + + /* All real cgroup v2 controllers */ +- CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_CPUSET|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS, ++ CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_CPUSET2|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS, + + /* All cgroup v2 BPF pseudo-controllers */ + CGROUP_MASK_BPF = CGROUP_MASK_BPF_FIREWALL|CGROUP_MASK_BPF_DEVICES|CGROUP_MASK_BPF_FOREIGN|CGROUP_MASK_BPF_SOCKET_BIND, +diff --git a/src/basic/string-util.c b/src/basic/string-util.c +index a645958..45f358b 100644 +--- a/src/basic/string-util.c ++++ b/src/basic/string-util.c +@@ -1146,3 +1146,45 @@ int string_contains_word_strv(const char *string, const char *separators, char * + *ret_word = found; + return !!found; + } ++ ++int string_isvalid_interval(const char *instr) ++{ ++ const char *pstr = instr; /* tmp */ ++ const char *pstr_front = instr; /* front char */ ++ const char *pstr_behind = instr; /* behind char */ ++ ++ if (isempty(instr)) ++ { ++ return 1; ++ } ++ ++ while (*pstr != '\0') ++ { ++ /* behind */ ++ pstr_behind = pstr + 1; ++ ++ /* 0-3,4,6,7-10 */ ++ if (((*pstr < '0') || (*pstr > '9')) && ++ (*pstr != '-') && ++ (*pstr != ',')) ++ { ++ return 2; ++ } ++ ++ /* - , must is a num */ ++ if (('-' == *pstr) || (',' == *pstr)) ++ { ++ if ((*pstr_front < '0') || (*pstr_front > '9') || ++ (*pstr_behind < '0') || (*pstr_behind > '9')) ++ { ++ return 3; ++ } ++ } ++ ++ /* front */ ++ pstr_front = pstr; ++ pstr++; ++ } ++ ++ return 0; ++} +diff --git a/src/basic/string-util.h b/src/basic/string-util.h +index 9155e50..338dcd5 100644 +--- a/src/basic/string-util.h ++++ b/src/basic/string-util.h +@@ -242,3 +242,5 @@ int string_contains_word_strv(const char *string, const char *separators, char * + static inline int string_contains_word(const char *string, const char *separators, const char *word) { + return string_contains_word_strv(string, separators, STRV_MAKE(word), NULL); + } ++ ++int string_isvalid_interval(const char *instr); +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index de1d5f4..2c2d1b0 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -246,8 +246,14 @@ void cgroup_context_done(CGroupContext *c) { + while (c->bpf_foreign_programs) + cgroup_context_remove_bpf_foreign_program(c, c->bpf_foreign_programs); + +- cpu_set_reset(&c->cpuset_cpus); +- cpu_set_reset(&c->cpuset_mems); ++ if (c->cpuset_cpus) ++ c->cpuset_cpus = mfree(c->cpuset_cpus); ++ ++ if (c->cpuset_mems) ++ c->cpuset_mems = mfree(c->cpuset_mems); ++ ++ cpu_set_reset(&c->cpuset_cpus2); ++ cpu_set_reset(&c->cpuset_mems2); + } + + static int unit_get_kernel_memory_limit(Unit *u, const char *file, uint64_t *ret) { +@@ -382,7 +388,7 @@ static char *format_cgroup_memory_limit_comparison(char *buf, size_t l, Unit *u, + } + + void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { +- _cleanup_free_ char *disable_controllers_str = NULL, *cpuset_cpus = NULL, *cpuset_mems = NULL; ++ _cleanup_free_ char *disable_controllers_str = NULL, *cpuset_cpus2 = NULL, *cpuset_mems2 = NULL; + CGroupIODeviceLimit *il; + CGroupIODeviceWeight *iw; + CGroupIODeviceLatency *l; +@@ -412,14 +418,15 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { + + (void) cg_mask_to_string(c->disable_controllers, &disable_controllers_str); + +- cpuset_cpus = cpu_set_to_range_string(&c->cpuset_cpus); +- cpuset_mems = cpu_set_to_range_string(&c->cpuset_mems); ++ cpuset_cpus2 = cpu_set_to_range_string(&c->cpuset_cpus2); ++ cpuset_mems2 = cpu_set_to_range_string(&c->cpuset_mems2); + + fprintf(f, + "%sCPUAccounting: %s\n" + "%sIOAccounting: %s\n" + "%sBlockIOAccounting: %s\n" + "%sMemoryAccounting: %s\n" ++ "%sCPUSetAccounting: %s\n" + "%sTasksAccounting: %s\n" + "%sIPAccounting: %s\n" + "%sCPUWeight: %" PRIu64 "\n" +@@ -442,6 +449,10 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { + "%sMemoryMax: %" PRIu64 "%s\n" + "%sMemorySwapMax: %" PRIu64 "%s\n" + "%sMemoryLimit: %" PRIu64 "\n" ++ "%sCPUSetCpus=%s\n" ++ "%sCPUSetMems=%s\n" ++ "%sCPUSetCloneChildren=%s\n" ++ "%sCPUSetMemMigrate=%s\n" + "%sTasksMax: %" PRIu64 "\n" + "%sDevicePolicy: %s\n" + "%sDisableControllers: %s\n" +@@ -454,6 +465,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { + prefix, yes_no(c->io_accounting), + prefix, yes_no(c->blockio_accounting), + prefix, yes_no(c->memory_accounting), ++ prefix, yes_no(c->cpuset_accounting), + prefix, yes_no(c->tasks_accounting), + prefix, yes_no(c->ip_accounting), + prefix, c->cpu_weight, +@@ -462,8 +474,8 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { + prefix, c->startup_cpu_shares, + prefix, format_timespan(q, sizeof(q), c->cpu_quota_per_sec_usec, 1), + prefix, format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1), +- prefix, strempty(cpuset_cpus), +- prefix, strempty(cpuset_mems), ++ prefix, strempty(cpuset_cpus2), ++ prefix, strempty(cpuset_mems2), + prefix, c->io_weight, + prefix, c->startup_io_weight, + prefix, c->blockio_weight, +@@ -476,6 +488,10 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { + prefix, c->memory_max, format_cgroup_memory_limit_comparison(cdd, sizeof(cdd), u, "MemoryMax"), + prefix, c->memory_swap_max, format_cgroup_memory_limit_comparison(cde, sizeof(cde), u, "MemorySwapMax"), + prefix, c->memory_limit, ++ prefix, c->cpuset_cpus, ++ prefix, c->cpuset_mems, ++ prefix, yes_no(c->cpuset_clone_children), ++ prefix, yes_no(c->cpuset_memory_migrate), + prefix, tasks_max_resolve(&c->tasks_max), + prefix, cgroup_device_policy_to_string(c->device_policy), + prefix, strempty(disable_controllers_str), +@@ -1277,9 +1293,9 @@ static void cgroup_context_apply( + } + } + +- if ((apply_mask & CGROUP_MASK_CPUSET) && !is_local_root) { +- cgroup_apply_unified_cpuset(u, &c->cpuset_cpus, "cpuset.cpus"); +- cgroup_apply_unified_cpuset(u, &c->cpuset_mems, "cpuset.mems"); ++ if ((apply_mask & CGROUP_MASK_CPUSET2) && !is_local_root) { ++ cgroup_apply_unified_cpuset(u, &c->cpuset_cpus2, "cpuset.cpus"); ++ cgroup_apply_unified_cpuset(u, &c->cpuset_mems2, "cpuset.mems"); + } + + /* The 'io' controller attributes are not exported on the host's root cgroup (being a pure cgroup v2 +@@ -1477,6 +1493,45 @@ static void cgroup_context_apply( + } + } + ++ if ((apply_mask & CGROUP_MASK_CPUSET) && !is_local_root) { ++ (void) set_attribute_and_warn(u, "cpuset", "cgroup.clone_children", one_zero(c->cpuset_clone_children)); ++ (void) set_attribute_and_warn(u, "cpuset", "cpuset.memory_migrate", one_zero(c->cpuset_memory_migrate)); ++ if (c->cpuset_cpus) { ++ if (streq(c->cpuset_cpus, "all")) { ++ _cleanup_free_ char *str_cpuset_cpus = NULL; ++ _cleanup_free_ char *cg_root_path_cpus = NULL; ++ r = cg_get_root_path(&cg_root_path_cpus); ++ if (r < 0) ++ log_info_errno(r, "Failed to determine root cgroup, ignoring cgroup cpuset cpus: %m"); ++ if (cg_root_path_cpus) { ++ r = cg_get_attribute("cpuset", cg_root_path_cpus, "cpuset.cpus", &str_cpuset_cpus); ++ if (r < 0) ++ log_error("cgroup context apply: cg get attribute is error(%d), path=%s.", r, cg_root_path_cpus); ++ if (str_cpuset_cpus) ++ (void) set_attribute_and_warn(u, "cpuset", "cpuset.cpus", str_cpuset_cpus); ++ } ++ } else ++ (void) set_attribute_and_warn(u, "cpuset", "cpuset.cpus", c->cpuset_cpus); ++ } ++ if (c->cpuset_mems) { ++ if (streq(c->cpuset_mems, "all")) { ++ _cleanup_free_ char *str_cpuset_mems = NULL; ++ _cleanup_free_ char *cg_root_path_mems = NULL; ++ r = cg_get_root_path(&cg_root_path_mems); ++ if (r < 0) ++ log_info_errno(r, "Failed to determine root cgroup, ignoring cgroup cpuset mems: %m"); ++ if (cg_root_path_mems) { ++ r = cg_get_attribute("cpuset", cg_root_path_mems, "cpuset.mems", &str_cpuset_mems); ++ if (r < 0) ++ log_error("cgroup context apply: cg get attribute is error(%d), path=%s.", r, cg_root_path_mems); ++ if (str_cpuset_mems) ++ (void) set_attribute_and_warn(u, "cpuset", "cpuset.mems", str_cpuset_mems); ++ } ++ } else ++ (void) set_attribute_and_warn(u, "cpuset", "cpuset.mems", c->cpuset_mems); ++ } ++ } ++ + /* On cgroup v2 we can apply BPF everywhere. On cgroup v1 we apply it everywhere except for the root of + * containers, where we leave this to the manager */ + if ((apply_mask & (CGROUP_MASK_DEVICES | CGROUP_MASK_BPF_DEVICES)) && +@@ -1603,8 +1658,8 @@ static CGroupMask unit_get_cgroup_mask(Unit *u) { + c->cpu_quota_per_sec_usec != USEC_INFINITY) + mask |= CGROUP_MASK_CPU; + +- if (c->cpuset_cpus.set || c->cpuset_mems.set) +- mask |= CGROUP_MASK_CPUSET; ++ if (c->cpuset_cpus2.set || c->cpuset_mems2.set) ++ mask |= CGROUP_MASK_CPUSET2; + + if (cgroup_context_has_io_config(c) || cgroup_context_has_blockio_config(c)) + mask |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO; +@@ -1614,6 +1669,11 @@ static CGroupMask unit_get_cgroup_mask(Unit *u) { + unit_has_unified_memory_config(u)) + mask |= CGROUP_MASK_MEMORY; + ++ if (c->cpuset_accounting || ++ c->cpuset_cpus || ++ c->cpuset_mems) ++ mask |= CGROUP_MASK_CPUSET; ++ + if (c->device_allow || + c->device_policy != CGROUP_DEVICE_POLICY_AUTO) + mask |= CGROUP_MASK_DEVICES | CGROUP_MASK_BPF_DEVICES; +@@ -3984,7 +4044,7 @@ int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name) { + if (!u->cgroup_path) + return -ENODATA; + +- if ((u->cgroup_realized_mask & CGROUP_MASK_CPUSET) == 0) ++ if ((u->cgroup_realized_mask & CGROUP_MASK_CPUSET2) == 0) + return -ENODATA; + + r = cg_all_unified(); +diff --git a/src/core/cgroup.h b/src/core/cgroup.h +index ea92936..a8a4726 100644 +--- a/src/core/cgroup.h ++++ b/src/core/cgroup.h +@@ -115,6 +115,7 @@ struct CGroupContext { + bool io_accounting; + bool blockio_accounting; + bool memory_accounting; ++ bool cpuset_accounting; + bool tasks_accounting; + bool ip_accounting; + +@@ -131,8 +132,8 @@ struct CGroupContext { + usec_t cpu_quota_per_sec_usec; + usec_t cpu_quota_period_usec; + +- CPUSet cpuset_cpus; +- CPUSet cpuset_mems; ++ CPUSet cpuset_cpus2; ++ CPUSet cpuset_mems2; + + uint64_t io_weight; + uint64_t startup_io_weight; +@@ -148,6 +149,11 @@ struct CGroupContext { + uint64_t memory_max; + uint64_t memory_swap_max; + ++ char *cpuset_cpus; ++ char *cpuset_mems; ++ bool cpuset_clone_children; ++ bool cpuset_memory_migrate; ++ + bool default_memory_min_set; + bool default_memory_low_set; + bool memory_min_set; +diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c +index 84c3caf..0cdc98c 100644 +--- a/src/core/dbus-cgroup.c ++++ b/src/core/dbus-cgroup.c +@@ -414,8 +414,8 @@ const sd_bus_vtable bus_cgroup_vtable[] = { + SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0), + SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0), + SD_BUS_PROPERTY("CPUQuotaPeriodUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_period_usec), 0), +- SD_BUS_PROPERTY("AllowedCPUs", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_cpus), 0), +- SD_BUS_PROPERTY("AllowedMemoryNodes", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_mems), 0), ++ SD_BUS_PROPERTY("AllowedCPUs", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_cpus2), 0), ++ SD_BUS_PROPERTY("AllowedMemoryNodes", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_mems2), 0), + SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0), + SD_BUS_PROPERTY("IOWeight", "t", NULL, offsetof(CGroupContext, io_weight), 0), + SD_BUS_PROPERTY("StartupIOWeight", "t", NULL, offsetof(CGroupContext, startup_io_weight), 0), +@@ -440,6 +440,11 @@ const sd_bus_vtable bus_cgroup_vtable[] = { + SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0), + SD_BUS_PROPERTY("MemorySwapMax", "t", NULL, offsetof(CGroupContext, memory_swap_max), 0), + SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0), ++ SD_BUS_PROPERTY("CPUSetAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpuset_accounting), 0), ++ SD_BUS_PROPERTY("CPUSetCpus", "s", NULL, offsetof(CGroupContext, cpuset_cpus), 0), ++ SD_BUS_PROPERTY("CPUSetMems", "s", NULL, offsetof(CGroupContext, cpuset_mems), 0), ++ SD_BUS_PROPERTY("CPUSetCloneChildren", "b", bus_property_get_bool, offsetof(CGroupContext, cpuset_clone_children), 0), ++ SD_BUS_PROPERTY("CPUSetMemMigrate", "b", bus_property_get_bool, offsetof(CGroupContext, cpuset_memory_migrate), 0), + SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0), + SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0), + SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0), +@@ -1065,6 +1070,43 @@ int bus_cgroup_set_property( + if (streq(name, "MemoryLimitScale")) + return bus_cgroup_set_memory_scale(u, name, &c->memory_limit, message, flags, error); + ++ if (streq(name, "CPUSetAccounting")) ++ return bus_cgroup_set_boolean(u, name, &c->cpuset_accounting, CGROUP_MASK_CPUSET, message, flags, error); ++ ++ if (STR_IN_SET(name, "CPUSetCpus", "CPUSetMems")) { ++ const char *cpuset_str = NULL; ++ ++ r = sd_bus_message_read(message, "s", &cpuset_str); ++ if (r < 0) ++ return r; ++ ++ if (!UNIT_WRITE_FLAGS_NOOP(flags)) { ++ unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET); ++ if (streq(name, "CPUSetCpus")) { ++ if (c->cpuset_cpus) ++ c->cpuset_cpus = mfree(c->cpuset_cpus); ++ c->cpuset_cpus = strdup(cpuset_str); ++ if (!c->cpuset_cpus) ++ return -ENOMEM; ++ unit_write_settingf(u, flags, name, "CPUSetCpus=%s", cpuset_str); ++ } else { ++ if (c->cpuset_mems) ++ c->cpuset_mems = mfree(c->cpuset_mems); ++ c->cpuset_mems = strdup(cpuset_str); ++ if (!c->cpuset_mems) ++ return -ENOMEM; ++ unit_write_settingf(u, flags, name, "CPUSetMems=%s", cpuset_str); ++ } ++ } ++ return 1; ++ } ++ ++ if (streq(name, "CPUSetCloneChildren")) ++ return bus_cgroup_set_boolean(u, name, &c->cpuset_clone_children, CGROUP_MASK_CPUSET, message, flags, error); ++ ++ if (streq(name, "CPUSetMemMigrate")) ++ return bus_cgroup_set_boolean(u, name, &c->cpuset_memory_migrate, CGROUP_MASK_CPUSET, message, flags, error); ++ + if (streq(name, "TasksAccounting")) + return bus_cgroup_set_boolean(u, name, &c->tasks_accounting, CGROUP_MASK_PIDS, message, flags, error); + +@@ -1146,15 +1188,15 @@ int bus_cgroup_set_property( + return -ENOMEM; + + if (streq(name, "AllowedCPUs")) +- set = &c->cpuset_cpus; ++ set = &c->cpuset_cpus2; + else +- set = &c->cpuset_mems; ++ set = &c->cpuset_mems2; + + cpu_set_reset(set); + *set = new_set; + new_set = (CPUSet) {}; + +- unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET); ++ unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET2); + unit_write_settingf(u, flags, name, "%s=%s", name, setstr); + } + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index de057a0..82896af 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -2690,6 +2690,7 @@ const sd_bus_vtable bus_manager_vtable[] = { + SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultCpusetAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpuset_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitCPU", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitCPUSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), +diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in +index 42441ea..60c9dbc 100644 +--- a/src/core/load-fragment-gperf.gperf.in ++++ b/src/core/load-fragment-gperf.gperf.in +@@ -197,6 +197,11 @@ + {{type}}.MemoryMax, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context) + {{type}}.MemorySwapMax, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context) + {{type}}.MemoryLimit, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context) ++{{type}}.CPUSetAccounting, config_parse_bool, 0, offsetof({{type}}, cgroup_context.cpuset_accounting) ++{{type}}.CPUSetCpus, config_parse_cpuset_cpumems, 0, offsetof({{type}}, cgroup_context.cpuset_cpus) ++{{type}}.CPUSetMems, config_parse_cpuset_cpumems, 0, offsetof({{type}}, cgroup_context.cpuset_mems) ++{{type}}.CPUSetCloneChildren, config_parse_bool, 0, offsetof({{type}}, cgroup_context.cpuset_clone_children) ++{{type}}.CPUSetMemMigrate, config_parse_bool, 0, offsetof({{type}}, cgroup_context.cpuset_memory_migrate) + {{type}}.DeviceAllow, config_parse_device_allow, 0, offsetof({{type}}, cgroup_context) + {{type}}.DevicePolicy, config_parse_device_policy, 0, offsetof({{type}}, cgroup_context.device_policy) + {{type}}.IOAccounting, config_parse_bool, 0, offsetof({{type}}, cgroup_context.io_accounting) +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 399a759..ad80a64 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -3632,7 +3632,7 @@ int config_parse_allowed_cpus( + + CGroupContext *c = data; + +- (void) parse_cpu_set_extend(rvalue, &c->cpuset_cpus, true, unit, filename, line, lvalue); ++ (void) parse_cpu_set_extend(rvalue, &c->cpuset_cpus2, true, unit, filename, line, lvalue); + + return 0; + } +@@ -3651,7 +3651,7 @@ int config_parse_allowed_mems( + + CGroupContext *c = data; + +- (void) parse_cpu_set_extend(rvalue, &c->cpuset_mems, true, unit, filename, line, lvalue); ++ (void) parse_cpu_set_extend(rvalue, &c->cpuset_mems2, true, unit, filename, line, lvalue); + + return 0; + } +@@ -3722,6 +3722,75 @@ int config_parse_memory_limit( + return 0; + } + ++int config_parse_cpuset_cpumems( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) ++{ ++ char **pcpumems = data; ++ char *pinstr = NULL; ++ int iret = 0; ++ ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); ++ (void)section; ++ (void)section_line; ++ (void)ltype; ++ (void)userdata; ++ ++ if (!utf8_is_valid(rvalue)) ++ { ++ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); ++ return 0; ++ } ++ ++ if (0 == strcmp(rvalue, "all")) ++ { ++ pinstr = strdup(rvalue); ++ if (!pinstr) ++ { ++ return log_oom(); ++ } ++ ++ free(*pcpumems); ++ *pcpumems = pinstr; ++ ++ return 0; ++ } ++ ++ /* 0-2,4 */ ++ iret = string_isvalid_interval(rvalue); ++ if (0 != iret) ++ { ++ pinstr = NULL; ++ log_syntax(unit, LOG_ERR, filename, line, EINVAL, ++ "cpuset cpumems '%s' is invalid, Ignoring(%d).", ++ rvalue, iret); ++ } ++ else ++ { ++ pinstr = strdup(rvalue); ++ if (!pinstr) ++ { ++ return log_oom(); ++ } ++ } ++ ++ free(*pcpumems); ++ *pcpumems = pinstr; ++ ++ return 0; ++} ++ + int config_parse_tasks_max( + const char *unit, + const char *filename, +diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h +index 45e9c39..1ecad67 100644 +--- a/src/core/load-fragment.h ++++ b/src/core/load-fragment.h +@@ -74,6 +74,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_unit_slice); + CONFIG_PARSER_PROTOTYPE(config_parse_cg_weight); + CONFIG_PARSER_PROTOTYPE(config_parse_cpu_shares); + CONFIG_PARSER_PROTOTYPE(config_parse_memory_limit); ++CONFIG_PARSER_PROTOTYPE(config_parse_cpuset_cpumems); + CONFIG_PARSER_PROTOTYPE(config_parse_tasks_max); + CONFIG_PARSER_PROTOTYPE(config_parse_delegate); + CONFIG_PARSER_PROTOTYPE(config_parse_managed_oom_mode); +diff --git a/src/core/main.c b/src/core/main.c +index 9282b09..c4564e8 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -148,6 +148,7 @@ static bool arg_default_io_accounting; + static bool arg_default_ip_accounting; + static bool arg_default_blockio_accounting; + static bool arg_default_memory_accounting; ++static bool arg_default_cpuset_accounting; + static bool arg_default_tasks_accounting; + static TasksMax arg_default_tasks_max; + static sd_id128_t arg_machine_id; +@@ -693,6 +694,7 @@ static int parse_config_file(void) { + { "Manager", "DefaultIPAccounting", config_parse_bool, 0, &arg_default_ip_accounting }, + { "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting }, + { "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting }, ++ { "Manager", "DefaultCpusetAccounting", config_parse_bool, 0, &arg_default_cpuset_accounting }, + { "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting }, + { "Manager", "DefaultTasksMax", config_parse_tasks_max, 0, &arg_default_tasks_max }, + { "Manager", "CtrlAltDelBurstAction", config_parse_emergency_action, 0, &arg_cad_burst_action }, +@@ -764,6 +766,7 @@ static void set_manager_defaults(Manager *m) { + m->default_ip_accounting = arg_default_ip_accounting; + m->default_blockio_accounting = arg_default_blockio_accounting; + m->default_memory_accounting = arg_default_memory_accounting; ++ m->default_cpuset_accounting = arg_default_cpuset_accounting; + m->default_tasks_accounting = arg_default_tasks_accounting; + m->default_tasks_max = arg_default_tasks_max; + m->default_oom_policy = arg_default_oom_policy; +@@ -2358,6 +2361,7 @@ static void reset_arguments(void) { + arg_default_ip_accounting = false; + arg_default_blockio_accounting = false; + arg_default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT; ++ arg_default_cpuset_accounting = false; + arg_default_tasks_accounting = true; + arg_default_tasks_max = DEFAULT_TASKS_MAX; + arg_machine_id = (sd_id128_t) {}; +diff --git a/src/core/manager.c b/src/core/manager.c +index 38482c0..3a12d6d 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -776,6 +776,7 @@ int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager + + .default_timer_accuracy_usec = USEC_PER_MINUTE, + .default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT, ++ .default_cpuset_accounting = false, + .default_tasks_accounting = true, + .default_tasks_max = TASKS_MAX_UNSET, + .default_timeout_start_usec = DEFAULT_TIMEOUT_USEC, +diff --git a/src/core/manager.h b/src/core/manager.h +index 0c39626..f658caa 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -360,6 +360,7 @@ struct Manager { + + bool default_cpu_accounting; + bool default_memory_accounting; ++ bool default_cpuset_accounting; + bool default_io_accounting; + bool default_blockio_accounting; + bool default_tasks_accounting; +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index f2c75fc..fcc20d0 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -53,6 +53,7 @@ + #DefaultIPAccounting=no + #DefaultBlockIOAccounting=no + #DefaultMemoryAccounting={{ 'yes' if MEMORY_ACCOUNTING_DEFAULT else 'no' }} ++#DefaultCpusetAccounting= + #DefaultTasksAccounting=yes + #DefaultTasksMax=80% + #DefaultLimitCPU= +diff --git a/src/core/unit.c b/src/core/unit.c +index e30c14b..bfd47cf 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -176,6 +176,7 @@ static void unit_init(Unit *u) { + cc->io_accounting = u->manager->default_io_accounting; + cc->blockio_accounting = u->manager->default_blockio_accounting; + cc->memory_accounting = u->manager->default_memory_accounting; ++ cc->cpuset_accounting = u->manager->default_cpuset_accounting; + cc->tasks_accounting = u->manager->default_tasks_accounting; + cc->ip_accounting = u->manager->default_ip_accounting; + +diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c +index d3a5b25..caad3ab 100644 +--- a/src/shared/bus-unit-util.c ++++ b/src/shared/bus-unit-util.c +@@ -460,7 +460,10 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons + "IOAccounting", + "BlockIOAccounting", + "TasksAccounting", +- "IPAccounting")) ++ "IPAccounting", ++ "CPUSetAccounting", ++ "CPUSetCloneChildren", ++ "CPUSetMemMigrate")) + return bus_append_parse_boolean(m, field, eq); + + if (STR_IN_SET(field, "CPUWeight", +@@ -561,6 +564,16 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons + return bus_append_parse_size(m, field, eq, 1024); + } + ++ if (STR_IN_SET(field, "CPUSetCpus", "CPUSetMems")) { ++ if (string_isvalid_interval(eq) == 0 || streq(eq, "all")) ++ r = sd_bus_message_append(m, "(sv)", field, "s", eq); ++ else ++ r = -EINVAL; ++ if (r < 0) ++ return bus_log_create_error(r); ++ return 1; ++ } ++ + if (streq(field, "CPUQuota")) { + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY); +diff --git a/src/shared/cpu-set-util.c b/src/shared/cpu-set-util.c +index e3e6963..2cb4a36 100644 +--- a/src/shared/cpu-set-util.c ++++ b/src/shared/cpu-set-util.c +@@ -7,6 +7,7 @@ + + #include "alloc-util.h" + #include "cpu-set-util.h" ++#include "cgroup-util.h" + #include "dirent-util.h" + #include "errno-util.h" + #include "extract-word.h" +diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c +index 19e159b..425fe19 100644 +--- a/src/test/test-cgroup-mask.c ++++ b/src/test/test-cgroup-mask.c +@@ -55,6 +55,7 @@ static int test_cgroup_mask(void) { + * else. */ + m->default_cpu_accounting = + m->default_memory_accounting = ++ m->default_cpuset_accounting = + m->default_blockio_accounting = + m->default_io_accounting = + m->default_tasks_accounting = false; +@@ -140,10 +141,10 @@ static void test_cg_mask_to_string_one(CGroupMask mask, const char *t) { + + static void test_cg_mask_to_string(void) { + test_cg_mask_to_string_one(0, NULL); +- test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct cpuset io blkio memory devices pids bpf-firewall bpf-devices bpf-foreign bpf-socket-bind"); ++ test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct cpuset2 io blkio memory devices pids cpuset bpf-firewall bpf-devices bpf-foreign bpf-socket-bind"); + test_cg_mask_to_string_one(CGROUP_MASK_CPU, "cpu"); + test_cg_mask_to_string_one(CGROUP_MASK_CPUACCT, "cpuacct"); +- test_cg_mask_to_string_one(CGROUP_MASK_CPUSET, "cpuset"); ++ test_cg_mask_to_string_one(CGROUP_MASK_CPUSET2, "cpuset2"); + test_cg_mask_to_string_one(CGROUP_MASK_IO, "io"); + test_cg_mask_to_string_one(CGROUP_MASK_BLKIO, "blkio"); + test_cg_mask_to_string_one(CGROUP_MASK_MEMORY, "memory"); +diff --git a/test/fuzz/fuzz-unit-file/directives-all.service b/test/fuzz/fuzz-unit-file/directives-all.service +index 3039d1c..5f8cdd8 100644 +--- a/test/fuzz/fuzz-unit-file/directives-all.service ++++ b/test/fuzz/fuzz-unit-file/directives-all.service +@@ -48,6 +48,11 @@ BusName= + CoredumpFilter= + CPUAccounting= + CPUQuota= ++CPUSetAccounting= ++CPUSetCloneChildren= ++CPUSetCpus= ++CPUSetMemMigrate= ++CPUSetMems= + CPUShares= + CPUWeight= + CapabilityBoundingSet= +diff --git a/test/fuzz/fuzz-unit-file/directives.mount b/test/fuzz/fuzz-unit-file/directives.mount +index 451f291..3adfd5b 100644 +--- a/test/fuzz/fuzz-unit-file/directives.mount ++++ b/test/fuzz/fuzz-unit-file/directives.mount +@@ -19,6 +19,11 @@ CPUQuotaPeriodSec= + CPUSchedulingPolicy= + CPUSchedulingPriority= + CPUSchedulingResetOnFork= ++CPUSetAccounting= ++CPUSetCloneChildren= ++CPUSetCpus= ++CPUSetMemMigrate= ++CPUSetMems= + CPUShares= + CPUWeight= + CacheDirectory= +diff --git a/test/fuzz/fuzz-unit-file/directives.scope b/test/fuzz/fuzz-unit-file/directives.scope +index 7e69cf8..c953f9c 100644 +--- a/test/fuzz/fuzz-unit-file/directives.scope ++++ b/test/fuzz/fuzz-unit-file/directives.scope +@@ -11,6 +11,11 @@ BlockIOWriteBandwidth= + CPUAccounting= + CPUQuota= + CPUQuotaPeriodSec= ++CPUSetAccounting= ++CPUSetCloneChildren= ++CPUSetCpus= ++CPUSetMemMigrate= ++CPUSetMems= + CPUShares= + CPUWeight= + DefaultMemoryLow= +diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service +index de7d2c7..aa5ad32 100644 +--- a/test/fuzz/fuzz-unit-file/directives.service ++++ b/test/fuzz/fuzz-unit-file/directives.service +@@ -63,6 +63,11 @@ ConditionSecurity= + ConditionUser= + ConditionVirtualization= + Conflicts= ++CPUSetAccounting= ++CPUSetCloneChildren= ++CPUSetCpus= ++CPUSetMemMigrate= ++CPUSetMems= + DefaultDependencies= + Description= + Documentation= +diff --git a/test/fuzz/fuzz-unit-file/directives.slice b/test/fuzz/fuzz-unit-file/directives.slice +index 789ac8f..54cb55d 100644 +--- a/test/fuzz/fuzz-unit-file/directives.slice ++++ b/test/fuzz/fuzz-unit-file/directives.slice +@@ -11,6 +11,11 @@ BlockIOWriteBandwidth= + CPUAccounting= + CPUQuota= + CPUQuotaPeriodSec= ++CPUSetAccounting= ++CPUSetCloneChildren= ++CPUSetCpus= ++CPUSetMemMigrate= ++CPUSetMems= + CPUShares= + CPUWeight= + DefaultMemoryLow= +diff --git a/test/fuzz/fuzz-unit-file/directives.socket b/test/fuzz/fuzz-unit-file/directives.socket +index 11f589e..aa9e758 100644 +--- a/test/fuzz/fuzz-unit-file/directives.socket ++++ b/test/fuzz/fuzz-unit-file/directives.socket +@@ -24,6 +24,11 @@ CPUQuotaPeriodSec= + CPUSchedulingPolicy= + CPUSchedulingPriority= + CPUSchedulingResetOnFork= ++CPUSetAccounting= ++CPUSetCloneChildren= ++CPUSetCpus= ++CPUSetMemMigrate= ++CPUSetMems= + CPUShares= + CPUWeight= + CacheDirectory= +diff --git a/test/fuzz/fuzz-unit-file/directives.swap b/test/fuzz/fuzz-unit-file/directives.swap +index 582a136..bc07775 100644 +--- a/test/fuzz/fuzz-unit-file/directives.swap ++++ b/test/fuzz/fuzz-unit-file/directives.swap +@@ -19,6 +19,11 @@ CPUQuotaPeriodSec= + CPUSchedulingPolicy= + CPUSchedulingPriority= + CPUSchedulingResetOnFork= ++CPUSetAccounting= ++CPUSetCloneChildren= ++CPUSetCpus= ++CPUSetMemMigrate= ++CPUSetMems= + CPUShares= + CPUWeight= + CacheDirectory= +-- +2.23.0 + diff --git a/core-cgroup-support-default-slice-for-all-uni.patch b/core-cgroup-support-default-slice-for-all-uni.patch new file mode 100644 index 0000000000000000000000000000000000000000..158e9a996ba887553713e17fefe160e19bd42d02 --- /dev/null +++ b/core-cgroup-support-default-slice-for-all-uni.patch @@ -0,0 +1,216 @@ +From a25f206a49d8a3111ac42791b2eca8a3c9af4991 Mon Sep 17 00:00:00 2001 +From: licunlong +Date: Thu, 6 May 2021 09:38:55 +0800 +Subject: [PATCH] core-cgroup: support default slice for all units. + +With this patch, users can specify a default slice for all units by +adding DefaultUnitSlice=xxx.slice in /etc/systemd/system.conf. +--- + src/core/main.c | 22 +++++++++++ + src/core/manager.h | 2 + + src/core/unit.c | 98 ++++++++++++++++++++++++++++++++++++++++++---- + 3 files changed, 114 insertions(+), 8 deletions(-) + +diff --git a/src/core/main.c b/src/core/main.c +index 48e8a4b..c3d9e1c 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -159,6 +159,7 @@ static EmergencyAction arg_cad_burst_action; + static OOMPolicy arg_default_oom_policy; + static CPUSet arg_cpu_affinity; + static NUMAPolicy arg_numa_policy; ++static char *arg_default_unit_slice = NULL; + static usec_t arg_clock_usec; + static void *arg_random_seed; + static size_t arg_random_seed_size; +@@ -705,6 +706,7 @@ static int parse_config_file(void) { + { "Manager", "DefaultTasksMax", config_parse_tasks_max, 0, &arg_default_tasks_max }, + { "Manager", "CtrlAltDelBurstAction", config_parse_emergency_action, 0, &arg_cad_burst_action }, + { "Manager", "DefaultOOMPolicy", config_parse_oom_policy, 0, &arg_default_oom_policy }, ++ { "Manager", "DefaultUnitSlice", config_parse_string, 0, &arg_default_unit_slice }, + {} + }; + +@@ -784,6 +786,26 @@ static void set_manager_defaults(Manager *m) { + + (void) manager_default_environment(m); + (void) manager_transient_environment_add(m, arg_default_environment); ++ if (m->default_unit_slice) ++ { ++ free(m->default_unit_slice); ++ m->default_unit_slice = NULL; ++ } ++ ++ if (arg_default_unit_slice) ++ { ++ char *default_unit_slice_tmp = NULL; ++ ++ default_unit_slice_tmp = strdup(arg_default_unit_slice); ++ if (!default_unit_slice_tmp) ++ log_oom(); ++ ++ m->default_unit_slice = default_unit_slice_tmp; ++ ++ /* free */ ++ free(arg_default_unit_slice); ++ arg_default_unit_slice = NULL; ++ } + } + + static void set_manager_settings(Manager *m) { +diff --git a/src/core/manager.h b/src/core/manager.h +index 25d058f..ddddc8e 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -23,6 +23,7 @@ typedef struct Unit Unit; + + /* Enforce upper limit how many names we allow */ + #define MANAGER_MAX_NAMES 131072 /* 128K */ ++#define DEFAULT_UNIT_NAME_LEN_MAX 32 + + typedef struct Manager Manager; + +@@ -445,6 +446,7 @@ struct Manager { + unsigned notifygen; + + bool honor_device_enumeration; ++ char *default_unit_slice; + bool in_manager_catchup; + + VarlinkServer *varlink_server; +diff --git a/src/core/unit.c b/src/core/unit.c +index cbb02ea..e3dee86 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -3316,6 +3316,58 @@ int unit_set_slice(Unit *u, Unit *slice) { + return 1; + } + ++/* system-xxx.slice, xxx must be (a b c/A B C...and 0 1 2...) */ ++static bool slicename_is_valid(const char *slicename) { ++ const char *str_start = "system-"; ++ const char *str_end = ".slice"; ++ const char *str_tmp = NULL; ++ size_t len_in = 0; ++ size_t len_start = 0; ++ size_t len_end = 0; ++ size_t i = 0; ++ ++ if (isempty(slicename)) ++ return false; ++ ++ len_in = strlen(slicename); ++ len_start = strlen(str_start); ++ len_end = strlen(str_end); ++ ++ if (len_in > DEFAULT_UNIT_NAME_LEN_MAX) ++ return false; ++ ++ if (len_in <= len_start + len_end) ++ return false; ++ ++ /* system- */ ++ if (strncmp(slicename, str_start, len_start) != 0) ++ return false; ++ ++ str_tmp = slicename + len_start; ++ ++ len_in = strlen(str_tmp); ++ if (len_in <= len_end) ++ return false; ++ ++ /* .slice */ ++ if (!strneq(str_tmp + len_in - len_end, str_end, len_end)) ++ return false; ++ ++ /* a b c/A B C...and 0 1 2... */ ++ for (i = 0; i < (len_in - len_end); i++) { ++ char c = *(str_tmp + i); ++ ++ if ((c >= 'a' && c <= 'z') || ++ (c >= 'A' && c <= 'Z') || ++ (c >= '0' && c <= '9')) ++ continue; ++ else ++ return false; ++ } ++ ++ return true; ++} ++ + int unit_set_default_slice(Unit *u) { + const char *slice_name; + Unit *slice; +@@ -3326,6 +3378,20 @@ int unit_set_default_slice(Unit *u) { + if (UNIT_GET_SLICE(u)) + return 0; + ++ bool isdefaultslice = false; ++ char *default_unit_slice = u->manager->default_unit_slice; ++ ++ if (default_unit_slice) { ++ isdefaultslice = true; ++ ++ if (streq(default_unit_slice, SPECIAL_SYSTEM_SLICE)) ++ isdefaultslice = false; ++ else if (!slicename_is_valid(default_unit_slice)) { ++ log_error("default unit slice is error. slice name '%s' is invalid.", default_unit_slice); ++ isdefaultslice = false; ++ } ++ } ++ + if (u->instance) { + _cleanup_free_ char *prefix = NULL, *escaped = NULL; + +@@ -3343,24 +3409,40 @@ int unit_set_default_slice(Unit *u) { + if (!escaped) + return -ENOMEM; + +- if (MANAGER_IS_SYSTEM(u->manager)) +- slice_name = strjoina("system-", escaped, ".slice"); +- else ++ if (MANAGER_IS_SYSTEM(u->manager)) { ++ if (isdefaultslice) { ++ _cleanup_free_ char *default_unit_slice_tmp = NULL; ++ ++ default_unit_slice_tmp = strreplace(default_unit_slice, ".slice", "-"); ++ if (!default_unit_slice_tmp) ++ return -ENOMEM; ++ ++ slice_name = strjoina(default_unit_slice_tmp, escaped, ".slice"); ++ } else ++ slice_name = strjoina("system-", escaped, ".slice"); ++ } else + slice_name = strjoina("app-", escaped, ".slice"); + +- } else if (unit_is_extrinsic(u)) ++ } else if (unit_is_extrinsic(u)) { + /* Keep all extrinsic units (e.g. perpetual units and swap and mount units in user mode) in + * the root slice. They don't really belong in one of the subslices. */ + slice_name = SPECIAL_ROOT_SLICE; +- +- else if (MANAGER_IS_SYSTEM(u->manager)) +- slice_name = SPECIAL_SYSTEM_SLICE; +- else ++ isdefaultslice = false; ++ } else if (MANAGER_IS_SYSTEM(u->manager)) { ++ if (isdefaultslice) ++ slice_name = default_unit_slice; ++ else ++ slice_name = SPECIAL_SYSTEM_SLICE; ++ } else { + slice_name = SPECIAL_APP_SLICE; ++ isdefaultslice = false; ++ } + + r = manager_load_unit(u->manager, slice_name, NULL, NULL, &slice); + if (r < 0) + return r; ++ if (isdefaultslice) ++ slice->default_dependencies=false; + + return unit_set_slice(u, slice); + } +-- +2.27.0 + diff --git a/core-cgroup-support-freezer.patch b/core-cgroup-support-freezer.patch new file mode 100644 index 0000000000000000000000000000000000000000..e38319097a93a7ff2c21eb25375616c76383a279 --- /dev/null +++ b/core-cgroup-support-freezer.patch @@ -0,0 +1,589 @@ +From 05a0f33b0d0a650b25ce7955a171d725f9c3f5f6 Mon Sep 17 00:00:00 2001 +From: licunlong +Date: Thu, 6 May 2021 09:38:54 +0800 +Subject: [PATCH] core-cgroup: support freezer. + +This patch add support for freezer subsystem. +--- + src/basic/cgroup-util.c | 1 + + src/basic/cgroup-util.h | 4 +- + src/core/cgroup.c | 16 +++++++ + src/core/cgroup.h | 4 ++ + src/core/dbus-cgroup.c | 29 +++++++++++++ + src/core/dbus-manager.c | 1 + + src/core/load-fragment-gperf.gperf.in | 2 + + src/core/load-fragment.c | 33 ++++++++++++++ + src/core/load-fragment.h | 1 + + src/core/main.c | 4 ++ + src/core/manager.h | 1 + + src/core/system.conf.in | 1 + + src/core/unit.c | 1 + + src/shared/bus-unit-util.c | 11 +++++ + src/test/meson.build | 6 +++ + src/test/test-cgroup-freezer.c | 43 +++++++++++++++++++ + src/test/test-cgroup-mask.c | 3 +- + .../fuzz-unit-file/directives-all.service | 2 + + test/fuzz/fuzz-unit-file/directives.mount | 2 + + test/fuzz/fuzz-unit-file/directives.scope | 2 + + test/fuzz/fuzz-unit-file/directives.service | 2 + + test/fuzz/fuzz-unit-file/directives.slice | 2 + + test/fuzz/fuzz-unit-file/directives.socket | 2 + + test/fuzz/fuzz-unit-file/directives.swap | 2 + + 24 files changed, 173 insertions(+), 2 deletions(-) + create mode 100644 src/test/test-cgroup-freezer.c + +diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c +index 01a4181..f912b65 100644 +--- a/src/basic/cgroup-util.c ++++ b/src/basic/cgroup-util.c +@@ -2162,6 +2162,7 @@ static const char *const cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = { + [CGROUP_CONTROLLER_DEVICES] = "devices", + [CGROUP_CONTROLLER_PIDS] = "pids", + [CGROUP_CONTROLLER_CPUSET] = "cpuset", ++ [CGROUP_CONTROLLER_FREEZER] = "freezer", + [CGROUP_CONTROLLER_BPF_FIREWALL] = "bpf-firewall", + [CGROUP_CONTROLLER_BPF_DEVICES] = "bpf-devices", + [CGROUP_CONTROLLER_BPF_FOREIGN] = "bpf-foreign", +diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h +index 06a23ff..a491eca 100644 +--- a/src/basic/cgroup-util.h ++++ b/src/basic/cgroup-util.h +@@ -27,6 +27,7 @@ typedef enum CGroupController { + CGROUP_CONTROLLER_DEVICES, /* v1 only */ + CGROUP_CONTROLLER_PIDS, + CGROUP_CONTROLLER_CPUSET, ++ CGROUP_CONTROLLER_FREEZER, + + /* BPF-based pseudo-controllers, v2 only */ + CGROUP_CONTROLLER_BPF_FIREWALL, +@@ -51,13 +52,14 @@ typedef enum CGroupMask { + CGROUP_MASK_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICES), + CGROUP_MASK_PIDS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_PIDS), + CGROUP_MASK_CPUSET = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET), ++ CGROUP_MASK_FREEZER = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_FREEZER), + CGROUP_MASK_BPF_FIREWALL = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_FIREWALL), + CGROUP_MASK_BPF_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_DEVICES), + CGROUP_MASK_BPF_FOREIGN = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_FOREIGN), + CGROUP_MASK_BPF_SOCKET_BIND = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_SOCKET_BIND), + + /* All real cgroup v1 controllers */ +- CGROUP_MASK_V1 = CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT|CGROUP_MASK_BLKIO|CGROUP_MASK_MEMORY|CGROUP_MASK_CPUSET|CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS, ++ CGROUP_MASK_V1 = CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT|CGROUP_MASK_BLKIO|CGROUP_MASK_MEMORY|CGROUP_MASK_CPUSET|CGROUP_MASK_FREEZER|CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS, + + /* All real cgroup v2 controllers */ + CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_CPUSET2|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS, +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index 83e94c7..f811a8b 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -139,6 +139,7 @@ void cgroup_context_init(CGroupContext *c) { + .startup_blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID, + + .tasks_max = TASKS_MAX_UNSET, ++ .freezer_state = NULL, + + .moom_swap = MANAGED_OOM_AUTO, + .moom_mem_pressure = MANAGED_OOM_AUTO, +@@ -260,6 +261,9 @@ void cgroup_context_done(CGroupContext *c) { + + cpu_set_reset(&c->cpuset_cpus2); + cpu_set_reset(&c->cpuset_mems2); ++ ++ if (c->freezer_state) ++ c->freezer_state = mfree(c->freezer_state); + } + + static int unit_get_kernel_memory_limit(Unit *u, const char *file, uint64_t *ret) { +@@ -433,6 +437,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { + "%sBlockIOAccounting: %s\n" + "%sMemoryAccounting: %s\n" + "%sCPUSetAccounting: %s\n" ++ "%sFreezerAccounting=%s\n" + "%sTasksAccounting: %s\n" + "%sIPAccounting: %s\n" + "%sCPUWeight: %" PRIu64 "\n" +@@ -460,6 +465,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { + "%sCPUSetCloneChildren=%s\n" + "%sCPUSetMemMigrate=%s\n" + "%sTasksMax: %" PRIu64 "\n" ++ "%sFreezerState=%s\n" + "%sDevicePolicy: %s\n" + "%sDisableControllers: %s\n" + "%sDelegate: %s\n" +@@ -472,6 +478,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { + prefix, yes_no(c->blockio_accounting), + prefix, yes_no(c->memory_accounting), + prefix, yes_no(c->cpuset_accounting), ++ prefix, yes_no(c->freezer_accounting), + prefix, yes_no(c->tasks_accounting), + prefix, yes_no(c->ip_accounting), + prefix, c->cpu_weight, +@@ -499,6 +506,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { + prefix, yes_no(c->cpuset_clone_children), + prefix, yes_no(c->cpuset_memory_migrate), + prefix, tasks_max_resolve(&c->tasks_max), ++ prefix, c->freezer_state, + prefix, cgroup_device_policy_to_string(c->device_policy), + prefix, strempty(disable_controllers_str), + prefix, yes_no(c->delegate), +@@ -1566,6 +1574,11 @@ static void cgroup_context_apply( + } + } + ++ if ((apply_mask & CGROUP_MASK_FREEZER) && !is_local_root) { ++ if (c->freezer_state) ++ (void) set_attribute_and_warn(u, "freezer", "freezer.state", c->freezer_state); ++ } ++ + /* On cgroup v2 we can apply BPF everywhere. On cgroup v1 we apply it everywhere except for the root of + * containers, where we leave this to the manager */ + if ((apply_mask & (CGROUP_MASK_DEVICES | CGROUP_MASK_BPF_DEVICES)) && +@@ -1708,6 +1721,9 @@ static CGroupMask unit_get_cgroup_mask(Unit *u) { + c->cpuset_mems) + mask |= CGROUP_MASK_CPUSET; + ++ if (c->freezer_accounting || c->freezer_state) ++ mask |= CGROUP_MASK_FREEZER; ++ + if (c->device_allow || + c->device_policy != CGROUP_DEVICE_POLICY_AUTO) + mask |= CGROUP_MASK_DEVICES | CGROUP_MASK_BPF_DEVICES; +diff --git a/src/core/cgroup.h b/src/core/cgroup.h +index 1e27104..6833d5b 100644 +--- a/src/core/cgroup.h ++++ b/src/core/cgroup.h +@@ -116,6 +116,7 @@ struct CGroupContext { + bool blockio_accounting; + bool memory_accounting; + bool cpuset_accounting; ++ bool freezer_accounting; + bool tasks_accounting; + bool ip_accounting; + +@@ -186,6 +187,9 @@ struct CGroupContext { + /* Common */ + TasksMax tasks_max; + ++ /* Freezer */ ++ char *freezer_state; ++ + /* Settings for systemd-oomd */ + ManagedOOMMode moom_swap; + ManagedOOMMode moom_mem_pressure; +diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c +index 0cdc98c..8527a1a 100644 +--- a/src/core/dbus-cgroup.c ++++ b/src/core/dbus-cgroup.c +@@ -445,6 +445,8 @@ const sd_bus_vtable bus_cgroup_vtable[] = { + SD_BUS_PROPERTY("CPUSetMems", "s", NULL, offsetof(CGroupContext, cpuset_mems), 0), + SD_BUS_PROPERTY("CPUSetCloneChildren", "b", bus_property_get_bool, offsetof(CGroupContext, cpuset_clone_children), 0), + SD_BUS_PROPERTY("CPUSetMemMigrate", "b", bus_property_get_bool, offsetof(CGroupContext, cpuset_memory_migrate), 0), ++ SD_BUS_PROPERTY("FreezerAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, freezer_accounting), 0), ++ SD_BUS_PROPERTY("FreezerState", "s", NULL, offsetof(CGroupContext, freezer_state), 0), + SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0), + SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0), + SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0), +@@ -1073,6 +1075,9 @@ int bus_cgroup_set_property( + if (streq(name, "CPUSetAccounting")) + return bus_cgroup_set_boolean(u, name, &c->cpuset_accounting, CGROUP_MASK_CPUSET, message, flags, error); + ++ if (streq(name, "FreezerAccounting")) ++ return bus_cgroup_set_boolean(u, name, &c->freezer_accounting, CGROUP_MASK_FREEZER, message, flags, error); ++ + if (STR_IN_SET(name, "CPUSetCpus", "CPUSetMems")) { + const char *cpuset_str = NULL; + +@@ -1107,6 +1112,30 @@ int bus_cgroup_set_property( + if (streq(name, "CPUSetMemMigrate")) + return bus_cgroup_set_boolean(u, name, &c->cpuset_memory_migrate, CGROUP_MASK_CPUSET, message, flags, error); + ++ if (streq(name, "FreezerState")) { ++ const char *state = NULL; ++ ++ r = sd_bus_message_read(message, "s", &state); ++ if (r < 0) ++ return r; ++ ++ if (!UNIT_WRITE_FLAGS_NOOP(flags)) { ++ unit_invalidate_cgroup(u, CGROUP_MASK_FREEZER); ++ ++ if (c->freezer_state) { ++ free(c->freezer_state); ++ c->freezer_state = NULL; ++ } ++ ++ c->freezer_state = strdup(state); ++ if (!c->freezer_state) ++ return -ENOMEM; ++ ++ unit_write_settingf(u, flags, name, "FreezerState=%s", state); ++ } ++ return 1; ++ } ++ + if (streq(name, "TasksAccounting")) + return bus_cgroup_set_boolean(u, name, &c->tasks_accounting, CGROUP_MASK_PIDS, message, flags, error); + +diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c +index 82896af..184df9d 100644 +--- a/src/core/dbus-manager.c ++++ b/src/core/dbus-manager.c +@@ -2691,6 +2691,7 @@ const sd_bus_vtable bus_manager_vtable[] = { + SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultCpusetAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpuset_accounting), SD_BUS_VTABLE_PROPERTY_CONST), ++ SD_BUS_PROPERTY("DefaultFreezerAccounting", "b", bus_property_get_bool, offsetof(Manager, default_freezer_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitCPU", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitCPUSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), +diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in +index 60c9dbc..5b7ecd2 100644 +--- a/src/core/load-fragment-gperf.gperf.in ++++ b/src/core/load-fragment-gperf.gperf.in +@@ -202,6 +202,8 @@ + {{type}}.CPUSetMems, config_parse_cpuset_cpumems, 0, offsetof({{type}}, cgroup_context.cpuset_mems) + {{type}}.CPUSetCloneChildren, config_parse_bool, 0, offsetof({{type}}, cgroup_context.cpuset_clone_children) + {{type}}.CPUSetMemMigrate, config_parse_bool, 0, offsetof({{type}}, cgroup_context.cpuset_memory_migrate) ++{{type}}.FreezerAccounting, config_parse_bool, 0, offsetof({{type}}, cgroup_context.freezer_accounting) ++{{type}}.FreezerState, config_parse_freezer_state, 0, offsetof({{type}}, cgroup_context.freezer_state) + {{type}}.DeviceAllow, config_parse_device_allow, 0, offsetof({{type}}, cgroup_context) + {{type}}.DevicePolicy, config_parse_device_policy, 0, offsetof({{type}}, cgroup_context.device_policy) + {{type}}.IOAccounting, config_parse_bool, 0, offsetof({{type}}, cgroup_context.io_accounting) +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 5f6a703..d5eb932 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -3791,6 +3791,39 @@ int config_parse_cpuset_cpumems( + return 0; + } + ++int config_parse_freezer_state( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { ++ ++ char **freezer_state = data; ++ char *pinstr = NULL; ++ ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ ++ if (!STR_IN_SET(rvalue, "FROZEN", "THAWED")) { ++ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Freezer state '%s' is invalid, Ignoring.", rvalue); ++ return 0; ++ } ++ ++ pinstr = strdup(rvalue); ++ if (!pinstr) ++ return log_oom(); ++ ++ free(*freezer_state); ++ *freezer_state = pinstr; ++ return 0; ++} ++ + int config_parse_tasks_max( + const char *unit, + const char *filename, +diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h +index 1ecad67..090776c 100644 +--- a/src/core/load-fragment.h ++++ b/src/core/load-fragment.h +@@ -75,6 +75,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_cg_weight); + CONFIG_PARSER_PROTOTYPE(config_parse_cpu_shares); + CONFIG_PARSER_PROTOTYPE(config_parse_memory_limit); + CONFIG_PARSER_PROTOTYPE(config_parse_cpuset_cpumems); ++CONFIG_PARSER_PROTOTYPE(config_parse_freezer_state); + CONFIG_PARSER_PROTOTYPE(config_parse_tasks_max); + CONFIG_PARSER_PROTOTYPE(config_parse_delegate); + CONFIG_PARSER_PROTOTYPE(config_parse_managed_oom_mode); +diff --git a/src/core/main.c b/src/core/main.c +index 6309aab..9cc7fec 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -149,6 +149,7 @@ static bool arg_default_ip_accounting; + static bool arg_default_blockio_accounting; + static bool arg_default_memory_accounting; + static bool arg_default_cpuset_accounting; ++static bool arg_default_freezer_accounting; + static bool arg_default_tasks_accounting; + static TasksMax arg_default_tasks_max; + static sd_id128_t arg_machine_id; +@@ -695,6 +696,7 @@ static int parse_config_file(void) { + { "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting }, + { "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting }, + { "Manager", "DefaultCpusetAccounting", config_parse_bool, 0, &arg_default_cpuset_accounting }, ++ { "Manager", "DefaultFreezerAccounting", config_parse_bool, 0, &arg_default_freezer_accounting }, + { "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting }, + { "Manager", "DefaultTasksMax", config_parse_tasks_max, 0, &arg_default_tasks_max }, + { "Manager", "CtrlAltDelBurstAction", config_parse_emergency_action, 0, &arg_cad_burst_action }, +@@ -767,6 +769,7 @@ static void set_manager_defaults(Manager *m) { + m->default_blockio_accounting = arg_default_blockio_accounting; + m->default_memory_accounting = arg_default_memory_accounting; + m->default_cpuset_accounting = arg_default_cpuset_accounting; ++ m->default_freezer_accounting = arg_default_freezer_accounting; + m->default_tasks_accounting = arg_default_tasks_accounting; + m->default_tasks_max = arg_default_tasks_max; + m->default_oom_policy = arg_default_oom_policy; +@@ -2405,6 +2408,7 @@ static void reset_arguments(void) { + arg_default_blockio_accounting = false; + arg_default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT; + arg_default_cpuset_accounting = false; ++ arg_default_freezer_accounting = false; + arg_default_tasks_accounting = true; + arg_default_tasks_max = DEFAULT_TASKS_MAX; + arg_machine_id = (sd_id128_t) {}; +diff --git a/src/core/manager.h b/src/core/manager.h +index b7a51cf..72fd86e 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -361,6 +361,7 @@ struct Manager { + bool default_cpu_accounting; + bool default_memory_accounting; + bool default_cpuset_accounting; ++ bool default_freezer_accounting; + bool default_io_accounting; + bool default_blockio_accounting; + bool default_tasks_accounting; +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index fcc20d0..f97bd2f 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -54,6 +54,7 @@ + #DefaultBlockIOAccounting=no + #DefaultMemoryAccounting={{ 'yes' if MEMORY_ACCOUNTING_DEFAULT else 'no' }} + #DefaultCpusetAccounting= ++#DefaultFreezerAccounting=no + #DefaultTasksAccounting=yes + #DefaultTasksMax=80% + #DefaultLimitCPU= +diff --git a/src/core/unit.c b/src/core/unit.c +index 2f20053..70849e4 100644 +--- a/src/core/unit.c ++++ b/src/core/unit.c +@@ -177,6 +177,7 @@ static void unit_init(Unit *u) { + cc->blockio_accounting = u->manager->default_blockio_accounting; + cc->memory_accounting = u->manager->default_memory_accounting; + cc->cpuset_accounting = u->manager->default_cpuset_accounting; ++ cc->freezer_accounting = u->manager->default_freezer_accounting; + cc->tasks_accounting = u->manager->default_tasks_accounting; + cc->ip_accounting = u->manager->default_ip_accounting; + +diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c +index caad3ab..f20fcbf 100644 +--- a/src/shared/bus-unit-util.c ++++ b/src/shared/bus-unit-util.c +@@ -462,6 +462,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons + "TasksAccounting", + "IPAccounting", + "CPUSetAccounting", ++ "FreezerAccounting", + "CPUSetCloneChildren", + "CPUSetMemMigrate")) + return bus_append_parse_boolean(m, field, eq); +@@ -574,6 +575,16 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons + return 1; + } + ++ if (streq(field, "FreezerState")) { ++ if (STR_IN_SET(eq, "FROZEN", "THAWED")) ++ r = sd_bus_message_append(m, "(sv)", field, "s", eq); ++ else ++ r = -EINVAL; ++ if (r < 0) ++ return bus_log_create_error(r); ++ return 1; ++ } ++ + if (streq(field, "CPUQuota")) { + if (isempty(eq)) + r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY); +diff --git a/src/test/meson.build b/src/test/meson.build +index c0faeb4..fc891bb 100644 +--- a/src/test/meson.build ++++ b/src/test/meson.build +@@ -450,6 +450,12 @@ tests += [ + [], + core_includes], + ++ [['src/test/test-cgroup-freezer.c'], ++ [libcore, ++ libshared], ++ [], ++ core_includes], ++ + [['src/test/test-cgroup-unit-default.c'], + [libcore, + libshared], +diff --git a/src/test/test-cgroup-freezer.c b/src/test/test-cgroup-freezer.c +new file mode 100644 +index 0000000..a533d16 +--- /dev/null ++++ b/src/test/test-cgroup-freezer.c +@@ -0,0 +1,43 @@ ++/* SPDX-License-Identifier: LGPL-2.1+ */ ++ ++#include "load-fragment.h" ++#include "string-util.h" ++ ++static void test_config_parse_freezer_state(void) { ++ /* int config_parse_freezer_state( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) */ ++ int r; ++ _cleanup_free_ char *pstate = NULL; ++ ++ r = config_parse_freezer_state(NULL, "fake", 1, "section", 1, "FreezerState", 0, "FROZEN", &pstate, NULL); ++ assert_se(r >= 0); ++ assert_se(streq(pstate, "FROZEN")); ++ ++ pstate = mfree(pstate); ++ r = config_parse_freezer_state(NULL, "fake", 1, "section", 1, "FreezerState", 0, "THAWED", &pstate, NULL); ++ assert_se(r >= 0); ++ assert_se(streq(pstate, "THAWED")); ++ ++ pstate = mfree(pstate); ++ r = config_parse_freezer_state(NULL, "fake", 1, "section", 1, "FreezerState", 0, "test", &pstate, NULL); ++ assert_se(r >= 0); ++ assert_se(!pstate); ++ ++ r = config_parse_freezer_state(NULL, "fake", 1, "section", 1, "FreezerState", 0, "", &pstate, NULL); ++ assert_se(r >= 0); ++ assert_se(!pstate); ++} ++ ++int main(int argc, char *argv[]){ ++ test_config_parse_freezer_state(); ++ return 0; ++} +diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c +index 425fe19..31fd5d0 100644 +--- a/src/test/test-cgroup-mask.c ++++ b/src/test/test-cgroup-mask.c +@@ -56,6 +56,7 @@ static int test_cgroup_mask(void) { + m->default_cpu_accounting = + m->default_memory_accounting = + m->default_cpuset_accounting = ++ m->default_freezer_accounting = + m->default_blockio_accounting = + m->default_io_accounting = + m->default_tasks_accounting = false; +@@ -141,7 +142,7 @@ static void test_cg_mask_to_string_one(CGroupMask mask, const char *t) { + + static void test_cg_mask_to_string(void) { + test_cg_mask_to_string_one(0, NULL); +- test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct cpuset2 io blkio memory devices pids cpuset bpf-firewall bpf-devices bpf-foreign bpf-socket-bind"); ++ test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct cpuset2 io blkio memory devices pids cpuset freezer bpf-firewall bpf-devices bpf-foreign bpf-socket-bind"); + test_cg_mask_to_string_one(CGROUP_MASK_CPU, "cpu"); + test_cg_mask_to_string_one(CGROUP_MASK_CPUACCT, "cpuacct"); + test_cg_mask_to_string_one(CGROUP_MASK_CPUSET2, "cpuset2"); +diff --git a/test/fuzz/fuzz-unit-file/directives-all.service b/test/fuzz/fuzz-unit-file/directives-all.service +index 5f8cdd8..1cd161d 100644 +--- a/test/fuzz/fuzz-unit-file/directives-all.service ++++ b/test/fuzz/fuzz-unit-file/directives-all.service +@@ -107,6 +107,8 @@ FileDescriptorName= + FileDescriptorStoreMax= + ForceUnmount= + FreeBind= ++FreezerAccounting= ++FreezerState= + Group= + GuessMainPID= + IOAccounting= +diff --git a/test/fuzz/fuzz-unit-file/directives.mount b/test/fuzz/fuzz-unit-file/directives.mount +index 3adfd5b..53c035a 100644 +--- a/test/fuzz/fuzz-unit-file/directives.mount ++++ b/test/fuzz/fuzz-unit-file/directives.mount +@@ -47,6 +47,8 @@ ExecPaths= + ExtensionImages= + FinalKillSignal= + ForceUnmount= ++FreezerAccounting= ++FreezerState= + Group= + IOAccounting= + IODeviceLatencyTargetSec= +diff --git a/test/fuzz/fuzz-unit-file/directives.scope b/test/fuzz/fuzz-unit-file/directives.scope +index c953f9c..1dd6c60 100644 +--- a/test/fuzz/fuzz-unit-file/directives.scope ++++ b/test/fuzz/fuzz-unit-file/directives.scope +@@ -25,6 +25,8 @@ DeviceAllow= + DevicePolicy= + DisableControllers= + FinalKillSignal= ++FreezerAccounting= ++FreezerState= + IOAccounting= + IODeviceLatencyTargetSec= + IODeviceWeight= +diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service +index aa5ad32..a5f7f07 100644 +--- a/test/fuzz/fuzz-unit-file/directives.service ++++ b/test/fuzz/fuzz-unit-file/directives.service +@@ -73,6 +73,8 @@ Description= + Documentation= + FailureAction= + FailureActionExitStatus= ++FreezerAccounting= ++FreezerState= + IgnoreOnIsolate= + IgnoreOnSnapshot= + JobRunningTimeoutSec= +diff --git a/test/fuzz/fuzz-unit-file/directives.slice b/test/fuzz/fuzz-unit-file/directives.slice +index 54cb55d..2328a24 100644 +--- a/test/fuzz/fuzz-unit-file/directives.slice ++++ b/test/fuzz/fuzz-unit-file/directives.slice +@@ -24,6 +24,8 @@ Delegate= + DeviceAllow= + DevicePolicy= + DisableControllers= ++FreezerAccounting= ++FreezerState= + IOAccounting= + IODeviceLatencyTargetSec= + IODeviceWeight= +diff --git a/test/fuzz/fuzz-unit-file/directives.socket b/test/fuzz/fuzz-unit-file/directives.socket +index aa9e758..6fb1e5f 100644 +--- a/test/fuzz/fuzz-unit-file/directives.socket ++++ b/test/fuzz/fuzz-unit-file/directives.socket +@@ -59,6 +59,8 @@ FileDescriptorName= + FinalKillSignal= + FlushPending= + FreeBind= ++FreezerAccounting= ++FreezerState= + Group= + IOAccounting= + IODeviceLatencyTargetSec= +diff --git a/test/fuzz/fuzz-unit-file/directives.swap b/test/fuzz/fuzz-unit-file/directives.swap +index bc07775..6ca6198 100644 +--- a/test/fuzz/fuzz-unit-file/directives.swap ++++ b/test/fuzz/fuzz-unit-file/directives.swap +@@ -45,6 +45,8 @@ EnvironmentFile= + ExecPaths= + ExtensionImages= + FinalKillSignal= ++FreezerAccounting= ++FreezerState= + Group= + IOAccounting= + IODeviceLatencyTargetSec= +-- +2.23.0 + diff --git a/core-cgroup-support-memorysw.patch b/core-cgroup-support-memorysw.patch new file mode 100644 index 0000000000000000000000000000000000000000..5b2141d951323010b66d1490c0df1ea1d492334d --- /dev/null +++ b/core-cgroup-support-memorysw.patch @@ -0,0 +1,263 @@ +From cfb8a3cf09d9a958388ca1181bb92d9f77ab100e Mon Sep 17 00:00:00 2001 +From: licunlong +Date: Thu, 6 May 2021 09:38:54 +0800 +Subject: [PATCH] core-cgroup: support memorysw + +Upstream systemd dosen't support setting memory.memsw.limit_in_bytes. +This patch enables setting memory.memsw.limit_in_bytes by MemoryMemswLimit. +--- + src/core/cgroup.c | 17 +++++++++++++++-- + src/core/cgroup.h | 1 + + src/core/dbus-cgroup.c | 4 ++++ + src/core/load-fragment-gperf.gperf.in | 1 + + src/core/load-fragment.c | 2 ++ + src/shared/bus-print-properties.c | 2 +- + src/shared/bus-unit-util.c | 1 + + test/fuzz/fuzz-unit-file/directives-all.service | 1 + + test/fuzz/fuzz-unit-file/directives.mount | 1 + + test/fuzz/fuzz-unit-file/directives.scope | 1 + + test/fuzz/fuzz-unit-file/directives.service | 1 + + test/fuzz/fuzz-unit-file/directives.slice | 1 + + test/fuzz/fuzz-unit-file/directives.socket | 1 + + test/fuzz/fuzz-unit-file/directives.swap | 1 + + 14 files changed, 32 insertions(+), 3 deletions(-) + +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index d9b1d9b..4eedaf7 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -125,6 +125,7 @@ void cgroup_context_init(CGroupContext *c) { + .memory_swap_max = CGROUP_LIMIT_MAX, + + .memory_limit = CGROUP_LIMIT_MAX, ++ .memory_memsw_limit = CGROUP_LIMIT_MAX, + + .io_weight = CGROUP_WEIGHT_INVALID, + .startup_io_weight = CGROUP_WEIGHT_INVALID, +@@ -454,6 +455,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { + "%sMemoryMax: %" PRIu64 "%s\n" + "%sMemorySwapMax: %" PRIu64 "%s\n" + "%sMemoryLimit: %" PRIu64 "\n" ++ "%sMemoryMemswLimit=%" PRIu64 "\n" + "%sCPUSetCpus=%s\n" + "%sCPUSetMems=%s\n" + "%sCPUSetCloneChildren=%s\n" +@@ -495,6 +497,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { + prefix, c->memory_max, format_cgroup_memory_limit_comparison(cdd, sizeof(cdd), u, "MemoryMax"), + prefix, c->memory_swap_max, format_cgroup_memory_limit_comparison(cde, sizeof(cde), u, "MemorySwapMax"), + prefix, c->memory_limit, ++ prefix, c->memory_memsw_limit, + prefix, c->cpuset_cpus, + prefix, c->cpuset_mems, + prefix, yes_no(c->cpuset_clone_children), +@@ -1484,13 +1487,16 @@ static void cgroup_context_apply( + + } else { + char buf[DECIMAL_STR_MAX(uint64_t) + 1]; +- uint64_t val; ++ uint64_t val, sw_val; + + if (unit_has_unified_memory_config(u)) { + val = c->memory_max; ++ sw_val = CGROUP_LIMIT_MAX; + log_cgroup_compat(u, "Applying MemoryMax=%" PRIi64 " as MemoryLimit=", val); +- } else ++ } else { + val = c->memory_limit; ++ sw_val = c->memory_memsw_limit; ++ } + + if (val == CGROUP_LIMIT_MAX) + strncpy(buf, "-1\n", sizeof(buf)); +@@ -1498,6 +1504,12 @@ static void cgroup_context_apply( + xsprintf(buf, "%" PRIu64 "\n", val); + + (void) set_attribute_and_warn(u, "memory", "memory.limit_in_bytes", buf); ++ ++ if (sw_val == CGROUP_LIMIT_MAX) ++ strncpy(buf, "-1\n", sizeof(buf)); ++ else ++ xsprintf(buf, "%" PRIu64 "\n", sw_val); ++ (void) set_attribute_and_warn(u, "memory", "memory.memsw.limit_in_bytes", buf); + } + } + +@@ -1679,6 +1691,7 @@ static CGroupMask unit_get_cgroup_mask(Unit *u) { + + if (c->memory_accounting || + c->memory_limit != CGROUP_LIMIT_MAX || ++ c->memory_memsw_limit != CGROUP_LIMIT_MAX || + unit_has_unified_memory_config(u)) + mask |= CGROUP_MASK_MEMORY; + +diff --git a/src/core/cgroup.h b/src/core/cgroup.h +index 9177415..1a36c2d 100644 +--- a/src/core/cgroup.h ++++ b/src/core/cgroup.h +@@ -177,6 +177,7 @@ struct CGroupContext { + LIST_HEAD(CGroupBlockIODeviceBandwidth, blockio_device_bandwidths); + + uint64_t memory_limit; ++ uint64_t memory_memsw_limit; + + CGroupDevicePolicy device_policy; + LIST_HEAD(CGroupDeviceAllow, device_allow); +diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c +index 509ae4f..a200710 100644 +--- a/src/core/dbus-cgroup.c ++++ b/src/core/dbus-cgroup.c +@@ -440,6 +440,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = { + SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0), + SD_BUS_PROPERTY("MemorySwapMax", "t", NULL, offsetof(CGroupContext, memory_swap_max), 0), + SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0), ++ SD_BUS_PROPERTY("MemoryMemswLimit", "t", NULL, offsetof(CGroupContext, memory_memsw_limit), 0), + SD_BUS_PROPERTY("CPUSetAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpuset_accounting), 0), + SD_BUS_PROPERTY("CPUSetCpus", "s", NULL, offsetof(CGroupContext, cpuset_cpus), 0), + SD_BUS_PROPERTY("CPUSetMems", "s", NULL, offsetof(CGroupContext, cpuset_mems), 0), +@@ -1032,6 +1033,9 @@ int bus_cgroup_set_property( + if (streq(name, "MemoryLimit")) + return bus_cgroup_set_memory(u, name, &c->memory_limit, message, flags, error); + ++ if (streq(name, "MemoryMemswLimit")) ++ return bus_cgroup_set_memory(u, name, &c->memory_memsw_limit, message, flags, error); ++ + if (streq(name, "MemoryMinScale")) { + r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, message, flags, error); + if (r > 0) +diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in +index 5b7ecd2..0702aa0 100644 +--- a/src/core/load-fragment-gperf.gperf.in ++++ b/src/core/load-fragment-gperf.gperf.in +@@ -197,6 +197,7 @@ + {{type}}.MemoryMax, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context) + {{type}}.MemorySwapMax, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context) + {{type}}.MemoryLimit, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context) ++{{type}}.MemoryMemswLimit, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context) + {{type}}.CPUSetAccounting, config_parse_bool, 0, offsetof({{type}}, cgroup_context.cpuset_accounting) + {{type}}.CPUSetCpus, config_parse_cpuset_cpumems, 0, offsetof({{type}}, cgroup_context.cpuset_cpus) + {{type}}.CPUSetMems, config_parse_cpuset_cpumems, 0, offsetof({{type}}, cgroup_context.cpuset_mems) +diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c +index 1fb097d..a2ad32b 100644 +--- a/src/core/load-fragment.c ++++ b/src/core/load-fragment.c +@@ -3716,6 +3716,8 @@ int config_parse_memory_limit( + c->memory_swap_max = bytes; + else if (streq(lvalue, "MemoryLimit")) + c->memory_limit = bytes; ++ else if (streq(lvalue, "MemoryMemswLimit")) ++ c->memory_memsw_limit = bytes; + else + return -EINVAL; + +diff --git a/src/shared/bus-print-properties.c b/src/shared/bus-print-properties.c +index b459219..a16aca8 100644 +--- a/src/shared/bus-print-properties.c ++++ b/src/shared/bus-print-properties.c +@@ -165,7 +165,7 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b + + bus_print_property_value(name, expected_value, flags, "[not set]"); + +- else if ((STR_IN_SET(name, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "MemoryAvailable") && u == CGROUP_LIMIT_MAX) || ++ else if ((STR_IN_SET(name, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "MemoryMemswLimit", "MemoryAvailable") && u == CGROUP_LIMIT_MAX) || + (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == UINT64_MAX) || + (startswith(name, "Limit") && u == UINT64_MAX) || + (startswith(name, "DefaultLimit") && u == UINT64_MAX)) +diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c +index f20fcbf..b4b04e1 100644 +--- a/src/shared/bus-unit-util.c ++++ b/src/shared/bus-unit-util.c +@@ -521,6 +521,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons + "MemoryMax", + "MemorySwapMax", + "MemoryLimit", ++ "MemoryMemswLimit", + "TasksMax")) { + + if (streq(eq, "infinity")) { +diff --git a/test/fuzz/fuzz-unit-file/directives-all.service b/test/fuzz/fuzz-unit-file/directives-all.service +index 1cd161d..208c33b 100644 +--- a/test/fuzz/fuzz-unit-file/directives-all.service ++++ b/test/fuzz/fuzz-unit-file/directives-all.service +@@ -158,6 +158,7 @@ MemoryHigh= + MemoryLimit= + MemoryLow= + MemoryMax= ++MemoryMemswLimit= + MemorySwapMax= + MessageQueueMaxMessages= + MessageQueueMessageSize= +diff --git a/test/fuzz/fuzz-unit-file/directives.mount b/test/fuzz/fuzz-unit-file/directives.mount +index 53c035a..0c3cd57 100644 +--- a/test/fuzz/fuzz-unit-file/directives.mount ++++ b/test/fuzz/fuzz-unit-file/directives.mount +@@ -109,6 +109,7 @@ MemoryLimit= + MemoryLow= + MemoryMax= + MemoryMin= ++MemoryMemswLimit= + MemorySwapMax= + MountAPIVFS= + MountFlags= +diff --git a/test/fuzz/fuzz-unit-file/directives.scope b/test/fuzz/fuzz-unit-file/directives.scope +index 1dd6c60..36a60f6 100644 +--- a/test/fuzz/fuzz-unit-file/directives.scope ++++ b/test/fuzz/fuzz-unit-file/directives.scope +@@ -52,6 +52,7 @@ MemoryLimit= + MemoryLow= + MemoryMax= + MemoryMin= ++MemoryMemswLimit= + MemorySwapMax= + NetClass= + RestartKillSignal= +diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service +index a5f7f07..8044977 100644 +--- a/test/fuzz/fuzz-unit-file/directives.service ++++ b/test/fuzz/fuzz-unit-file/directives.service +@@ -231,6 +231,7 @@ MemoryLimit= + MemoryLow= + MemoryMax= + MemoryMin= ++MemoryMemswLimit= + MemorySwapMax= + MountAPIVFS= + MountFlags= +diff --git a/test/fuzz/fuzz-unit-file/directives.slice b/test/fuzz/fuzz-unit-file/directives.slice +index 2328a24..097ff4e 100644 +--- a/test/fuzz/fuzz-unit-file/directives.slice ++++ b/test/fuzz/fuzz-unit-file/directives.slice +@@ -49,6 +49,7 @@ MemoryLimit= + MemoryLow= + MemoryMax= + MemoryMin= ++MemoryMemswLimit= + MemorySwapMax= + NetClass= + Slice= +diff --git a/test/fuzz/fuzz-unit-file/directives.socket b/test/fuzz/fuzz-unit-file/directives.socket +index 6fb1e5f..c372f1e 100644 +--- a/test/fuzz/fuzz-unit-file/directives.socket ++++ b/test/fuzz/fuzz-unit-file/directives.socket +@@ -137,6 +137,7 @@ MemoryLimit= + MemoryLow= + MemoryMax= + MemoryMin= ++MemoryMemswLimit= + MemorySwapMax= + MessageQueueMaxMessages= + MessageQueueMessageSize= +diff --git a/test/fuzz/fuzz-unit-file/directives.swap b/test/fuzz/fuzz-unit-file/directives.swap +index 6ca6198..a46164e 100644 +--- a/test/fuzz/fuzz-unit-file/directives.swap ++++ b/test/fuzz/fuzz-unit-file/directives.swap +@@ -106,6 +106,7 @@ MemoryLimit= + MemoryLow= + MemoryMax= + MemoryMin= ++MemoryMemswLimit= + MemorySwapMax= + MountAPIVFS= + MountFlags= +-- +2.23.0 + diff --git a/delete-journal-files-except-system.journal-when-jour.patch b/delete-journal-files-except-system.journal-when-jour.patch new file mode 100644 index 0000000000000000000000000000000000000000..bb57e4e701ceae6c6b8c59cbdebd61e86f439e99 --- /dev/null +++ b/delete-journal-files-except-system.journal-when-jour.patch @@ -0,0 +1,186 @@ +From 02d47bd2108d46cf9790500a7568a7523df485f9 Mon Sep 17 00:00:00 2001 +From: xujing +Date: Fri, 26 Aug 2022 20:32:37 +0800 +Subject: [PATCH] delete journal files except system.journal when journal~ + is generated + +In the case of time change and system panic, the function of invoking +sd_journal_next to obtain logs may not meet expectations(rsyslog cannot obtain +logs). Therefore, when the journal~ file is generated, delete all journal files +except system.journal, to ensure that the sd_journal_next function meets user +expectations. +--- + meson.build | 2 ++ + src/basic/dirent-util.c | 24 ++++++++++++++++ + src/basic/dirent-util.h | 2 ++ + src/libsystemd/sd-journal/journal-file.c | 35 ++++++++++++++++++++++++ + src/libsystemd/sd-journal/sd-journal.c | 22 --------------- + 5 files changed, 63 insertions(+), 22 deletions(-) + +diff --git a/meson.build b/meson.build +index 278e264..9ab40b6 100644 +--- a/meson.build ++++ b/meson.build +@@ -1644,6 +1644,8 @@ basic_includes = include_directories( + 'src/basic', + 'src/fundamental', + 'src/systemd', ++ 'src/libsystemd/sd-id128', ++ 'src/libsystemd/sd-journal', + '.') + + libsystemd_includes = [basic_includes, include_directories( +diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c +index f6213a3..b227cae 100644 +--- a/src/basic/dirent-util.c ++++ b/src/basic/dirent-util.c +@@ -6,6 +6,8 @@ + #include "dirent-util.h" + #include "path-util.h" + #include "string-util.h" ++#include "id128-util.h" ++#include "syslog-util.h" + + static int dirent_ensure_type(DIR *d, struct dirent *de) { + struct stat st; +@@ -59,6 +61,28 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { + return endswith(de->d_name, suffix); + } + ++bool dirent_is_journal_subdir(const struct dirent *de) { ++ const char *e, *n; ++ assert(de); ++ ++ /* returns true if the specified directory entry looks like a directory that might contain journal ++ * files we might be interested in, i.e. is either a 128bit ID or a 128bit ID suffixed by a ++ * namespace. */ ++ ++ if (!IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN)) ++ return false; ++ ++ e = strchr(de->d_name, '.'); ++ if (!e) ++ return id128_is_valid(de->d_name); /* No namespace */ ++ ++ n = strndupa(de->d_name, e - de->d_name); ++ if (!id128_is_valid(n)) ++ return false; ++ ++ return log_namespace_name_valid(e + 1); ++} ++ + struct dirent *readdir_ensure_type(DIR *d) { + struct dirent *de; + +diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h +index c7956e7..f72a731 100644 +--- a/src/basic/dirent-util.h ++++ b/src/basic/dirent-util.h +@@ -11,6 +11,8 @@ + bool dirent_is_file(const struct dirent *de) _pure_; + bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_; + ++bool dirent_is_journal_subdir(const struct dirent *de); ++ + struct dirent *readdir_ensure_type(DIR *d); + struct dirent *readdir_no_dot(DIR *dirp); + +diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c +index 6807c46..0abda23 100644 +--- a/src/libsystemd/sd-journal/journal-file.c ++++ b/src/libsystemd/sd-journal/journal-file.c +@@ -33,6 +33,7 @@ + #include "string-util.h" + #include "strv.h" + #include "xattr-util.h" ++#include "dirent-util.h" + + #define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*sizeof(HashItem)) + #define DEFAULT_FIELD_HASH_TABLE_SIZE (333ULL*sizeof(HashItem)) +@@ -3781,9 +3782,37 @@ int journal_file_rotate( + return r; + } + ++static void delete_dumped_journal_files(const char *path) { ++ _cleanup_closedir_ DIR *d = NULL; ++ struct dirent *de; ++ ++ d = opendir(path); ++ if (!d) ++ return; ++ ++ FOREACH_DIRENT_ALL(de, d, return) { ++ if (IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN) && ++ (endswith(de->d_name, ".journal") || ++ endswith(de->d_name, ".journal~")) && ++ strcmp(de->d_name, "system.journal") != 0) ++ (void) unlinkat_deallocate(dirfd(d), de->d_name, 0); ++ ++ if (dirent_is_journal_subdir(de)) { ++ _cleanup_free_ char *sub_path = NULL; ++ ++ sub_path = path_join(path, de->d_name); ++ if (!sub_path) ++ continue; ++ ++ delete_dumped_journal_files(sub_path); ++ } ++ } ++} ++ + int journal_file_dispose(int dir_fd, const char *fname) { + _cleanup_free_ char *p = NULL; + _cleanup_close_ int fd = -1; ++ dual_timestamp boot_timestamp; + + assert(fname); + +@@ -3804,6 +3833,12 @@ int journal_file_dispose(int dir_fd, const char *fname) { + if (renameat(dir_fd, fname, dir_fd, p) < 0) + return -errno; + ++ dual_timestamp_get(&boot_timestamp); ++ if (boot_timestamp.monotonic < 10*USEC_PER_MINUTE) { ++ delete_dumped_journal_files("/var/log/journal"); ++ return 0; ++ } ++ + /* btrfs doesn't cope well with our write pattern and fragments heavily. Let's defrag all files we rotate */ + fd = openat(dir_fd, p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) +diff --git a/src/libsystemd/sd-journal/sd-journal.c b/src/libsystemd/sd-journal/sd-journal.c +index 1a76bb6..56e1398 100644 +--- a/src/libsystemd/sd-journal/sd-journal.c ++++ b/src/libsystemd/sd-journal/sd-journal.c +@@ -1523,28 +1523,6 @@ static bool dirent_is_journal_file(const struct dirent *de) { + endswith(de->d_name, ".journal~"); + } + +-static bool dirent_is_journal_subdir(const struct dirent *de) { +- const char *e, *n; +- assert(de); +- +- /* returns true if the specified directory entry looks like a directory that might contain journal +- * files we might be interested in, i.e. is either a 128bit ID or a 128bit ID suffixed by a +- * namespace. */ +- +- if (!IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN)) +- return false; +- +- e = strchr(de->d_name, '.'); +- if (!e) +- return id128_is_valid(de->d_name); /* No namespace */ +- +- n = strndupa(de->d_name, e - de->d_name); +- if (!id128_is_valid(n)) +- return false; +- +- return log_namespace_name_valid(e + 1); +-} +- + static int directory_open(sd_journal *j, const char *path, DIR **ret) { + DIR *d; + +-- +2.23.0 + diff --git a/fix-mount-failed-while-daemon-reexec.patch b/fix-mount-failed-while-daemon-reexec.patch new file mode 100644 index 0000000000000000000000000000000000000000..906483f45a2344467303bdaf822dd6a2ce39dad7 --- /dev/null +++ b/fix-mount-failed-while-daemon-reexec.patch @@ -0,0 +1,61 @@ +From e485f8a182f8a141676f7ffe0311a1a4724c3c1a Mon Sep 17 00:00:00 2001 +From: licunlong +Date: Tue, 28 Jun 2022 21:56:26 +0800 +Subject: [PATCH] fix mount failed while daemon-reexec + +--- + src/core/manager.c | 1 + + src/core/manager.h | 1 + + src/core/mount.c | 5 ++++- + 3 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/src/core/manager.c b/src/core/manager.c +index 5dff366..45c4ae0 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -1762,6 +1762,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { + } + + manager_ready(m); ++ m->mountinfo_uptodate = false; + + return 0; + } +diff --git a/src/core/manager.h b/src/core/manager.h +index cf6cd64..663fe8d 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -238,6 +238,7 @@ struct Manager { + /* Data specific to the mount subsystem */ + struct libmnt_monitor *mount_monitor; + sd_event_source *mount_event_source; ++ bool mountinfo_uptodate; + + /* Data specific to the swap filesystem */ + FILE *proc_swaps; +diff --git a/src/core/mount.c b/src/core/mount.c +index 6e514d5..25b0460 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -1684,6 +1684,7 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) { + (void) mount_setup_unit(m, device, path, options, fstype, set_flags); + } + ++ m->mountinfo_uptodate = true; + return 0; + } + +@@ -1842,8 +1843,10 @@ static int mount_process_proc_self_mountinfo(Manager *m) { + assert(m); + + r = drain_libmount(m); +- if (r <= 0) ++ if (r < 0) + return r; ++ if (r == 0 && m->mountinfo_uptodate) ++ return 0; + + r = mount_load_proc_self_mountinfo(m, true); + if (r < 0) { +-- +2.33.0 diff --git a/fuser-print-umount-message-to-reboot-umount-msg.patch b/fuser-print-umount-message-to-reboot-umount-msg.patch new file mode 100644 index 0000000000000000000000000000000000000000..734396c54aced9b7c424e60aceae14ac11a54ae2 --- /dev/null +++ b/fuser-print-umount-message-to-reboot-umount-msg.patch @@ -0,0 +1,225 @@ +From 224b51420b0e3b62cda4bb16f31c6d28e96c7123 Mon Sep 17 00:00:00 2001 +From: sunshihao +Date: Mon, 25 Jan 2021 14:42:23 +0800 +Subject: [PATCH] fuser: print umount info to /.reboot-umount-msg.log + +The patch tries to save which processes holds the mountpoint +persistently to /.reboot-umount-msg.log, when the system is +suspended during system restart. + +This patch change the value of DefaultDFXReboot that is set in +/etc/systemd/system.conf file from no to yes.The systemd reboot +feature will open when the process start. + +Signed-off-by: sunshihao +Signed-off-by: Zhiqiang Liu +Signed-off-by: lixiaokeng +--- + src/core/fuser.c | 57 +++++++++++++++++++++++++++++++++++++---- + src/core/fuser.h | 3 +++ + src/core/job.c | 38 +++++++++++++++++++++++++++ + src/core/system.conf.in | 2 +- + 4 files changed, 94 insertions(+), 6 deletions(-) + +diff --git a/src/core/fuser.c b/src/core/fuser.c +index 0a0c791..dd2ca60 100644 +--- a/src/core/fuser.c ++++ b/src/core/fuser.c +@@ -383,6 +383,8 @@ static void print_matches(const struct name *name) { + static char P_cmd_long[MAX_COMM_LEN]; + char cmd_path[PATH_MAX]; + int r = 0; ++ FILE *fp = NULL; ++ int flag = 0; + + if (name == NULL) { + manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, +@@ -390,11 +392,29 @@ static void print_matches(const struct name *name) { + return; + } + ++ /* Write the content in the back of previous one */ ++ fp = fopen(REBOOT_UMOUNT_FILE_NAME, "a+"); ++ ++ /* print the time info to /.reboot-umount-msg.log file */ ++ if (fp == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Open %s failed!", REBOOT_UMOUNT_FILE_NAME); ++ } ++ + manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, + "\t\tUSER\t\tPID\tCOMMAND"); + manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, + "%s:", name->filename); + ++ /* print the umount fail point to the /.reboot-umount-msg.log file */ ++ if (fp != NULL) { ++ if (strlen(name->filename) <= MOUNT_FILE_NAME_MAX_LEN) { ++ fprintf(fp, "%-20s\t", name->filename); ++ } else { ++ fprintf(fp, "%s\n\t\t\t", name->filename); ++ } ++ } ++ + for (pptr = name->matched_procs; pptr != NULL; pptr = pptr->next) { + if (pwent == NULL || pwent->pw_uid != pptr->uid) + pwent = getpwuid(pptr->uid); //get username +@@ -402,7 +422,7 @@ static void print_matches(const struct name *name) { + r = snprintf(cmd_path, sizeof(cmd_path), "/proc/%d", pptr->pid); + if (r <= 0) { + manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Can't snprintf /proc/%d.", pptr->pid); +- return; ++ goto out; + } + + read_cmdline(P_cmd_long, sizeof(P_cmd_long), cmd_path, "cmdline", ' '); +@@ -415,22 +435,49 @@ static void print_matches(const struct name *name) { + if (pptr->command == NULL) + continue; + ++ if (flag > 0) { ++ if (fp != NULL) { ++ fprintf(fp, "\t\t\t"); ++ } ++ } else { ++ flag++; ++ } ++ + if (pwent != NULL) { +- if (pptr->pid != 0) ++ if (pptr->pid != 0) { + manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, + "\t\t%-s\t\t%-d\t%-s", pwent->pw_name, pptr->pid, pptr->command); +- else ++ if (fp != NULL) { ++ fprintf(fp, "%-s\t\t%-d\t%-s\n", pwent->pw_name, pptr->pid, pptr->command); ++ } ++ } else { + manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, + "\t\t%-s\t\t%-s\t%-s", pwent->pw_name, "kernel", pptr->command); ++ if (fp != NULL) { ++ fprintf(fp, "%-s\t\t%-s\t%-s\n", pwent->pw_name, "kernel", pptr->command); ++ } ++ } + } else { +- if (pptr->pid != 0) ++ if (pptr->pid != 0) { + manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, + "\t\t%-d\t\t%-d\t%-s", pptr->uid, pptr->pid, pptr->command); +- else ++ if (fp != NULL) { ++ fprintf(fp, "%-d\t\t%-d\t%-s\n", pptr->uid, pptr->pid, pptr->command); ++ } ++ } else { + manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, + "\t\t%-d\t\t%-s\t%-s", pptr->uid, "kernel", pptr->command); ++ if (fp != NULL) { ++ fprintf(fp, "%-d\t\t%-s\t%-s\n", pptr->uid, "kernel", pptr->command); ++ } ++ } + } + } ++ ++out: ++ if (fp != NULL) { ++ fclose(fp); ++ } + } + + static void free_matched_procs(struct procs *matched_procs) { +diff --git a/src/core/fuser.h b/src/core/fuser.h +index b74b879..2729c9b 100644 +--- a/src/core/fuser.h ++++ b/src/core/fuser.h +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + #include "manager.h" + +@@ -51,5 +52,7 @@ struct device { + #define MAX_COMM_LEN 1024 + #define PROC_MOUNTS "/proc/mounts" + #define PROC_SWAPS "/proc/swaps" ++#define REBOOT_UMOUNT_FILE_NAME "/.reboot-umount-msg.log" ++#define MOUNT_FILE_NAME_MAX_LEN 20 + + int fuser(const char *dir); +diff --git a/src/core/job.c b/src/core/job.c +index 3645c11..7a0ed48 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -31,6 +31,8 @@ + #include "mount.h" + #include "process-util.h" + ++bool g_first_print = true; ++ + Job* job_new_raw(Unit *unit) { + Job *j; + +@@ -682,6 +684,9 @@ static void job_emit_done_message(Unit *u, uint32_t job_id, JobType t, JobResult + const char *ident, *format; + int r = 0; + pid_t pid; ++ FILE *fp = NULL; ++ time_t tmpt; ++ struct tm local_time; + + assert(u); + assert(t >= 0); +@@ -751,6 +756,39 @@ static void job_emit_done_message(Unit *u, uint32_t job_id, JobType t, JobResult + ((u->type == UNIT_MOUNT || u->type == UNIT_AUTOMOUNT) && t == JOB_STOP && result == JOB_FAILED)) { + + Mount *m = MOUNT(u); ++ if (g_first_print) { ++ /* Overwrite previous content at the first time */ ++ fp = fopen(REBOOT_UMOUNT_FILE_NAME, "w+"); ++ ++ /* Only get the local time once */ ++ tmpt = time(NULL); ++ if (!localtime_r(&tmpt, &local_time)) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Get local time failed!"); ++ } ++ } ++ ++ /* print the time info to /.reboot-umount-msg.log file */ ++ if (g_first_print && fp == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Open %s failed!", REBOOT_UMOUNT_FILE_NAME); ++ } else if (g_first_print) { ++ /* Only do this part one time */ ++ g_first_print = false; ++ ++ if (chmod(REBOOT_UMOUNT_FILE_NAME, S_IRUSR | S_IWUSR)) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Set %s file attributes failed!", REBOOT_UMOUNT_FILE_NAME); ++ } ++ ++ fprintf(fp, "reboot time is %d/%d/%d-%d:%d:%d.\n", local_time.tm_year + 1900, ++ local_time.tm_mon + 1, local_time.tm_mday, local_time.tm_hour, ++ local_time.tm_min, local_time.tm_sec); ++ ++ fprintf(fp, "\n\t\t\tUSER\t\tPID\tCOMMAND\n"); ++ fclose(fp); ++ } ++ + + r = safe_fork("(fuser-shutdown)", FORK_RESET_SIGNALS, &pid); + if (r < 0) { +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index cf34a12..d6cc751 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -74,4 +74,4 @@ DefaultLimitMEMLOCK=64M + #DefaultLimitRTPRIO= + #DefaultLimitRTTIME= + #DefaultOOMPolicy=stop +-#DefaultDFXReboot=no ++DefaultDFXReboot=yes +-- +2.27.0 + diff --git a/let-the-child-of-one-unit-don-t-affect-each-other.patch b/let-the-child-of-one-unit-don-t-affect-each-other.patch new file mode 100644 index 0000000000000000000000000000000000000000..f60169f8c92229a086db208deaf3130eef99eb7f --- /dev/null +++ b/let-the-child-of-one-unit-don-t-affect-each-other.patch @@ -0,0 +1,96 @@ +From 8c9de291f2b782f5d7d40447f08553b5e325a34d Mon Sep 17 00:00:00 2001 +From: licunlong +Date: Fri, 19 Mar 2021 01:29:01 +0800 +Subject: [PATCH] let the child of one unit don't affect each other. +This should only be used for .slice unit in the [Unit] section. +To reproduce the problem resolved by this patch, try the following steps: +1. start service A in a slice; +2. change the cgroup property by "echo 512 > service_a/cpu.shares"; +3. systemctl daemon-reload; +4. start service B in a slice; +5. check the cgroup property by "cat service_a/cpu.shares"; +With this directive enabled, the value will stay as 512; if disabled, +if will be restored to the default value of systemd. Defaults to "no". + +--- + src/core/cgroup.c | 3 +++ + src/core/load-fragment-gperf.gperf.in | 1 + + src/core/unit-serialize.c | 2 ++ + src/core/unit.h | 2 ++ + test/fuzz/fuzz-unit-file/directives.service | 1 + + 5 files changed, 9 insertions(+) + +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index 4eedaf7..ab6d602 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -2618,6 +2618,9 @@ void unit_add_family_to_cgroup_realize_queue(Unit *u) { + + UNIT_FOREACH_DEPENDENCY(m, u, UNIT_ATOM_SLICE_OF) { + ++ if (u->independent_child) ++ continue; ++ + /* No point in doing cgroup application for units without active processes. */ + if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(m))) + continue; +diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in +index 0702aa0..76b1217 100644 +--- a/src/core/load-fragment-gperf.gperf.in ++++ b/src/core/load-fragment-gperf.gperf.in +@@ -286,6 +286,7 @@ Unit.JoinsNamespaceOf, config_parse_unit_deps, + Unit.RequiresOverridable, config_parse_obsolete_unit_deps, UNIT_REQUIRES, 0 + Unit.RequisiteOverridable, config_parse_obsolete_unit_deps, UNIT_REQUISITE, 0 + Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, 0 ++Unit.IndependentChild, config_parse_bool, 0, offsetof(Unit, independent_child) + Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded) + Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start) + Unit.RefuseManualStop, config_parse_bool, 0, offsetof(Unit, refuse_manual_stop) +diff --git a/src/core/unit-serialize.c b/src/core/unit-serialize.c +index f3b3e70..b818181 100644 +--- a/src/core/unit-serialize.c ++++ b/src/core/unit-serialize.c +@@ -801,6 +801,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { + if (u->load_state == UNIT_LOADED) { + + fprintf(f, ++ "%s\tIndependentChild:%s\n" + "%s\tStopWhenUnneeded: %s\n" + "%s\tRefuseManualStart: %s\n" + "%s\tRefuseManualStop: %s\n" +@@ -808,6 +809,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { + "%s\tOnSuccessJobMode: %s\n" + "%s\tOnFailureJobMode: %s\n" + "%s\tIgnoreOnIsolate: %s\n", ++ prefix, yes_no(u->independent_child), + prefix, yes_no(u->stop_when_unneeded), + prefix, yes_no(u->refuse_manual_start), + prefix, yes_no(u->refuse_manual_stop), +diff --git a/src/core/unit.h b/src/core/unit.h +index cb85dfc..439714a 100644 +--- a/src/core/unit.h ++++ b/src/core/unit.h +@@ -350,6 +350,8 @@ typedef struct Unit { + sd_id128_t invocation_id; + char invocation_id_string[SD_ID128_STRING_MAX]; /* useful when logging */ + ++ bool independent_child; ++ + /* Garbage collect us we nobody wants or requires us anymore */ + bool stop_when_unneeded; + +diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service +index 8044977..03eab60 100644 +--- a/test/fuzz/fuzz-unit-file/directives.service ++++ b/test/fuzz/fuzz-unit-file/directives.service +@@ -98,6 +98,7 @@ RefuseManualStop= + ReloadPropagatedFrom= + Requires= + RequiresMountsFor= ++IndependentChild= + RequiresOverridable= + Requisite= + RequisiteOverridable= +-- +2.27.0 + diff --git a/print-the-process-status-to-console-when-shutdown.patch b/print-the-process-status-to-console-when-shutdown.patch new file mode 100644 index 0000000000000000000000000000000000000000..51b9839b65af6b1ea20b3f7b513082a2cb0a7278 --- /dev/null +++ b/print-the-process-status-to-console-when-shutdown.patch @@ -0,0 +1,1283 @@ +From 5966f7a3b90ee25f23182e9320621a8477a40a51 Mon Sep 17 00:00:00 2001 +From: jiangchuangang +Date: Thu, 2 Sep 2021 12:14:19 +0800 +Subject: [PATCH] print process status to console when shutdown + +--- + meson.build | 6 +- + src/basic/process-util.c | 58 ++++ + src/basic/process-util.h | 2 + + src/core/fuser.c | 506 +++++++++++++++++++++++++++++++++ + src/core/fuser.h | 55 ++++ + src/core/job.c | 36 +++ + src/core/main.c | 13 +- + src/core/manager.c | 1 + + src/core/manager.h | 2 + + src/core/meson.build | 2 + + src/core/system.conf.in | 1 + + src/shutdown/meson.build | 10 +- + src/shutdown/process-status.c | 143 ++++++++++ + src/shutdown/process-status.h | 24 ++ + src/shutdown/shutdown.c | 45 +++ + src/shutdown/umount.c | 8 +- + src/test/meson.build | 17 ++ + src/test/test-fuser.c | 14 + + src/test/test-process-status.c | 10 + + 19 files changed, 945 insertions(+), 8 deletions(-) + create mode 100644 src/core/fuser.c + create mode 100644 src/core/fuser.h + create mode 100644 src/shutdown/process-status.c + create mode 100644 src/shutdown/process-status.h + create mode 100644 src/test/test-fuser.c + create mode 100644 src/test/test-process-status.c + +diff --git a/meson.build b/meson.build +index 1c088ba..278e264 100644 +--- a/meson.build ++++ b/meson.build +@@ -3211,8 +3211,10 @@ public_programs += executable( + executable( + 'systemd-shutdown', + systemd_shutdown_sources, +- include_directories : includes, +- link_with : [libshared], ++ include_directories : [includes, ++ core_includes], ++ link_with : [libcore, ++ libshared], + dependencies : [libmount], + install_rpath : rootlibexecdir, + install : true, +diff --git a/src/basic/process-util.c b/src/basic/process-util.c +index 14259ea..e28412a 100644 +--- a/src/basic/process-util.c ++++ b/src/basic/process-util.c +@@ -1729,3 +1729,61 @@ static const char* const sched_policy_table[] = { + }; + + DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX); ++ ++unsigned int read_cmdline(char *restrict const dst, unsigned sz, const char* whom, const char *what, char sep) { ++ char path[PATH_MAX]; ++ _cleanup_close_ int fd = 0; ++ int len = 0; ++ unsigned n = 0; ++ ++ if (sz <= 0) ++ return 0; ++ ++ if (sz >= INT_MAX) ++ sz = INT_MAX-1; ++ ++ dst[0] = '\0'; ++ ++ len = snprintf(path, sizeof(path), "%s/%s", whom, what); ++ if (len <= 0 || (size_t)len >= sizeof(path)) ++ return 0; ++ ++ fd = open(path, O_RDONLY); ++ if (fd == -1) ++ return 0; ++ ++ for (;;) { ++ ssize_t r = read(fd, dst+n, sz-n); ++ ++ if (r == -1) { ++ if (errno == EINTR) ++ continue; ++ break; ++ } ++ ++ if (r <= 0) ++ break; ++ n += r; ++ ++ if (n == sz) { ++ --n; ++ break; ++ } ++ } ++ ++ if (n) { ++ unsigned i = n; ++ ++ while (i && dst[i-1] == '\0') ++ --i; ++ ++ while (i--) ++ if (dst[i] == '\n' || dst[i] == '\0') dst[i] = sep; ++ ++ if (dst[n-1] == ' ') ++ dst[n-1] = '\0'; ++ } ++ ++ dst[n] = '\0'; ++ return n; ++} +diff --git a/src/basic/process-util.h b/src/basic/process-util.h +index 0e064de..6f9b577 100644 +--- a/src/basic/process-util.h ++++ b/src/basic/process-util.h +@@ -205,3 +205,5 @@ int pidfd_get_pid(int fd, pid_t *ret); + int setpriority_closest(int priority); + + bool invoked_as(char *argv[], const char *token); ++ ++unsigned int read_cmdline(char *restrict const dst, unsigned sz, const char* whom, const char *what, char sep); +diff --git a/src/core/fuser.c b/src/core/fuser.c +new file mode 100644 +index 0000000..0a0c791 +--- /dev/null ++++ b/src/core/fuser.c +@@ -0,0 +1,506 @@ ++#include "fuser.h" ++#include "process-util.h" ++ ++static int parse_dir(struct name *this_name, struct inode *match_inode) { ++ if ((this_name == NULL) || (match_inode == NULL)) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Can't parse dir."); ++ return -1; ++ } ++ ++ if (stat(this_name->filename, &this_name->st) != 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Can't stat dir %s.", this_name->filename); ++ return -1; ++ } ++ ++ match_inode->name = this_name; ++ match_inode->device = this_name->st.st_dev; ++ match_inode->inode = this_name->st.st_ino; ++ ++ return 0; ++} ++ ++static int parse_mounts(struct name *this_name, struct device *match_device) { ++ if ((this_name == NULL) && (match_device == NULL)) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Can't parse mounts."); ++ return -1; ++ } ++ ++ match_device->name = this_name; ++ ++ if (S_ISBLK(this_name->st.st_mode)) ++ match_device->device = this_name->st.st_rdev; ++ else ++ match_device->device = this_name->st.st_dev; ++ ++ return 0; ++} ++ ++static uid_t getpiduid(const pid_t pid) { ++ char pathname[PATH_MAX]; ++ struct stat st; ++ int r = 0; ++ ++ r = snprintf(pathname, sizeof(pathname), "/proc/%d", pid); ++ if (r < 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Snprintf run failed in getpiduid."); ++ return 0; ++ } ++ ++ if (stat(pathname, &st) != 0) ++ return 0; ++ ++ return st.st_uid; ++} ++ ++static struct stat *get_pidstat(const pid_t pid) { ++ char pathname[PATH_MAX]; ++ struct stat *st = NULL; ++ int r = 0; ++ ++ st = (struct stat *)malloc(sizeof(struct stat)); ++ if (st == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Malloc failed in get_pidstat."); ++ return NULL; ++ } ++ ++ r = snprintf(pathname, sizeof(pathname), "/proc/%d/cwd", pid); ++ if (r < 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Snprintf run failed in get_pidstat."); ++ return NULL; ++ } ++ ++ if (stat(pathname, st) != 0) { ++ free(st); ++ return NULL; ++ } ++ ++ return st; ++} ++ ++static void add_matched_proc(struct name *name, const pid_t pid, const uid_t uid) { ++ struct procs *pptr = NULL; ++ struct procs *last_proc = NULL; ++ char pathname[PATH_MAX]; ++ char cmdname[CMD_NAME_LEN + 1]; ++ char *cptr = NULL; ++ int cmdlen = 0; ++ FILE *fp = NULL; ++ ++ if (name == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Name should not be NULL."); ++ return; ++ } ++ ++ //find out wheather the pid already in pptr->pid ++ for (pptr = name->matched_procs; pptr != NULL; pptr = pptr->next) { ++ last_proc = pptr; ++ ++ if (pptr->pid == pid) ++ return; ++ } ++ ++ pptr = (struct procs *)malloc(sizeof(struct procs)); ++ if (pptr == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Can't malloc in add_matched_proc."); ++ return; ++ } ++ ++ pptr->pid = pid; ++ pptr->uid = uid; ++ pptr->username = NULL; ++ pptr->next = NULL; ++ pptr->command = NULL; ++ ++ if ((snprintf(pathname, sizeof(pathname), "/proc/%d/stat", pid) > 0) && ++ ((fp = fopen(pathname, "r")) != NULL) && (fscanf(fp, "%*d (%100[^)]", cmdname) == 1)) { ++ pptr->command = (char *)malloc(COMM_LEN + 1); ++ ++ if (pptr->command != NULL) { ++ cmdlen = 0; ++ ++ for (cptr = cmdname; cmdlen < COMM_LEN && *cptr; cptr++) { ++ if (isprint(*cptr)) { ++ pptr->command[cmdlen++] = *cptr; ++ } else if (cmdlen < (COMM_LEN - 4)) { ++ cmdlen += sprintf(&(pptr->command[cmdlen]), "\\%03o", *cptr); ++ } ++ } ++ ++ pptr->command[cmdlen] = '\0'; ++ } ++ } ++ ++ if (last_proc == NULL) ++ name->matched_procs = pptr; ++ else ++ last_proc->next = pptr; ++ ++ if (fp) ++ fclose(fp); ++} ++ ++static void check_dir(const pid_t pid, const char *dirname, const struct device *dev, ++ const struct inode *ino, const uid_t uid) { ++ DIR *dirp = NULL; ++ dev_t thedev; ++ struct dirent *direntry = NULL; ++ struct stat st; ++ char dirpath[PATH_MAX]; ++ char filepath[PATH_MAX]; ++ int r = 0; ++ ++ if (dirname == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Dirname is NULL."); ++ return; ++ } ++ ++ r = snprintf(dirpath, sizeof(dirpath), "/proc/%d/%s", pid, dirname); ++ if (r < 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Snprintf run failed in check_dir."); ++ return; ++ } ++ ++ dirp = opendir(dirpath); ++ if (dirp == NULL) ++ return; ++ ++ while ((direntry = readdir(dirp)) != NULL) { ++ if (direntry->d_name[0] < '0' || direntry->d_name[0] > '9') ++ continue; ++ ++ snprintf(filepath, sizeof(filepath), "/proc/%d/%s/%s", ++ pid, dirname, direntry->d_name); ++ ++ if (stat(filepath, &st) != 0) ++ continue; ++ ++ thedev = st.st_dev; ++ ++ if ((dev != NULL) && (thedev == dev->device)) { ++ add_matched_proc(dev->name, pid, uid); ++ } ++ ++ if ((ino != NULL) && (thedev == ino->device)) { ++ if (st.st_ino == ino->inode) { ++ add_matched_proc(ino->name, pid, uid); ++ } ++ } ++ } //end while ++ ++ closedir(dirp); ++} ++ ++static int scan_procs(const struct name *name, const struct inode *ino, const struct device *dev) { ++ DIR *topproc_dir = NULL; ++ struct dirent *topproc_dent = NULL; ++ pid_t pid; ++ pid_t my_pid; ++ uid_t uid; ++ ++ if (name == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Name should not be null in scan_procs."); ++ return -1; ++ } ++ ++ if ((ino == NULL) && (dev == NULL)) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Ino and dev should not be NULL in scan_procs."); ++ return -1; ++ } ++ ++ topproc_dir = opendir("/proc"); ++ if (topproc_dir == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Can't open dir proc."); ++ return -1; ++ } ++ ++ my_pid = getpid(); ++ ++ while ((topproc_dent = readdir(topproc_dir)) != NULL) { ++ dev_t scan_dev; ++ struct stat *st = NULL; ++ ++ /* Not a process */ ++ if ((topproc_dent->d_name[0] < '0') || (topproc_dent->d_name[0] > '9')) ++ continue; ++ ++ pid = atoi(topproc_dent->d_name); ++ if (pid == my_pid) ++ continue; ++ ++ uid = getpiduid(pid); ++ ++ st = get_pidstat(pid); ++ scan_dev = st ? st->st_dev : 0; ++ ++ if ((dev != NULL) && (scan_dev == dev->device)) ++ add_matched_proc(dev->name, pid, uid); ++ ++ if ((ino != NULL) && (scan_dev == ino->device)) { ++ if (!st) ++ st = get_pidstat(pid); ++ ++ if (st && (st->st_dev == ino->device) && (st->st_ino == ino->inode)) ++ add_matched_proc(ino->name, pid, uid); ++ } ++ ++ if (st) ++ free(st); ++ ++ check_dir(pid, "fd", dev, ino, uid); ++ } // end while ++ ++ closedir(topproc_dir); ++ return 0; ++} ++ ++static void add_special_proc(struct name *name, const uid_t uid, const char *command) { ++ struct procs *pptr = NULL; ++ ++ if (name == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Name should not be null in add_special_proc."); ++ return; ++ } ++ ++ for (pptr = name->matched_procs; pptr != NULL; pptr = pptr->next) { ++ if (pptr->command != NULL && strcmp(pptr->command, command) == 0) ++ return; ++ } ++ ++ if ((pptr = malloc(sizeof(struct procs))) == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Can't allocate memory for add_special_proc() proc"); ++ return; ++ } ++ ++ pptr->pid = 0; ++ pptr->uid = uid; ++ pptr->next = name->matched_procs; ++ pptr->command = strdup(command); ++ ++ name->matched_procs = pptr; ++} ++ ++static void scan_mounts_and_swaps(const struct name *name, const struct inode *ino, ++ const struct device *dev, const char *file) { ++ FILE *fp = NULL; ++ char line[PATH_MAX]; ++ char *find_mountp = NULL; ++ char *find_space_mounts = NULL; ++ char *find_space_swaps = NULL; ++ struct stat st; ++ ++ if (name == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Name should not be null in scan_mounts_and_swaps."); ++ return; ++ } ++ ++ if ((ino == NULL) && (dev == NULL)) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Ino and dev should not be null in scan_mounts_and_swaps."); ++ return; ++ } ++ ++ fp = fopen(file, "r"); ++ if (fp == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Can't open file %s", file); ++ return; ++ } ++ ++ while (fgets(line, PATH_MAX, fp) != NULL) { ++ if (strcmp(file, PROC_MOUNTS) == 0) { ++ if ((find_mountp = strchr(line, ' ')) == NULL) ++ continue; ++ ++ find_mountp++; ++ ++ find_space_mounts = strchr(find_mountp, ' '); ++ if (find_space_mounts == NULL) ++ continue; ++ ++ *find_space_mounts = '\0'; ++ ++ if (stat(find_mountp, &st) != 0) ++ continue; ++ } else { ++ find_space_swaps = strchr(line, ' '); ++ if (find_space_swaps == NULL) ++ continue; ++ ++ *find_space_swaps = '\0'; ++ find_space_swaps++; ++ ++ while (*find_space_swaps == ' ') { ++ find_space_swaps++; ++ ++ if (*find_space_swaps == '\0') ++ continue; ++ } ++ ++ if (stat(line, &st) != 0) { ++ continue; ++ } ++ } ++ ++ if ((dev != NULL) && (st.st_dev == dev->device)) { ++ if (strcmp(file, PROC_MOUNTS) == 0) ++ add_special_proc(dev->name, 0, find_mountp); ++ ++ if (strcmp(file, PROC_SWAPS) == 0) ++ add_special_proc(dev->name, 0, line); ++ } ++ ++ if ((ino != NULL) && (st.st_dev == ino->device) && (st.st_ino == ino->inode)) { ++ if (strcmp(file, PROC_MOUNTS) == 0) ++ add_special_proc(ino->name, 0, find_mountp); ++ ++ if (strcmp(file, PROC_SWAPS) == 0) ++ add_special_proc(ino->name, 0, line); ++ } ++ } // end while ++ ++ fclose(fp); ++} ++ ++static void print_matches(const struct name *name) { ++ struct procs *pptr = NULL; ++ struct passwd *pwent = NULL; ++ static char P_cmd_long[MAX_COMM_LEN]; ++ char cmd_path[PATH_MAX]; ++ int r = 0; ++ ++ if (name == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Name should not be null in print_matches."); ++ return; ++ } ++ ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "\t\tUSER\t\tPID\tCOMMAND"); ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "%s:", name->filename); ++ ++ for (pptr = name->matched_procs; pptr != NULL; pptr = pptr->next) { ++ if (pwent == NULL || pwent->pw_uid != pptr->uid) ++ pwent = getpwuid(pptr->uid); //get username ++ ++ r = snprintf(cmd_path, sizeof(cmd_path), "/proc/%d", pptr->pid); ++ if (r <= 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Can't snprintf /proc/%d.", pptr->pid); ++ return; ++ } ++ ++ read_cmdline(P_cmd_long, sizeof(P_cmd_long), cmd_path, "cmdline", ' '); ++ ++ if (strlen(P_cmd_long) != 0){ ++ free(pptr->command); ++ pptr->command = strdup(P_cmd_long); ++ } ++ ++ if (pptr->command == NULL) ++ continue; ++ ++ if (pwent != NULL) { ++ if (pptr->pid != 0) ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "\t\t%-s\t\t%-d\t%-s", pwent->pw_name, pptr->pid, pptr->command); ++ else ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "\t\t%-s\t\t%-s\t%-s", pwent->pw_name, "kernel", pptr->command); ++ } else { ++ if (pptr->pid != 0) ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "\t\t%-d\t\t%-d\t%-s", pptr->uid, pptr->pid, pptr->command); ++ else ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "\t\t%-d\t\t%-s\t%-s", pptr->uid, "kernel", pptr->command); ++ } ++ } ++} ++ ++static void free_matched_procs(struct procs *matched_procs) { ++ struct procs *procs_tmp = NULL; ++ struct procs *procs_next = NULL; ++ ++ procs_tmp = matched_procs; ++ ++ while (procs_tmp != NULL) { ++ procs_next = procs_tmp->next; ++ ++ if (procs_tmp->command) ++ free(procs_tmp->command); ++ ++ free(procs_tmp); ++ ++ procs_tmp = procs_next; ++ } ++} ++ ++int fuser(const char *dir) { ++ struct name this_name; ++ struct inode match_inode; ++ struct device match_device; ++ int r = 0; ++ ++ if (dir == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Dir should not be NULL."); ++ return -1; ++ } ++ ++ this_name.matched_procs = NULL; ++ ++ this_name.filename = strdup(dir); //need to free ++ if (this_name.filename == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Can't allocate memory for fuser() this_name->filename."); ++ return -1; ++ } ++ ++ r = parse_dir(&this_name, &match_inode); ++ if (r < 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "%s", "Failed to parse file."); ++ free(this_name.filename); ++ return -1; ++ } ++ ++ r = parse_mounts(&this_name, &match_device); ++ if (r < 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "%s", "Failed to parse mounts."); ++ free(this_name.filename); ++ return -1; ++ } ++ ++ r = scan_procs(&this_name, &match_inode, &match_device); ++ if (r < 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "%s", "Failed to scan_procs."); ++ free(this_name.filename); ++ return -1; ++ } ++ ++ scan_mounts_and_swaps(&this_name, &match_inode, &match_device, PROC_MOUNTS); ++ scan_mounts_and_swaps(&this_name, &match_inode, &match_device, PROC_SWAPS); ++ print_matches(&this_name); ++ ++ free_matched_procs(this_name.matched_procs); ++ free(this_name.filename); ++ return 0; ++} +diff --git a/src/core/fuser.h b/src/core/fuser.h +new file mode 100644 +index 0000000..b74b879 +--- /dev/null ++++ b/src/core/fuser.h +@@ -0,0 +1,55 @@ ++#pragma once ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "manager.h" ++ ++struct procs { ++ pid_t pid; ++ uid_t uid; ++ char *username; ++ char *command; ++ struct procs *next; ++}; ++ ++struct name { ++ char *filename; ++ struct stat st; ++ struct procs *matched_procs; ++}; ++ ++struct inode { ++ struct name *name; ++ dev_t device; ++ ino_t inode; ++}; ++ ++struct device { ++ struct name *name; ++ dev_t device; ++}; ++ ++#ifndef PATH_MAX ++#define PATH_MAX 4096 ++#endif /* PATH_MAX */ ++ ++#define CMD_NAME_LEN 100 ++#define COMM_LEN 64 ++#define MAX_COMM_LEN 1024 ++#define PROC_MOUNTS "/proc/mounts" ++#define PROC_SWAPS "/proc/swaps" ++ ++int fuser(const char *dir); +diff --git a/src/core/job.c b/src/core/job.c +index eb6728a..3645c11 100644 +--- a/src/core/job.c ++++ b/src/core/job.c +@@ -27,6 +27,9 @@ + #include "terminal-util.h" + #include "unit.h" + #include "virt.h" ++#include "fuser.h" ++#include "mount.h" ++#include "process-util.h" + + Job* job_new_raw(Unit *unit) { + Job *j; +@@ -677,6 +680,8 @@ static const char* job_done_mid(JobType type, JobResult result) { + static void job_emit_done_message(Unit *u, uint32_t job_id, JobType t, JobResult result) { + _cleanup_free_ char *free_ident = NULL; + const char *ident, *format; ++ int r = 0; ++ pid_t pid; + + assert(u); + assert(t >= 0); +@@ -741,6 +746,37 @@ static void job_emit_done_message(Unit *u, uint32_t job_id, JobType t, JobResult + "See 'systemctl status %s' for details.", quoted); + } + } ++ ++ if (IN_SET(manager_state(u->manager), MANAGER_STOPPING) && u->manager->default_dfx_reboot && ++ ((u->type == UNIT_MOUNT || u->type == UNIT_AUTOMOUNT) && t == JOB_STOP && result == JOB_FAILED)) { ++ ++ Mount *m = MOUNT(u); ++ ++ r = safe_fork("(fuser-shutdown)", FORK_RESET_SIGNALS, &pid); ++ if (r < 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Failed to fork for fuser!"); ++ return; ++ } ++ if (r == 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "-------------fuser -mv %s----------------", m->where); ++ ++ r = fuser(m->where); ++ if (r < 0) ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Can't run fuser."); ++ ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "%s","----------------------------------------------------------------------"); ++ _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); ++ } ++ ++ r = wait_for_terminate_with_timeout(pid, 3 * USEC_PER_SEC); ++ if (r == -ETIMEDOUT) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Timeout to run (fuser-shutdown)."); ++ (void) kill(pid, SIGKILL); ++ } ++ } + } + + static int job_perform_on_unit(Job **j) { +diff --git a/src/core/main.c b/src/core/main.c +index 8de32a7..2a6b9b8 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -114,6 +114,7 @@ static bool arg_dump_core; + static int arg_crash_chvt; + static bool arg_crash_shell; + static bool arg_crash_reboot; ++static bool arg_default_dfx_reboot; + static char *arg_confirm_spawn; + static ShowStatus arg_show_status; + static StatusUnitFormat arg_status_unit_format; +@@ -645,6 +646,7 @@ static int parse_config_file(void) { + { "Manager", "CrashChangeVT", config_parse_crash_chvt, 0, &arg_crash_chvt }, + { "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell }, + { "Manager", "CrashReboot", config_parse_bool, 0, &arg_crash_reboot }, ++ { "Manager", "DefaultDFXReboot", config_parse_bool, 0, &arg_default_dfx_reboot }, + { "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status }, + { "Manager", "StatusUnitFormat", config_parse_status_unit_format, 0, &arg_status_unit_format }, + { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, &arg_cpu_affinity }, +@@ -756,6 +758,7 @@ static void set_manager_defaults(Manager *m) { + m->default_restart_usec = arg_default_restart_usec; + m->default_start_limit_interval = arg_default_start_limit_interval; + m->default_start_limit_burst = arg_default_start_limit_burst; ++ m->default_dfx_reboot = arg_default_dfx_reboot; + + /* On 4.15+ with unified hierarchy, CPU accounting is essentially free as it doesn't require the CPU + * controller to be enabled, so the default is to enable it unless we got told otherwise. */ +@@ -1473,18 +1476,20 @@ static int become_shutdown( + + char log_level[DECIMAL_STR_MAX(int) + 1], + exit_code[DECIMAL_STR_MAX(uint8_t) + 1], +- timeout[DECIMAL_STR_MAX(usec_t) + 1]; ++ timeout[DECIMAL_STR_MAX(usec_t) + 1], ++ dfx_reboot[DECIMAL_STR_MAX(bool)+1]; + +- const char* command_line[13] = { ++ const char* command_line[15] = { + SYSTEMD_SHUTDOWN_BINARY_PATH, + shutdown_verb, + "--timeout", timeout, + "--log-level", log_level, ++ "--dfx-reboot", dfx_reboot, + "--log-target", + }; + + _cleanup_strv_free_ char **env_block = NULL; +- size_t pos = 7; ++ size_t pos = 9; + int r; + usec_t watchdog_timer = 0; + +@@ -1494,6 +1499,7 @@ static int become_shutdown( + + xsprintf(log_level, "%d", log_get_max_level()); + xsprintf(timeout, "%" PRI_USEC "us", arg_default_timeout_stop_usec); ++ xsprintf(dfx_reboot, "%d", arg_default_dfx_reboot); + + switch (log_get_target()) { + +@@ -2325,6 +2331,7 @@ static void reset_arguments(void) { + arg_crash_chvt = -1; + arg_crash_shell = false; + arg_crash_reboot = false; ++ arg_default_dfx_reboot = false; + arg_confirm_spawn = mfree(arg_confirm_spawn); + arg_show_status = _SHOW_STATUS_INVALID; + arg_status_unit_format = STATUS_UNIT_FORMAT_DEFAULT; +diff --git a/src/core/manager.c b/src/core/manager.c +index 3a12d6d..29ef96b 100644 +--- a/src/core/manager.c ++++ b/src/core/manager.c +@@ -771,6 +771,7 @@ int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager + *m = (Manager) { + .unit_file_scope = scope, + .objective = _MANAGER_OBJECTIVE_INVALID, ++ .default_dfx_reboot = false, + + .status_unit_format = STATUS_UNIT_FORMAT_DEFAULT, + +diff --git a/src/core/manager.h b/src/core/manager.h +index dada79c..c20abd5 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -335,6 +335,8 @@ struct Manager { + /* Have we ever changed the "kernel.pid_max" sysctl? */ + bool sysctl_pid_max_changed; + ++ bool default_dfx_reboot; ++ + ManagerTestRunFlags test_run_flags; + + /* If non-zero, exit with the following value when the systemd +diff --git a/src/core/meson.build b/src/core/meson.build +index f0d2c6f..825eede 100644 +--- a/src/core/meson.build ++++ b/src/core/meson.build +@@ -127,6 +127,8 @@ libcore_sources = ''' + unit-serialize.h + unit.c + unit.h ++ fuser.c ++ fuser.h + '''.split() + + subdir('bpf/socket_bind') +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index dfc2477..cf34a12 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -74,3 +74,4 @@ DefaultLimitMEMLOCK=64M + #DefaultLimitRTPRIO= + #DefaultLimitRTTIME= + #DefaultOOMPolicy=stop ++#DefaultDFXReboot=no +diff --git a/src/shutdown/meson.build b/src/shutdown/meson.build +index e1348d9..12fbef3 100644 +--- a/src/shutdown/meson.build ++++ b/src/shutdown/meson.build +@@ -1,15 +1,21 @@ + # SPDX-License-Identifier: LGPL-2.1-or-later + ++shutdown_includes = [includes, include_directories('.')] ++ + systemd_shutdown_sources = files(''' + shutdown.c + umount.c + umount.h ++ process-status.c ++ process-status.h + '''.split()) + + tests += [ + [['src/shutdown/test-umount.c', + 'src/shutdown/umount.c', + 'src/shutdown/umount.h'], +- [], +- [libmount]], ++ [libshared, ++ libcore], ++ [libmount], ++ core_includes], + ] +diff --git a/src/shutdown/process-status.c b/src/shutdown/process-status.c +new file mode 100644 +index 0000000..11837a2 +--- /dev/null ++++ b/src/shutdown/process-status.c +@@ -0,0 +1,143 @@ ++#include "process-status.h" ++#include "process-util.h" ++ ++static uid_t P_uid; ++static int P_pid; ++static int P_ppid; ++static char P_stat[COMM_LEN]; ++static char P_cmd_short[COMM_LEN]; ++static char P_user[COMM_LEN]; ++static char P_cmd_long[COMM_LEN]; ++ ++static int read_from_stat(int pid) { ++ char buf[PATH_MAX]; ++ char cmd_path[PATH_MAX]; ++ char pathname[PATH_MAX]; ++ int fd = 0; ++ struct stat st; ++ int r = 0; ++ ++ memset(buf, 0, sizeof(buf)); ++ memset(cmd_path, 0, sizeof(cmd_path)); ++ memset(pathname, 0, sizeof(pathname)); ++ ++ r = snprintf(pathname, sizeof(pathname), "/proc/%d", pid); ++ if (r <= 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Can't snprintf /proc/%d.", pid); ++ return -1; ++ } ++ ++ if (stat(pathname, &st) != 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Can't stat %s.", pathname); ++ return -1; ++ } ++ ++ P_uid = st.st_uid; ++ ++ r = snprintf(buf, sizeof(buf), "/proc/%d/stat", pid); ++ if (r <= 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Can't snprintf /proc/%d/stat.", pid); ++ return -1; ++ } ++ ++ fd = open(buf, O_RDONLY, 0); ++ if (fd == -1) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Can't open %s.", buf); ++ return -1; ++ } ++ ++ r = read(fd, buf, sizeof(buf) - 1); ++ if (r < 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Can't read /proc/%d/stat.", pid); ++ close(fd); ++ return -1; ++ } ++ ++ r = sscanf(buf, "%d %s %s %d", &P_pid, P_cmd_short, P_stat, &P_ppid); ++ if (r < 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Can't run sscanf."); ++ close(fd); ++ return -1; ++ } ++ ++ close(fd); ++ ++ if(P_pid != pid) ++ return -1; ++ ++ r = snprintf(cmd_path, sizeof(cmd_path), "/proc/%d", pid); ++ if (r <= 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Can't snprintf /proc/%d.", pid); ++ return -1; ++ } ++ ++ /* read from /proc/$pid/cmdline */ ++ read_cmdline(P_cmd_long, sizeof(P_cmd_long), cmd_path, "cmdline", ' '); ++ ++ return 0; ++} ++ ++static void do_user(void) { ++ struct passwd *p = NULL; ++ ++ p = getpwuid(P_uid); ++ if (p) { ++ snprintf(P_user, sizeof(P_user), "%s", p->pw_name); ++ } else { ++ snprintf(P_user, sizeof(P_user), "%u", P_uid); ++ } ++} ++ ++static void print_proc(void) { ++ if ((P_ppid != KTHREADD) && (strcmp(P_cmd_short, "(kthreadd)") != 0)) { ++ if (strlen(P_cmd_long) != 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL,"systemd-shutdown", ++ "%-s\t%-d\t%-d\t%-s", P_user, P_pid, P_ppid, P_cmd_long); ++ } else { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL,"systemd-shutdown", ++ "%-s\t%-d\t%-d\t%-s", P_user, P_pid, P_ppid, P_cmd_short); ++ } ++ } ++} ++ ++int process_status(void) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL,"systemd-shutdown", ++ "%s", "-----------------------------------------------------------------"); ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL,"systemd-shutdown", ++ "%s", "USER\tPID\tPPID\tCMD"); ++ ++ struct dirent *ent = NULL; ++ DIR *dir = NULL; ++ ++ dir = opendir("/proc"); ++ if (dir == NULL) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL,"systemd-shutdown", ++ "%s", "can't open /proc"); ++ return -1; ++ } ++ ++ while((ent = readdir(dir))){ ++ if (*ent->d_name < '0' || *ent->d_name > '9') ++ continue; ++ ++ if (read_from_stat(atoi(ent->d_name)) != 0) ++ continue; ++ ++ do_user(); ++ ++ print_proc(); ++ } ++ ++ closedir(dir); ++ ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL,"systemd-shutdown", ++ "%s", "------------------------------------------------------------------"); ++ ++ return 0; ++} +diff --git a/src/shutdown/process-status.h b/src/shutdown/process-status.h +new file mode 100644 +index 0000000..2f4333d +--- /dev/null ++++ b/src/shutdown/process-status.h +@@ -0,0 +1,24 @@ ++#pragma once ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "manager.h" ++ ++#define COMM_LEN 512 ++ ++#ifndef PATH_MAX ++#define PATH_MAX 4096 ++#endif ++ ++#define KTHREADD 2 ++ ++int process_status(void); +diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c +index a98cfc4..1ad6fa0 100644 +--- a/src/shutdown/shutdown.c ++++ b/src/shutdown/shutdown.c +@@ -38,13 +38,17 @@ + #include "util.h" + #include "virt.h" + #include "watchdog.h" ++#include "process-status.h" + + #define SYNC_PROGRESS_ATTEMPTS 3 + #define SYNC_TIMEOUT_USEC (10*USEC_PER_SEC) ++#define SHUTDOWN_TIMEOUT_MIN (0*USEC_PER_SEC) ++#define SHUTDOWN_TIMEOUT_INTERVAL (30*USEC_PER_SEC) + + static char* arg_verb; + static uint8_t arg_exit_code; + static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC; ++static bool dfx_reboot = false; + + static int parse_argv(int argc, char *argv[]) { + enum { +@@ -55,6 +59,7 @@ static int parse_argv(int argc, char *argv[]) { + ARG_LOG_TIME, + ARG_EXIT_CODE, + ARG_TIMEOUT, ++ ARG_DFX_REBOOT, + }; + + static const struct option options[] = { +@@ -65,6 +70,7 @@ static int parse_argv(int argc, char *argv[]) { + { "log-time", optional_argument, NULL, ARG_LOG_TIME }, + { "exit-code", required_argument, NULL, ARG_EXIT_CODE }, + { "timeout", required_argument, NULL, ARG_TIMEOUT }, ++ { "dfx-reboot", required_argument, NULL, ARG_DFX_REBOOT }, + {} + }; + +@@ -78,6 +84,13 @@ static int parse_argv(int argc, char *argv[]) { + while ((c = getopt_long(argc, argv, "-", options, NULL)) >= 0) + switch (c) { + ++ case ARG_DFX_REBOOT: ++ if (streq(optarg, "1")) { ++ dfx_reboot = true; ++ } ++ ++ break; ++ + case ARG_LOG_LEVEL: + r = log_set_max_level_from_string(optarg); + if (r < 0) +@@ -313,6 +326,9 @@ int main(int argc, char *argv[]) { + char *arguments[3], *watchdog_device; + int cmd, r, umount_log_level = LOG_INFO; + static const char* const dirs[] = {SYSTEM_SHUTDOWN_PATH, NULL}; ++ usec_t now_time, time_interval; ++ pid_t pid; ++ bool fork_failed = false; + + /* The log target defaults to console, but the original systemd process will pass its log target in through a + * command line argument, which will override this default. Also, ensure we'll never log to the journal or +@@ -405,8 +421,37 @@ int main(int argc, char *argv[]) { + need_md_detach = !in_container; + can_initrd = !in_container && !in_initrd() && access("/run/initramfs/shutdown", X_OK) == 0; + ++ now_time = now(CLOCK_MONOTONIC); ++ time_interval = SHUTDOWN_TIMEOUT_MIN; + /* Unmount all mountpoints, swaps, and loopback devices */ + for (;;) { ++ if (dfx_reboot && (now(CLOCK_MONOTONIC) >= now_time + time_interval)) { ++ r = safe_fork("(process_status)", FORK_RESET_SIGNALS, &pid); ++ if (r < 0) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, ++ "Failed to fork for process_status!"); ++ fork_failed = true; ++ } ++ if (r == 0) { ++ r = process_status(); ++ if (r < 0) ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Can't run ps."); ++ ++ _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); ++ } ++ ++ now_time = now(CLOCK_MONOTONIC); ++ time_interval = SHUTDOWN_TIMEOUT_INTERVAL; ++ ++ if (!fork_failed) { ++ r = wait_for_terminate_with_timeout(pid, 3 * USEC_PER_SEC); ++ if (r == -ETIMEDOUT) { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Timeout to run (process_status)."); ++ (void) kill(pid, SIGKILL); ++ } ++ } ++ } ++ + bool changed = false; + + if (use_watchdog) +diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c +index c2a2624..1541bcc 100644 +--- a/src/shutdown/umount.c ++++ b/src/shutdown/umount.c +@@ -37,6 +37,7 @@ + #include "umount.h" + #include "util.h" + #include "virt.h" ++#include "manager.h" + + static void mount_point_free(MountPoint **head, MountPoint *m) { + assert(head); +@@ -553,6 +554,7 @@ static int umount_with_timeout(MountPoint *m, int umount_log_level) { + return r; + if (r == 0) { + log_info("Unmounting '%s'.", m->path); ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Unmounting '%s'.", m->path); + + /* Start the mount operation here in the child Using MNT_FORCE + * causes some filesystems (e.g. FUSE and NFS and other network +@@ -562,8 +564,12 @@ static int umount_with_timeout(MountPoint *m, int umount_log_level) { + * filesystem less busy so the unmount might succeed (rather + * than return EBUSY). */ + r = umount2(m->path, MNT_FORCE); +- if (r < 0) ++ if (r < 0) { + log_full_errno(umount_log_level, errno, "Failed to unmount %s: %m", m->path); ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Failed to unmount '%s'.", m->path); ++ } else { ++ manager_status_printf(NULL, STATUS_TYPE_NORMAL, NULL, "Unmounted '%s'.", m->path); ++ } + + _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); + } +diff --git a/src/test/meson.build b/src/test/meson.build +index 561386d..09c5298 100644 +--- a/src/test/meson.build ++++ b/src/test/meson.build +@@ -616,6 +616,23 @@ tests += [ + libshared], + [], + core_includes], ++ ++ [['src/test/test-process-status.c', ++ 'src/shutdown/process-status.c', ++ 'src/shutdown/process-status.h'], ++ [libcore, ++ libshared], ++ [], ++ [shutdown_includes, ++ core_includes]], ++ ++ [['src/test/test-fuser.c', ++ 'src/core/fuser.c', ++ 'src/core/fuser.h'], ++ [libcore, ++ libshared], ++ [], ++ core_includes], + ] + + ############################################################ +diff --git a/src/test/test-fuser.c b/src/test/test-fuser.c +new file mode 100644 +index 0000000..1527b5b +--- /dev/null ++++ b/src/test/test-fuser.c +@@ -0,0 +1,14 @@ ++#include "fuser.h" ++#include "tests.h" ++ ++int main(int argc, char *argv[]){ ++ test_setup_logging(LOG_DEBUG); ++ ++ assert_se(fuser("/") == 0); ++ assert_se(fuser(NULL) < 0); ++ assert_se(fuser("/dev") == 0); ++ assert_se(fuser("/dev/empty/mountpoint") < 0); ++ assert_se(fuser("") < 0); ++ ++ return 0; ++} +diff --git a/src/test/test-process-status.c b/src/test/test-process-status.c +new file mode 100644 +index 0000000..4a4c3da +--- /dev/null ++++ b/src/test/test-process-status.c +@@ -0,0 +1,10 @@ ++#include "process-status.h" ++#include "tests.h" ++ ++int main(int argc, char *argv[]){ ++ ++ assert_se(process_status() == 0); ++ ++ return 0; ++ ++} +-- +2.23.0 + diff --git a/process-util-log-more-information-when-runnin.patch b/process-util-log-more-information-when-runnin.patch new file mode 100644 index 0000000000000000000000000000000000000000..059ef8d7dbe5dbe05c16f4ae8f9a6f24601b037c --- /dev/null +++ b/process-util-log-more-information-when-runnin.patch @@ -0,0 +1,156 @@ +From f4b4008495211c60bda7e1edda45beb36a553bc7 Mon Sep 17 00:00:00 2001 +From: licunlong +Date: Thu, 14 Jan 2021 15:57:59 +0800 +Subject: [PATCH] process-util: log more information when running + systemctl. + + Print the PID and its cmdline to the system log when a process + runs systemctl command. +--- + src/basic/process-util.c | 31 +++++++++++++++++++++++++++++++ + src/basic/process-util.h | 1 + + src/systemctl/systemctl.c | 12 ++++++++++++ + src/test/test-process-util.c | 22 ++++++++++++++++++++++ + 4 files changed, 66 insertions(+) + +diff --git a/src/basic/process-util.c b/src/basic/process-util.c +index 5452edd..f137ba0 100644 +--- a/src/basic/process-util.c ++++ b/src/basic/process-util.c +@@ -42,6 +42,7 @@ + #include "stdio-util.h" + #include "string-table.h" + #include "string-util.h" ++#include "strv.h" + #include "terminal-util.h" + #include "user-util.h" + #include "utf8.h" +@@ -189,6 +190,36 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags + return 0; + } + ++int print_process_cmdline_with_arg(pid_t pid, int argc, char *argv[], char *filter[]) { ++ bool is_filtered = false; ++ int r; ++ const char *arg_cmdline = "["; ++ _cleanup_free_ char *cmdline = NULL; ++ ++ r = get_process_cmdline(pid, SIZE_MAX, 0, &cmdline); ++ if (r < 0) { ++ syslog(LOG_INFO, "Failed to get cmdline of PID %d. Ignoring.", pid); ++ return r; ++ } else { ++ for (int i = 0; i < argc; i++ ) { ++ if (filter && strv_find(filter, argv[i])) { ++ is_filtered = true; ++ break; ++ } ++ if (i == 0) { ++ arg_cmdline = strjoina(arg_cmdline, argv[i]); ++ } else { ++ arg_cmdline = strjoina(arg_cmdline, " ", argv[i]); ++ } ++ } ++ if (!is_filtered) { ++ syslog(LOG_INFO, "%s] called by PID %d (%s)", arg_cmdline, pid, cmdline); ++ } ++ return 0; ++ } ++ ++} ++ + static int update_argv(const char name[], size_t l) { + static int can_do = -1; + +diff --git a/src/basic/process-util.h b/src/basic/process-util.h +index 41d4759..4d8147e 100644 +--- a/src/basic/process-util.h ++++ b/src/basic/process-util.h +@@ -38,6 +38,7 @@ typedef enum ProcessCmdlineFlags { + + int get_process_comm(pid_t pid, char **name); + int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **line); ++int print_process_cmdline_with_arg(pid_t pid, int argc, char *argv[], char *filter[]); + int get_process_exe(pid_t pid, char **name); + int get_process_uid(pid_t pid, uid_t *uid); + int get_process_gid(pid_t pid, gid_t *gid); +diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c +index 1c01914..dd5bee9 100644 +--- a/src/systemctl/systemctl.c ++++ b/src/systemctl/systemctl.c +@@ -12,6 +12,7 @@ + + #include + #include ++#include + #include + + #include "sd-daemon.h" +@@ -9272,6 +9273,14 @@ static int logind_cancel_shutdown(void) { + + static int run(int argc, char *argv[]) { + int r; ++ pid_t ppid; ++ char *filter[] = { ++ "status", "show", "cat", ++ "is-active", "is-failed", "is-enabled", "is-system-running", ++ "list-units", "list-sockets", "list-timers", "list-dependencies", ++ "list-unit-files", "list-machines", "list-jobs", ++ "get-default", "show-environment", NULL ++ }; + + setlocale(LC_ALL, ""); + log_parse_environment(); +@@ -9291,6 +9300,9 @@ static int run(int argc, char *argv[]) { + if (r <= 0) + goto finish; + ++ ppid = getppid(); ++ (void) print_process_cmdline_with_arg(ppid, argc, argv, filter); ++ + if (arg_action != ACTION_SYSTEMCTL && running_in_chroot() > 0) { + if (!arg_quiet) + log_info("Running in chroot, ignoring request."); +diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c +index 8dc9fdd..1cb4ee2 100644 +--- a/src/test/test-process-util.c ++++ b/src/test/test-process-util.c +@@ -601,6 +601,27 @@ static void test_ioprio_class_from_to_string(void) { + } + } + ++static void test_print_process_cmdline_with_arg(pid_t pid) { ++ char *arg_filter_empty[] = {"", NULL}; ++ char *arg_filter_1_in[] = {"status", NULL}; ++ char *arg_filter_1_no[] = {"stop", NULL}; ++ char *arg_filter_2_in[] = {"restart", "status", NULL}; ++ char *arg_filter_2_no[] = {"restart", "stop", NULL}; ++ char *arg_var_1[1] = {"systemctl"}; ++ char *arg_var_10[10] = {"systemctl", "restart", "1", "2", "3", "4", "5", "6", "7", "8"}; ++ char *arg_var_filter[3] = {"systemctl", "status", "dbus.service"}; ++ assert_se(print_process_cmdline_with_arg(pid, 0, NULL, NULL) >=0); ++ assert_se(print_process_cmdline_with_arg(pid, 1, arg_var_1, NULL) >= 0); ++ assert_se(print_process_cmdline_with_arg(pid, 10, arg_var_10, NULL) >= 0); ++ assert_se(print_process_cmdline_with_arg(897349, 1, arg_var_1, NULL) < 0); ++ assert_se(print_process_cmdline_with_arg(897349, 10, arg_var_10, NULL) < 0); ++ assert_se(print_process_cmdline_with_arg(pid, 3, arg_var_filter, arg_filter_empty) >= 0); ++ assert_se(print_process_cmdline_with_arg(pid, 3, arg_var_filter, arg_filter_1_in) >= 0); ++ assert_se(print_process_cmdline_with_arg(pid, 3, arg_var_filter, arg_filter_1_no) >= 0); ++ assert_se(print_process_cmdline_with_arg(pid, 3, arg_var_filter, arg_filter_2_in) >= 0); ++ assert_se(print_process_cmdline_with_arg(pid, 3, arg_var_filter, arg_filter_2_no) >= 0); ++} ++ + int main(int argc, char *argv[]) { + log_show_color(true); + test_setup_logging(LOG_INFO); +@@ -627,6 +648,7 @@ int main(int argc, char *argv[]) { + test_ioprio_class_from_to_string(); + test_setpriority_closest(); + test_get_process_ppid(); ++ test_print_process_cmdline_with_arg(getpid()); + + return 0; + } +-- +2.23.0 + diff --git a/shutdown-reboot-when-recieve-crash-signal.patch b/shutdown-reboot-when-recieve-crash-signal.patch new file mode 100644 index 0000000000000000000000000000000000000000..42130900c07cb22c3d86d40343b266766ed234eb --- /dev/null +++ b/shutdown-reboot-when-recieve-crash-signal.patch @@ -0,0 +1,63 @@ +From 3ac4d1fc1a067afc0e0d4ca37a44ac252ee8b96b Mon Sep 17 00:00:00 2001 +From: xujing +Date: Tue, 8 Feb 2022 21:02:31 +0800 +Subject: [PATCH] shutdown: reboot when recieve crash signal + +--- + src/shutdown/shutdown.c | 33 +++++++++++++++++++++++++++++++++ + 1 files changed, 33 insertions(+) + +diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c +index 680de4f..066a03a 100644 +--- a/src/shutdown/shutdown.c ++++ b/src/shutdown/shutdown.c +@@ -307,6 +307,26 @@ static void bump_sysctl_printk_log_level(int min_level) { + log_debug_errno(r, "Failed to bump kernel.printk to %i: %m", min_level + 1); + } + ++_noreturn_ static void crash(int sig) { ++ if (getpid_cached() != 1) ++ /* Pass this on immediately, if this is not PID 1 */ ++ (void) raise(sig); ++ else { ++ bool in_container = detect_container() > 0; ++ ++ log_info("Recieve signal %d.", sig); ++ ++ broadcast_signal(SIGTERM, true, true, arg_timeout); ++ broadcast_signal(SIGKILL, true, false, arg_timeout); ++ ++ if (!in_container) ++ sync_with_progress(); ++ ++ log_info("Rebooting now."); ++ (void) reboot(RB_AUTOBOOT); ++ } ++} ++ + int main(int argc, char *argv[]) { + bool need_umount, need_swapoff, need_loop_detach, need_dm_detach, need_md_detach, in_container, use_watchdog = false, can_initrd; + _cleanup_free_ char *cgroup = NULL; +@@ -316,6 +336,19 @@ int main(int argc, char *argv[]) { + usec_t now_time, time_interval; + pid_t pid; + bool fork_failed = false; ++ static const struct sigaction sa = { ++ .sa_handler = crash, ++ .sa_flags = SA_NODEFER, /* So that we can raise the signal again from the signal handler */ ++ }; ++ ++ (void) reset_all_signal_handlers(); ++ (void) ignore_signals(SIGNALS_IGNORE, -1); ++ ++ /* We ignore the return value here, since, we don't mind if we ++ * cannot set up a crash handler */ ++ r = sigaction_many(&sa, SIGNALS_CRASH_HANDLER, -1); ++ if (r < 0) ++ log_debug_errno(r, "I had trouble setting up the crash handler, ignoring: %m"); + + /* The log target defaults to console, but the original systemd process will pass its log target in through a + * command line argument, which will override this default. Also, ensure we'll never log to the journal or +-- +2.23.0 + diff --git a/support-disable-cgroup-controllers-we-don-t-want.patch b/support-disable-cgroup-controllers-we-don-t-want.patch new file mode 100644 index 0000000000000000000000000000000000000000..5fc541a3238ab2fe10ea2ea158acd5a6d060b1f8 --- /dev/null +++ b/support-disable-cgroup-controllers-we-don-t-want.patch @@ -0,0 +1,216 @@ +From ef31366523d784d92f25abd99b3782acda29a01c Mon Sep 17 00:00:00 2001 +From: xujing +Date: Fri, 8 Jul 2022 19:47:45 +0800 +Subject: [PATCH] support disable cgroup controllers we don't want + +--- + src/basic/cgroup-util.c | 14 +++++++++++ + src/basic/cgroup-util.h | 1 + + src/core/cgroup.c | 1 + + src/core/main.c | 7 ++++++ + src/core/manager.h | 2 ++ + src/core/system.conf.in | 1 + + src/shared/conf-parser.c | 54 ++++++++++++++++++++++++++++++++++++++++ + src/shared/conf-parser.h | 1 + + 8 files changed, 81 insertions(+) + +diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c +index f912b65..79089ac 100644 +--- a/src/basic/cgroup-util.c ++++ b/src/basic/cgroup-util.c +@@ -1951,6 +1951,20 @@ int cg_mask_supported(CGroupMask *ret) { + return cg_mask_supported_subtree(root, ret); + } + ++int cg_mask_disable_cgroup(CGroupMask disabled, CGroupMask *ret) { ++ int r; ++ ++ r = cg_all_unified(); ++ if (r < 0) ++ return r; ++ ++ /* We only care CGROUP_V1 */ ++ if (r == 0) ++ *ret &= ~disabled; ++ ++ return 0; ++} ++ + int cg_kernel_controllers(Set **ret) { + _cleanup_set_free_free_ Set *controllers = NULL; + _cleanup_fclose_ FILE *f = NULL; +diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h +index a491eca..faa253b 100644 +--- a/src/basic/cgroup-util.h ++++ b/src/basic/cgroup-util.h +@@ -269,6 +269,7 @@ typedef const char* (*cg_migrate_callback_t)(CGroupMask mask, void *userdata); + + int cg_mask_supported(CGroupMask *ret); + int cg_mask_supported_subtree(const char *root, CGroupMask *ret); ++int cg_mask_disable_cgroup(CGroupMask disabled, CGroupMask *ret); + int cg_mask_from_string(const char *s, CGroupMask *ret); + int cg_mask_to_string(CGroupMask mask, char **ret); + +diff --git a/src/core/cgroup.c b/src/core/cgroup.c +index ab6d602..6101d53 100644 +--- a/src/core/cgroup.c ++++ b/src/core/cgroup.c +@@ -3378,6 +3378,7 @@ int manager_setup_cgroup(Manager *m) { + if (r < 0) + return log_error_errno(r, "Failed to determine supported bpf-based pseudo-controllers: %m"); + m->cgroup_supported |= mask; ++ m->system_cgroup_supported = m->cgroup_supported; + + /* 10. Log which controllers are supported */ + for (CGroupController c = 0; c < _CGROUP_CONTROLLER_MAX; c++) +diff --git a/src/core/main.c b/src/core/main.c +index a39d7d3..c4ce9a8 100644 +--- a/src/core/main.c ++++ b/src/core/main.c +@@ -145,6 +145,7 @@ static nsec_t arg_timer_slack_nsec; + static usec_t arg_default_timer_accuracy_usec; + static Set* arg_syscall_archs; + static FILE* arg_serialization; ++static CGroupMask arg_disable_cgroup_controllers; + static int arg_default_cpu_accounting; + static bool arg_default_io_accounting; + static bool arg_default_ip_accounting; +@@ -696,6 +697,7 @@ static int parse_config_file(void) { + { "Manager", "DefaultLimitNICE", config_parse_rlimit, RLIMIT_NICE, arg_default_rlimit }, + { "Manager", "DefaultLimitRTPRIO", config_parse_rlimit, RLIMIT_RTPRIO, arg_default_rlimit }, + { "Manager", "DefaultLimitRTTIME", config_parse_rlimit, RLIMIT_RTTIME, arg_default_rlimit }, ++ { "Manager", "DisableCGroupControllers", config_parse_cgroup, 0, &arg_disable_cgroup_controllers }, + { "Manager", "DefaultCPUAccounting", config_parse_tristate, 0, &arg_default_cpu_accounting }, + { "Manager", "DefaultIOAccounting", config_parse_bool, 0, &arg_default_io_accounting }, + { "Manager", "DefaultIPAccounting", config_parse_bool, 0, &arg_default_ip_accounting }, +@@ -767,6 +769,10 @@ static void set_manager_defaults(Manager *m) { + m->default_start_limit_burst = arg_default_start_limit_burst; + m->default_dfx_reboot = arg_default_dfx_reboot; + ++ m->cgroup_disabled = arg_disable_cgroup_controllers; ++ m->cgroup_supported = m->system_cgroup_supported; ++ (void) cg_mask_disable_cgroup(m->cgroup_disabled, &m->cgroup_supported); ++ + /* On 4.15+ with unified hierarchy, CPU accounting is essentially free as it doesn't require the CPU + * controller to be enabled, so the default is to enable it unless we got told otherwise. */ + if (arg_default_cpu_accounting >= 0) +@@ -2395,6 +2401,7 @@ static void reset_arguments(void) { + + /* arg_serialization — ignore */ + ++ arg_disable_cgroup_controllers = 0; + arg_default_cpu_accounting = -1; + arg_default_io_accounting = false; + arg_default_ip_accounting = false; +diff --git a/src/core/manager.h b/src/core/manager.h +index 54c1d3e..1f7d3b5 100644 +--- a/src/core/manager.h ++++ b/src/core/manager.h +@@ -295,6 +295,8 @@ struct Manager { + /* Data specific to the cgroup subsystem */ + Hashmap *cgroup_unit; + CGroupMask cgroup_supported; ++ CGroupMask system_cgroup_supported; ++ CGroupMask cgroup_disabled; + char *cgroup_root; + + /* Notifications from cgroups, when the unified hierarchy is used is done via inotify. */ +diff --git a/src/core/system.conf.in b/src/core/system.conf.in +index c1fd308..2fe6f60 100644 +--- a/src/core/system.conf.in ++++ b/src/core/system.conf.in +@@ -49,6 +49,7 @@ + #DefaultStartLimitIntervalSec=10s + #DefaultStartLimitBurst=5 + #DefaultEnvironment= ++#DisableCGroupControllers=no + #DefaultCPUAccounting=no + #DefaultIOAccounting=no + #DefaultIPAccounting=no +diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c +index d0ac1b2..23fc1f5 100644 +--- a/src/shared/conf-parser.c ++++ b/src/shared/conf-parser.c +@@ -10,6 +10,7 @@ + #include "alloc-util.h" + #include "conf-files.h" + #include "conf-parser.h" ++#include "cgroup-util.h" + #include "def.h" + #include "ether-addr-util.h" + #include "extract-word.h" +@@ -1196,6 +1197,59 @@ int config_parse_rlimit( + return 0; + } + ++int config_parse_cgroup( ++ const char *unit, ++ const char *filename, ++ unsigned line, ++ const char *section, ++ unsigned section_line, ++ const char *lvalue, ++ int ltype, ++ const char *rvalue, ++ void *data, ++ void *userdata) { ++ assert(filename); ++ assert(lvalue); ++ assert(rvalue); ++ assert(data); ++ ++ CGroupMask *disabled_mask = data; ++ int r; ++ ++ for (;;) { ++ _cleanup_free_ char *word = NULL; ++ CGroupController cc; ++ int yes_or_no = 0; ++ ++ r = extract_first_word(&rvalue, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); ++ if (r == 0) ++ break; ++ if (r == -ENOMEM) ++ return log_oom(); ++ if (r < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); ++ break; ++ } ++ ++ yes_or_no = parse_boolean(word); ++ if (yes_or_no == 0) { ++ *disabled_mask = 0; ++ break; ++ } else if (yes_or_no == 1) { ++ *disabled_mask = CGROUP_MASK_V1; ++ break; ++ } ++ ++ cc = cgroup_controller_from_string(word); ++ if (cc < 0) { ++ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DisableCGroupControllers, ignoring: %s", word); ++ break; ++ } ++ *disabled_mask |= CGROUP_CONTROLLER_TO_MASK(cc); ++ } ++ return 0; ++} ++ + int config_parse_permille( + const char* unit, + const char *filename, +diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h +index c3a1382..65ef71e 100644 +--- a/src/shared/conf-parser.h ++++ b/src/shared/conf-parser.h +@@ -146,6 +146,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ifnames); + CONFIG_PARSER_PROTOTYPE(config_parse_ip_port); + CONFIG_PARSER_PROTOTYPE(config_parse_mtu); + CONFIG_PARSER_PROTOTYPE(config_parse_rlimit); ++CONFIG_PARSER_PROTOTYPE(config_parse_cgroup); + CONFIG_PARSER_PROTOTYPE(config_parse_vlanprotocol); + CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr); + CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs); +-- +2.23.0 + diff --git a/systemd-core-Add-new-rules-for-lower-priority-events.patch b/systemd-core-Add-new-rules-for-lower-priority-events.patch new file mode 100644 index 0000000000000000000000000000000000000000..921b3621f92f95bdc4a0de889dea51675df487fc --- /dev/null +++ b/systemd-core-Add-new-rules-for-lower-priority-events.patch @@ -0,0 +1,224 @@ +From 135dce487e4637e8afc4090334ccb2cb9feccdf1 Mon Sep 17 00:00:00 2001 +From: yangbin +Date: Fri, 3 Apr 2020 11:56:41 +0800 +Subject: [PATCH] systemd-core: Add new rules for lower priority events to + preempt over higher priority events + +1. When a high priority event happenes very frequent, and this event takes long time for execution,systemd will get into busy for handling this event only, and lower priority events will have no any change to dispatch and run. + +2. One example is the event for /proc/self/mountinfo, which have a very high priority with -10. +When there are many mountpoints in mountinfo(for example, there may be many netns mountpoints),this event will take long time to finish. +Then if now there are mountpoints in repeating mounting and unmounting(for example, /run/user/uid mountpoint will be mounted then unmounted when for one su command), +this event will take all time of systemd, and lower priority lower events will not be dispatched anyway. +This will case a very severity problem that zombie process will not be reaped, for the evnet for reaping zombies has a lower priority of -6. + +3. This patch fix this problem by add the following rules to allow lower priority events to preempt over higher priority events. +a) If a higher priority event has already been execute for a certain count in consecutive, it can be preempted by lower priority events. The default value for this count is 10, and can be configured through 'sd_event_source_set_preempt_dispatch_count'. +b) If a lower priority gets into pending for 10 times in consecutive, it can preempt over higher priority events. +c) If a lower priority is in pending, and is not dispatched over 50 iteration, it can preempt over higher priority events. +d) The above rules only works for events with priority equal or higher than 'SD_EVENT_PRIORITY_NORMAL' or evnets with type of SOURCE_DEFER, since SOURCE_DEFER events is used for job running queues. +--- + src/core/mount.c | 4 ++ + src/libsystemd/sd-event/event-source.h | 5 ++ + src/libsystemd/sd-event/sd-event.c | 81 ++++++++++++++++++++++++++ + src/systemd/sd-event.h | 1 + + 4 files changed, 91 insertions(+) + +diff --git a/src/core/mount.c b/src/core/mount.c +index 053deac..de5b745 100644 +--- a/src/core/mount.c ++++ b/src/core/mount.c +@@ -1895,6 +1895,10 @@ static void mount_enumerate(Manager *m) { + goto fail; + } + ++ r = sd_event_source_set_preempt_dispatch_count(m->mount_event_source, 5); ++ if (r < 0) ++ goto fail; ++ + (void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch"); + } + +diff --git a/src/libsystemd/sd-event/event-source.h b/src/libsystemd/sd-event/event-source.h +index d2dc214..0fa41aa 100644 +--- a/src/libsystemd/sd-event/event-source.h ++++ b/src/libsystemd/sd-event/event-source.h +@@ -70,6 +70,11 @@ struct sd_event_source { + uint64_t pending_iteration; + uint64_t prepare_iteration; + ++ uint64_t preempted_iteration; /*The iteration that dispatched_count is greater than preempt_dispatch_count*/ ++ unsigned pending_count; /*times of pending not dispatched*/ ++ unsigned dispatched_count; /*consecutive dispatched count*/ ++ unsigned preempt_dispatch_count; /*Will be preempted by lower priority if dispatched count reaches to this*/ ++ + sd_event_destroy_t destroy_callback; + + LIST_FIELDS(sd_event_source, sources); +diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c +index e9199de..46f8aff 100644 +--- a/src/libsystemd/sd-event/sd-event.c ++++ b/src/libsystemd/sd-event/sd-event.c +@@ -27,6 +27,11 @@ + #include "strxcpyx.h" + #include "time-util.h" + ++#define DEFAULT_PREEMPTED_ITERATION_COUNT (3) ++#define DEFAULT_PREEMPT_DISPATCH_COUNT (10) ++#define DEFAULT_PREEMPT_PENDING_COUNT (10) ++#define DEFAULT_PREEMPT_ITERATION_COUNT (30) ++ + #define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC) + + static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) { +@@ -152,6 +157,11 @@ struct sd_event { + + LIST_HEAD(sd_event_source, sources); + ++ /*last dispatched source, its type is sd_event_source, ++ * here use void to avoid accessing its members, ++ * for it may have been freed already.*/ ++ void *last_source; ++ + usec_t last_run_usec, last_log_usec; + unsigned delays[sizeof(usec_t) * 8]; + }; +@@ -165,6 +175,39 @@ static sd_event *event_resolve(sd_event *e) { + return e == SD_EVENT_DEFAULT ? default_event : e; + } + ++static int preempt_prioq_compare(const sd_event_source *x, const sd_event_source *y) { ++ if((x->priority > SD_EVENT_PRIORITY_NORMAL && x->type != SOURCE_DEFER) ++ || (y->priority > SD_EVENT_PRIORITY_NORMAL && y->type != SOURCE_DEFER)) { ++ return 0; /*only high priority evnets can preempt*/ ++ } ++ ++ if(x->priority <= y->priority) { ++ if(x->dispatched_count >= x->preempt_dispatch_count) ++ return 1; ++ if(y->type != SOURCE_DEFER) { /*pending state for defer event is always true*/ ++ /*y has lower priority, but its pending count is greater than x, so y wins*/ ++ if(y->pending_count >= (x->pending_count + DEFAULT_PREEMPT_PENDING_COUNT)) ++ return 1; ++ /*y has lower priority, but is in pending longer than x, so y wins*/ ++ if(x->pending_iteration >= (y->pending_iteration + DEFAULT_PREEMPT_ITERATION_COUNT)) ++ return 1; ++ } ++ } else { ++ if(y->dispatched_count >= y->preempt_dispatch_count) ++ return -1; ++ if(x->type != SOURCE_DEFER) { /*pending state for defer event is always true*/ ++ /*x has lower priority, but its pending count is greater than y, so x wins*/ ++ if(x->pending_count >= (y->pending_count + DEFAULT_PREEMPT_PENDING_COUNT)) ++ return -1; ++ /*x has lower priority, but is in pending longer than y, so x wins*/ ++ if(y->pending_iteration >= (x->pending_iteration + DEFAULT_PREEMPT_ITERATION_COUNT)) ++ return -1; ++ } ++ } ++ ++ return 0; ++} ++ + static int pending_prioq_compare(const void *a, const void *b) { + const sd_event_source *x = a, *y = b; + int r; +@@ -182,6 +225,10 @@ static int pending_prioq_compare(const void *a, const void *b) { + if (r != 0) + return r; + ++ r = preempt_prioq_compare(a, b); ++ if(r != 0) ++ return r; ++ + /* Lower priority values first */ + r = CMP(x->priority, y->priority); + if (r != 0) +@@ -998,6 +1045,17 @@ static int source_set_pending(sd_event_source *s, bool b) { + assert(s); + assert(s->type != SOURCE_EXIT); + ++ if (b && s->pending == b) ++ s->pending_count++; ++ else ++ s->pending_count = (b ? 1 : 0); ++ if (b && s->preempted_iteration && ++ (s->pending_count >= DEFAULT_PREEMPTED_ITERATION_COUNT || ++ s->event->iteration >= (s->preempted_iteration + DEFAULT_PREEMPTED_ITERATION_COUNT)) ) { ++ s->dispatched_count = 0; ++ s->preempted_iteration = 0; ++ } ++ + if (s->pending == b) + return 0; + +@@ -1057,6 +1115,7 @@ static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType t + .type = type, + .pending_index = PRIOQ_IDX_NULL, + .prepare_index = PRIOQ_IDX_NULL, ++ .preempt_dispatch_count = DEFAULT_PREEMPT_DISPATCH_COUNT, + }; + + if (!floating) +@@ -2370,6 +2429,7 @@ static int event_source_offline( + s->enabled = enabled; + s->ratelimited = ratelimited; + ++ s->pending_count = 0; + switch (s->type) { + + case SOURCE_IO: +@@ -3443,6 +3503,19 @@ static int process_inotify(sd_event *e) { + return done; + } + ++static void source_dispatch_pre(sd_event_source *s) { ++ if(s->event->last_source == s) { ++ s->dispatched_count++; ++ if(s->dispatched_count >= s->preempt_dispatch_count) ++ s->preempted_iteration = s->event->iteration; ++ } else { ++ s->preempted_iteration = 0; ++ s->dispatched_count = 0; ++ } ++ s->event->last_source = s; ++ s->pending_count = 0; ++} ++ + static int source_dispatch(sd_event_source *s) { + _cleanup_(sd_event_unrefp) sd_event *saved_event = NULL; + EventSourceType saved_type; +@@ -3496,6 +3569,7 @@ static int source_dispatch(sd_event_source *s) { + return r; + } + ++ source_dispatch_pre(s); + s->dispatching = true; + + switch (s->type) { +@@ -4449,3 +4523,10 @@ _public_ int sd_event_source_is_ratelimited(sd_event_source *s) { + + return s->ratelimited; + } ++ ++_public_ int sd_event_source_set_preempt_dispatch_count(sd_event_source *s, unsigned count) { ++ assert_return(s, -EINVAL); ++ ++ s->preempt_dispatch_count = count; ++ return 0; ++} +diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h +index 2ae2a0d..f113aba 100644 +--- a/src/systemd/sd-event.h ++++ b/src/systemd/sd-event.h +@@ -165,6 +165,7 @@ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b); + int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, unsigned burst); + int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval_usec, unsigned *ret_burst); + int sd_event_source_is_ratelimited(sd_event_source *s); ++int sd_event_source_set_preempt_dispatch_count(sd_event_source *s, unsigned count); + + /* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */ + _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref); +-- +2.23.0 + diff --git a/systemd.spec b/systemd.spec index 547f59f128fe11dfc964f57e32d7dd6c3033d643..3ed646f527174a50a7b3bf20b82a562fa9f7bf11 100644 --- a/systemd.spec +++ b/systemd.spec @@ -21,7 +21,7 @@ Name: systemd Url: https://www.freedesktop.org/wiki/Software/systemd Version: 249 -Release: 44 +Release: 45 License: MIT and LGPLv2+ and GPLv2+ Summary: System and Service Manager @@ -314,7 +314,6 @@ Patch6264: backport-execute-use-_cleanup_-logic-where-appropriate.patch Patch6265: backport-execute-line-break-comments-a-bit-less-aggressively.patch Patch6266: backport-execute-document-that-the-env-param-is-input-and-out.patch Patch6267: backport-sd-dhcp-lease-fix-memleak.patch -Patch6268: backport-core-mount-fail-early-if-directory-cannot-be-created.patch Patch6269: backport-util-another-set-of-CVE-2021-4034-assert-s.patch Patch6270: backport-resolve-fix-potential-memleak-and-use-after-free.patch Patch6271: backport-resolve-fix-possible-memleak.patch @@ -422,6 +421,25 @@ Patch6373: backport-coredump-Fix-format-string-type-mismatch.patch Patch6374: backport-coredump-drop-an-unused-variable.patch Patch6375: backport-CVE-2022-4415-coredump-adjust-whitespace.patch Patch6376: backport-CVE-2022-4415-dont-allow-user-access-coredumps-with-changed-uid.patch +Patch6377: backport-dns-domain-make-each-label-nul-terminated.patch +Patch6378: backport-resolve-fix-heap-buffer-overflow-reported-by-ASAN-wi.patch +Patch6379: backport-sd-bus-do-not-pass-NULL-when-received-message-with-i.patch +Patch6380: backport-growfs-don-t-actually-resize-on-dry-run.patch +Patch6381: backport-stat-util-replace-is_dir-is_dir_fd-by-single-is_dir_.patch +Patch6382: backport-tmpfiles-check-the-directory-we-were-supposed-to-cre.patch +Patch6383: backport-coredump-Connect-stdout-stderr-to-dev-null-before-do.patch +Patch6384: backport-cgroups-agent-connect-stdin-stdout-stderr-to-dev-nul.patch +Patch6385: backport-unit-file-avoid-null-in-debugging-logs.patch +Patch6386: backport-resolve-mdns_packet_extract_matching_rrs-may-return-.patch +Patch6387: backport-dhcp-fix-potential-buffer-overflow.patch +Patch6388: backport-sd-device-monitor-actually-refuse-to-send-invalid-de.patch +Patch6389: backport-sysusers-add-fsync-for-passwd-24324.patch +Patch6390: backport-condition-fix-device-tree-firmware-path.patch +Patch6391: backport-log-don-t-attempt-to-duplicate-closed-fd.patch +Patch6392: backport-mount-util-fix-error-code.patch +Patch6393: backport-analyze-add-forgotten-return-statement.patch +Patch6394: backport-shared-condition-avoid-nss-lookup-in-PID1.patch +Patch6395: backport-logind-fix-getting-property-OnExternalPower-via-D-Bu.patch Patch9001: update-rtc-with-system-clock-when-shutdown.patch Patch9002: udev-add-actions-while-rename-netif-failed.patch @@ -461,6 +479,25 @@ Patch9035: add-loongarch-for-missing_syscall_def.patch %endif Patch9036: core-update-arg_default_rlimit-in-bump_rlimit.patch Patch9037: set-forwardtowall-no-to-avoid-emerg-log-shown-on-she.patch +Patch9038: core-cgroup-support-cpuset.patch +Patch9039: core-cgroup-support-freezer.patch +Patch9040: core-cgroup-support-memorysw.patch +Patch9041: systemd-core-Add-new-rules-for-lower-priority-events.patch +Patch9042: bugfix-also-stop-machine-when-a-machine-un.patch +Patch9043: print-the-process-status-to-console-when-shutdown.patch +Patch9044: Retry-to-handle-the-uevent-when-worker-is-terminated.patch +Patch9045: treat-hyphen-as-valid-hostname-char.patch +Patch9046: process-util-log-more-information-when-runnin.patch +Patch9047: fuser-print-umount-message-to-reboot-umount-msg.patch +Patch9048: shutdown-reboot-when-recieve-crash-signal.patch +Patch9049: core-add-OptionalLog-to-allow-users-change-log-level.patch +Patch9050: core-cgroup-support-default-slice-for-all-uni.patch +Patch9051: core-add-invalidate-cgroup-config.patch +Patch9052: let-the-child-of-one-unit-don-t-affect-each-other.patch +Patch9053: support-disable-cgroup-controllers-we-don-t-want.patch +Patch9054: fix-mount-failed-while-daemon-reexec.patch +Patch9055: bugfix-for-cgroup-Swap-cgroup-v1-deletion-and-migration.patch +Patch9056: delete-journal-files-except-system.journal-when-jour.patch BuildRequires: gcc, gcc-c++ BuildRequires: libcap-devel, libmount-devel, pam-devel, libselinux-devel @@ -503,7 +540,6 @@ Obsoletes: systemd-sysv < 206 Obsoletes: %{name} < 229-5 Provides: systemd-sysv = 206 Conflicts: initscripts < 9.56.1 -Recommends: %{name}-help Provides: %{name}-rpm-config Obsoletes: %{name}-rpm-config < 243 @@ -1874,6 +1910,10 @@ fi %{_libdir}/security/pam_systemd.so %changelog +* Fri Jan 13 2023 yangmingtai -249-45 +- backport patches from upstream and add patchs to enhance compatibility + and features + * Wed Dec 28 2022 huyubiao - 249-44 - fix CVE-2022-4415 diff --git a/treat-hyphen-as-valid-hostname-char.patch b/treat-hyphen-as-valid-hostname-char.patch new file mode 100644 index 0000000000000000000000000000000000000000..b2fbe875eda15c827114171d8acfab1440f197f9 --- /dev/null +++ b/treat-hyphen-as-valid-hostname-char.patch @@ -0,0 +1,51 @@ +From c04904a4f54f8949a6a7821a0859e2732366259b Mon Sep 17 00:00:00 2001 +From: licunlong +Date: Tue, 24 Nov 2020 19:57:38 +0800 +Subject: [PATCH] treat hyphen as valid hostname char + +--- + src/basic/hostname-util.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c +index 5bfa028..b80a2b8 100644 +--- a/src/basic/hostname-util.c ++++ b/src/basic/hostname-util.c +@@ -77,6 +77,16 @@ bool valid_ldh_char(char c) { + c == '-'; + } + ++static bool hostname_valid_char(char c) { ++ return ++ (c >= 'a' && c <= 'z') || ++ (c >= 'A' && c <= 'Z') || ++ (c >= '0' && c <= '9') || ++ c == '-' || ++ c == '_' || ++ c == '.'; ++} ++ + bool hostname_is_valid(const char *s, ValidHostnameFlags flags) { + unsigned n_dots = 0; + const char *p; +@@ -117,7 +127,7 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) { + hyphen = true; + + } else { +- if (!valid_ldh_char(*p)) ++ if (!hostname_valid_char(*p)) + return false; + + dot = false; +@@ -160,7 +170,7 @@ char* hostname_cleanup(char *s) { + dot = false; + hyphen = true; + +- } else if (valid_ldh_char(*p)) { ++ } else if (hostname_valid_char(*p)) { + *(d++) = *p; + dot = false; + hyphen = false; +-- +2.23.0 +