found 803013 241-7~deb10u1
thanks

Now updating my machines to buster, I see this issue is still present,
now in systemd version 241-7~deb10u1. The same steps can reproduce:
  - Set up cgroups e.g. adding TaskIDs to /sys/fs/cgroup/cpu/DIR/tasks
    files. (I use cgrulesengd from package cgroup-tools, but any other
    use of cgroups is equally affected.)
  - Then when you use systemd commands:
      systemctl daemon-reload
      systemctl start anacron
    you will see your cgroups (your tasks files) becoming empty.
    Command daemon-reload seems to happen within "apt-get dist-upgrade"
    sequences, and "start anacron" happens nightly. (Some other systemd
    commands may also affect.)
and the "same" fix applies: new patch file below, for changed sources.

(Funny how this bug is not getting fixed, in four years...)

Thanks, Paul
-- 
Paul Szabo   p...@maths.usyd.edu.au   http://www.maths.usyd.edu.au/u/psz/
School of Mathematics and Statistics   University of Sydney    Australia

I support NTEU members taking a stand for workplace rights in the face of
poorly-run change management. Visit www.nteu.org.au/sydney to learn more.
diff -r -U18 a-241/src/basic/cgroup-util.c b-241/src/basic/cgroup-util.c
--- a-241/src/basic/cgroup-util.c	2019-02-14 21:11:58.000000000 +1100
+++ b-241/src/basic/cgroup-util.c	2019-09-12 08:53:43.900643247 +1000
@@ -368,36 +368,52 @@
 
 int cg_migrate(
                 const char *cfrom,
                 const char *pfrom,
                 const char *cto,
                 const char *pto,
                 CGroupFlags flags) {
 
         bool done = false;
         _cleanup_set_free_ Set *s = NULL;
         int r, ret = 0;
         pid_t my_pid;
 
         assert(cfrom);
         assert(pfrom);
         assert(cto);
         assert(pto);
 
+        /*
+         * PSz 25 Oct 2015
+         * An empty "to" path is surely wrong
+         * (do not annoy cgroups that are not ours).
+         * PSz 23 Jul 2017
+         * Cannot(?) happen anymore, see:
+         *   cg_migrate_recursive_fallback()
+         *   cg_migrate_everywhere()
+         * below... log if it does!
+         */
+        if (!strlen(pto)) {
+                log_warning("PSz debug: cg_migrate skip from (%s)%s to (%s)%s", cfrom, pfrom, cto, pto);
+                return ret;
+        }
+        /* log_warning("PSz debug: cg_migrate do from (%s)%s to (%s)%s", cfrom, pfrom, cto, pto); */
+
         s = set_new(NULL);
         if (!s)
                 return -ENOMEM;
 
         my_pid = getpid_cached();
 
         do {
                 _cleanup_fclose_ FILE *f = NULL;
                 pid_t pid = 0;
                 done = true;
 
                 r = cg_enumerate_processes(cfrom, pfrom, &f);
                 if (r < 0) {
                         if (ret >= 0 && r != -ENOENT)
                                 return r;
 
                         return ret;
                 }
@@ -509,36 +525,52 @@
                 CGroupFlags flags) {
 
         int r;
 
         assert(cfrom);
         assert(pfrom);
         assert(cto);
         assert(pto);
 
         r = cg_migrate_recursive(cfrom, pfrom, cto, pto, flags);
         if (r < 0) {
                 char prefix[strlen(pto) + 1];
 
                 /* This didn't work? Then let's try all prefixes of the destination */
 
                 PATH_FOREACH_PREFIX(prefix, pto) {
                         int q;
 
+                        /*
+                         * PSz 23 Jul 2017
+                         * Skip an empty ("") prefix path: surely wrong,
+                         * do not annoy cgroups that are not ours.
+                         * Other comments:
+                         * - Why this "did not work so try something else"?
+                         * - Maybe should have used PATH_FOREACH_PREFIX_MORE
+                         *   for cleaner, more compact code.
+                         * - Should check cg_attach_fallback() also, and maybe
+                         *   review all other uses of PATH_FOREACH_PREFIX.
+                         */
+                        if (!strlen(prefix)) {
+                                /* log_warning("PSz debug: cg_migrate_recursive_fallback skip from (%s)%s to (%s)[EMPTY prefix of %s]", cfrom, pfrom, cto, pto); */
+                                continue;
+                        }
+
                         q = cg_migrate_recursive(cfrom, pfrom, cto, prefix, flags);
                         if (q >= 0)
                                 return q;
                 }
         }
 
         return r;
 }
 
 static const char *controller_to_dirname(const char *controller) {
         const char *e;
 
         assert(controller);
 
         /* Converts a controller name to the directory name below
          * /sys/fs/cgroup/ we want to mount it to. Effectively, this
          * just cuts off the name= prefixed used for named
          * hierarchies, if it is specified. */
@@ -2233,38 +2265,46 @@
         if (q > 0)
                 return r;
 
         supported &= CGROUP_MASK_V1;
         done = 0;
 
         for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
                 CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
                 const char *p = NULL;
 
                 if (!FLAGS_SET(supported, bit))
                         continue;
 
                 if (FLAGS_SET(done, bit))
                         continue;
 
                 if (to_callback)
                         p = to_callback(bit, userdata);
-                if (!p)
+                if (!p) {
                         p = to;
+                } else if (!strlen(p)) {
+                        /*
+                         * PSz 12 Sep 2019
+                         * Skip an empty path returned by to_callback
+                         */
+                        /* log_warning("PSz debug: to_callback in cg_migrate_everywhere returned empty, skipping (%s)%s to (%s)%s", SYSTEMD_CGROUP_CONTROLLER, to, cgroup_controller_to_string(c), p); */
+                        continue;
+                }
 
                 (void) cg_migrate_recursive_fallback(SYSTEMD_CGROUP_CONTROLLER, to, cgroup_controller_to_string(c), p, 0);
                 done |= CGROUP_MASK_EXTEND_JOINED(bit);
         }
 
         return r;
 }
 
 int cg_trim_everywhere(CGroupMask supported, const char *path, bool delete_root) {
         CGroupController c;
         CGroupMask done;
         int r, q;
 
         r = cg_trim(SYSTEMD_CGROUP_CONTROLLER, path, delete_root);
         if (r < 0)
                 return r;
 
         q = cg_all_unified();

Reply via email to