]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
api: Delete the cgroup if cgroup_create_cgroup() fails
authorTom Hromatka <tom.hromatka@oracle.com>
Thu, 11 May 2023 19:53:18 +0000 (13:53 -0600)
committerTom Hromatka <tom.hromatka@oracle.com>
Wed, 17 May 2023 22:02:42 +0000 (16:02 -0600)
cgroup_create_cgroup() loops through the controllers in struct cgroup
and creates the requested cgroups.  Some controllers could succeed
before a controller fails.  This results in a case where the cgroup
directory has been created and remains in /sys/fs/cgroup even after a
failure.

Invoke cgroup_delete_cgroup() after we fail to create a cgroup under a
controller.  This will delete the cgroup directory if it had been
created and put the system (nearly) back to its original state.  (It's
possible that the parent cgroup's subtree_control file was modified and
not restored, but that's best fixed in another patch.)

Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>
Reviewed-by: Kamalesh Babulal <kamalesh.babulal@oracle.com>
src/api.c
src/config.c

index 9b830720ad0ed7d45746f2eb7c8e8e8ca777cff5..c30ac98b95f453712eee9522dc3b70fc31fe000c 100644 (file)
--- a/src/api.c
+++ b/src/api.c
@@ -2909,6 +2909,11 @@ int cgroup_create_cgroup(struct cgroup *cgroup, int ignore_ownership)
                /* Create an empty cgroup v2 cgroup */
                error = _cgroup_create_cgroup(cgroup, NULL, ignore_ownership);
                if (error)
+                       /*
+                        * Since we only attempted to create a single cgroup,
+                        * _cgroup_create_cgroup() can capably undo the failure and no
+                        * interventions are required here.
+                        */
                        return error;
        }
 
@@ -2919,8 +2924,21 @@ int cgroup_create_cgroup(struct cgroup *cgroup, int ignore_ownership)
         */
        for (i = 0; i < cgroup->index; i++) {
                error = _cgroup_create_cgroup(cgroup, cgroup->controller[i], ignore_ownership);
-               if (error)
+               if (error) {
+                       int del_error;
+
+                       /*
+                        * This will remove any cgroup directories that were made, but it won't
+                        * undo changes that have been written to the parent cgroup's
+                        * subtree_control file.  To safely undo changes there, we would need to
+                        * save the subtree_control file's previous value and restore it.
+                        */
+                       del_error = cgroup_delete_cgroup(cgroup, 1);
+                       if (del_error)
+                               cgroup_err("Failed to delete %s: %s\n", cgroup->name,
+                                          cgroup_strerror(del_error));
                        return error;
+               }
        }
 
        return 0;
index 9fcfc032d7eac4c88d6bac6ba8abe929f279e9af..80c09ece436e46f305ad52a8399081f078701631 100644 (file)
@@ -1221,6 +1221,7 @@ int cgroup_config_load_config(const char *pathname)
 #endif
        int namespace_enabled = 0;
        int mount_enabled = 0;
+       int tmp_errno;
        int error;
        int ret;
 
@@ -1297,7 +1298,14 @@ int cgroup_config_load_config(const char *pathname)
 
        return 0;
 err_grp:
+       /*
+        * Save off the error that has already occurred.  The errno from
+        * cgroup_config_destroy_groups() is secondary to the original error that was reported,
+        * and thus can be discarded;
+        */
+       tmp_errno = last_errno;
        cgroup_config_destroy_groups();
+       last_errno = tmp_errno;
 err_mnt:
        cgroup_config_unmount_controllers();
        cgroup_free_config();