]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
cgroup-util: port from nftw() to recurse_dir()
authorLennart Poettering <lennart@poettering.net>
Fri, 1 Oct 2021 13:55:37 +0000 (15:55 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 7 Oct 2021 09:59:23 +0000 (11:59 +0200)
src/shared/cgroup-setup.c

index f197f715c7927f31c89aeb9d9bcdb5bccab99664..7dee7e9512776339b00812be47b19df8cded7ff8 100644 (file)
@@ -1,22 +1,22 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
-#include <ftw.h>
 #include <unistd.h>
 
 #include "cgroup-setup.h"
 #include "cgroup-util.h"
 #include "errno-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "mkdir.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
+#include "process-util.h"
+#include "recurse-dir.h"
 #include "stdio-util.h"
 #include "string-util.h"
-#include "fs-util.h"
-#include "mkdir.h"
-#include "process-util.h"
-#include "fileio.h"
 #include "user-util.h"
-#include "fd-util.h"
 
 bool cg_is_unified_wanted(void) {
         static thread_local int wanted = -1;
@@ -149,19 +149,23 @@ int cg_blkio_weight_parse(const char *s, uint64_t *ret) {
         return 0;
 }
 
-static int trim_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
-        assert(path);
-        assert(sb);
-        assert(ftwbuf);
-
-        if (typeflag != FTW_DP)
-                return 0;
-
-        if (ftwbuf->level < 1)
-                return 0;
-
-        (void) rmdir(path);
-        return 0;
+static int trim_cb(
+                RecurseDirEvent event,
+                const char *path,
+                int dir_fd,
+                int inode_fd,
+                const struct dirent *de,
+                const struct statx *sx,
+                void *userdata) {
+
+        /* Failures to delete inner cgroup we ignore (but debug log in case error code is unexpected) */
+        if (event == RECURSE_DIR_LEAVE &&
+            de->d_type == DT_DIR &&
+            unlinkat(dir_fd, de->d_name, AT_REMOVEDIR) < 0 &&
+            !IN_SET(errno, ENOENT, ENOTEMPTY, EBUSY))
+                log_debug_errno(errno, "Failed to trim inner cgroup %s, ignoring: %m", path);
+
+        return RECURSE_DIR_CONTINUE;
 }
 
 int cg_trim(const char *controller, const char *path, bool delete_root) {
@@ -169,32 +173,41 @@ int cg_trim(const char *controller, const char *path, bool delete_root) {
         int r, q;
 
         assert(path);
+        assert(controller);
 
         r = cg_get_path(controller, path, NULL, &fs);
         if (r < 0)
                 return r;
 
-        errno = 0;
-        if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0) {
-                if (errno == ENOENT)
-                        r = 0;
-                else
-                        r = errno_or_else(EIO);
-        }
-
-        if (delete_root) {
-                if (rmdir(fs) < 0 && errno != ENOENT)
-                        return -errno;
+        r = recurse_dir_at(
+                        AT_FDCWD,
+                        fs,
+                        /* statx_mask= */ 0,
+                        /* n_depth_max= */ UINT_MAX,
+                        RECURSE_DIR_ENSURE_TYPE,
+                        trim_cb,
+                        NULL);
+        if (r == -ENOENT) /* non-existing is the ultimate trimming, hence no error */
+                r = 0;
+        else if (r < 0)
+                log_debug_errno(r, "Failed to iterate through cgroup %s: %m", path);
+
+        /* If we shall delete the top-level cgroup, then propagate the faiure to do so (except if it is
+         * already gone anyway). Also, let's debug log about this failure, except if the error code is an
+         * expected one. */
+        if (delete_root && !empty_or_root(path) &&
+            rmdir(fs) < 0 && errno != ENOENT) {
+                if (!IN_SET(errno, ENOTEMPTY, EBUSY))
+                        log_debug_errno(errno, "Failed to trim cgroup %s: %m", path);
+                if (r >= 0)
+                        r = -errno;
         }
 
         q = cg_hybrid_unified();
         if (q < 0)
                 return q;
-        if (q > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
-                q = cg_trim(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, delete_root);
-                if (q < 0)
-                        log_warning_errno(q, "Failed to trim compat systemd cgroup %s: %m", path);
-        }
+        if (q > 0 && streq(controller, SYSTEMD_CGROUP_CONTROLLER))
+                (void) cg_trim(SYSTEMD_CGROUP_CONTROLLER_LEGACY, path, delete_root);
 
         return r;
 }