From 07259f1f17a3a60e46f72728e0262d8d8927c509 Mon Sep 17 00:00:00 2001 From: Kamalesh Babulal Date: Tue, 24 Jan 2023 12:35:48 -0700 Subject: [PATCH] src/api: Fix cgroup_delete_cgroup_ext() on shared mount point 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 Signed-off-by: Tom Hromatka --- src/api.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/api.c b/src/api.c index cea3efe1..704e62d8 100644 --- 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)) -- 2.47.2