From: Tom Hromatka Date: Thu, 11 May 2023 19:53:18 +0000 (-0600) Subject: api: Delete the cgroup if cgroup_create_cgroup() fails X-Git-Tag: v3.1.0~70 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6d44f253d9e55e6b2095ae50d216137e9a2e481a;p=thirdparty%2Flibcgroup.git api: Delete the cgroup if cgroup_create_cgroup() fails 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 Reviewed-by: Kamalesh Babulal --- diff --git a/src/api.c b/src/api.c index 9b830720..c30ac98b 100644 --- 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; diff --git a/src/config.c b/src/config.c index 9fcfc032..80c09ece 100644 --- a/src/config.c +++ b/src/config.c @@ -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();