]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
src/api: Fix cgroup_delete_cgroup_ext() on shared mount point
authorKamalesh Babulal <kamalesh.babulal@oracle.com>
Tue, 24 Jan 2023 19:42:19 +0000 (12:42 -0700)
committerTom Hromatka <tom.hromatka@oracle.com>
Tue, 24 Jan 2023 19:42:24 +0000 (12:42 -0700)
In cgroup v1, the controllers can share mount points and when the cgroup
is deleted on one of controller mount point (symlink), as the side effect
are deleted for the controllers sharing the mount point. But this might
not true always, the user might try call cgroup_delete_cgroup_ext() with
a cgroup that doesn't exist over the share mount point and still get the
return code to be zero.

Fix this issue by introducing cgrp_del_shared_mnt flag, that gets set
when deleting the cgroup on the first of the controllers sharing the
mount point and check the flag on the second controller mount point
to ensure that cgroup existed.

Reproducer:
-----------
$ sudo cgdelete -g cpu:foo
$ echo $?
$ 0

With the patch:
---------------
$ cgdelete -g cpu:foo
cgdelete: cannot remove group 'foo': Cgroup does not exist
$ echo $?
82

Signed-off-by: Kamalesh Babulal <kamalesh.babulal@oracle.com>
Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>
(cherry picked from commit 07259f1f17a3a60e46f72728e0262d8d8927c509)

src/api.c

index cea3efe1d0011c4100cc41838943de60977fff67..704e62d81cddff64d729b3e2f7b268deacbc4ec0 100644 (file)
--- a/src/api.c
+++ b/src/api.c
@@ -2886,6 +2886,7 @@ static int cgroup_find_parent(struct cgroup *cgroup, char *controller, char **pa
 
        if (stat(child_path, &stat_child) < 0) {
                if (is_cgrp_ctrl_shared_mnt(controller)) {
+                       last_errno = errno;
                        ret = ECGROUPNOTEXIST;
                        goto free_parent;
                }
@@ -3168,6 +3169,7 @@ int cgroup_delete_cgroup(struct cgroup *cgroup, int ignore_migration)
 int cgroup_delete_cgroup_ext(struct cgroup *cgroup, int flags)
 {
        int first_error = 0, first_errno = 0;
+       int cgrp_del_on_shared_mnt = 0;
        char parent_path[FILENAME_MAX];
        char *controller_name = NULL;
        FILE *parent_tasks = NULL;
@@ -3212,12 +3214,29 @@ int cgroup_delete_cgroup_ext(struct cgroup *cgroup, int flags)
                if (!(flags & CGFLAG_DELETE_EMPTY_ONLY)) {
                        ret = cgroup_find_parent(cgroup, controller_name, &parent_name);
                        if (ret) {
-                               if (first_error == 0 && ret != ECGROUPNOTEXIST) {
-                                       first_errno = last_errno;
-                                       first_error = ret;
+                               /*
+                                * ECGROPNOTEXIST is returned on cgroup v1, where
+                                * controllers share the mount points. When cgroup
+                                * is deleted on one of symbolic link (controller)
+                                * and they should pass on other controllers sharing
+                                * the mount point.
+                                *
+                                * cgrp_del_shared_mnt serves as an extra check
+                                * flag that gets set, when the cgroup exists and
+                                * is deleted or else sets an error.
+                                */
+                               if (first_error == 0 &&
+                                   (ret != ECGROUPNOTEXIST ||
+                                   (ret == ECGROUPNOTEXIST && cgrp_del_on_shared_mnt == 0))) {
+                                               first_errno = last_errno;
+                                               first_error = ECGOTHER;
                                }
                                continue;
                        }
+
+                       if (is_cgrp_ctrl_shared_mnt(controller_name))
+                                       cgrp_del_on_shared_mnt = 1;
+
                        if (parent_name == NULL) {
                                /* Root group is being deleted. */
                                if (!(flags & CGFLAG_DELETE_RECURSIVE))