]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
Revert "Revert "cgfsng: avoid tiny race window""
authorChristian Brauner <christian.brauner@ubuntu.com>
Wed, 3 Oct 2018 10:20:49 +0000 (12:20 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Wed, 3 Oct 2018 10:29:20 +0000 (12:29 +0200)
This reverts commit c5e7a7acbf23f0c267179b3318af41423b39493a.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/cgroups/cgfsng.c
src/lxc/utils.c

index 0fc9b11d2c01acaec95358f8866f649147599fb8..ec4501c33e4e50a25f5bea3c22dd6d16c641a43a 100644 (file)
@@ -1257,13 +1257,50 @@ on_error:
        return bret;
 }
 
+static int mkdir_eexist_on_last(const char *dir, mode_t mode)
+{
+       const char *tmp = dir;
+       const char *orig = dir;
+       size_t orig_len;
+
+       orig_len = strlen(dir);
+       do {
+               int ret;
+               size_t cur_len;
+               char *makeme;
+
+               dir = tmp + strspn(tmp, "/");
+               tmp = dir + strcspn(dir, "/");
+
+               errno = ENOMEM;
+               cur_len = dir - orig;
+               makeme = strndup(orig, cur_len);
+               if (!makeme)
+                       return -1;
+
+               ret = mkdir(makeme, mode);
+               if (ret < 0) {
+                       if ((errno != EEXIST) || (orig_len == cur_len)) {
+                               SYSERROR("Failed to create directory \"%s\"", makeme);
+                               free(makeme);
+                               return -1;
+                       }
+               }
+               free(makeme);
+
+       } while (tmp != dir);
+
+       return 0;
+}
+
 static bool monitor_create_path_for_hierarchy(struct hierarchy *h, char *cgname)
 {
        int ret;
 
        h->monitor_full_path = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL);
-       if (dir_exists(h->monitor_full_path)) {
-               ERROR("The cgroup \"%s\" already existed", h->monitor_full_path);
+       ret = mkdir_eexist_on_last(h->monitor_full_path, 0755);
+       if (ret < 0) {
+               ERROR("Failed to create cgroup \"%s\"", h->monitor_full_path);
                return false;
        }
 
@@ -1272,12 +1309,6 @@ static bool monitor_create_path_for_hierarchy(struct hierarchy *h, char *cgname)
                return false;
        }
 
-       ret = mkdir_p(h->monitor_full_path, 0755);
-       if (ret < 0) {
-               ERROR("Failed to create cgroup \"%s\"", h->monitor_full_path);
-               return false;
-       }
-
        return cg_unified_create_cgroup(h, cgname);
 }
 
@@ -1286,8 +1317,9 @@ static bool container_create_path_for_hierarchy(struct hierarchy *h, char *cgnam
        int ret;
 
        h->container_full_path = must_make_path(h->mountpoint, h->container_base_path, cgname, NULL);
-       if (dir_exists(h->container_full_path)) {
-               ERROR("The cgroup \"%s\" already existed", h->container_full_path);
+       ret = mkdir_eexist_on_last(h->container_full_path, 0755);
+       if (ret < 0) {
+               ERROR("Failed to create cgroup \"%s\"", h->container_full_path);
                return false;
        }
 
@@ -1296,12 +1328,6 @@ static bool container_create_path_for_hierarchy(struct hierarchy *h, char *cgnam
                return false;
        }
 
-       ret = mkdir_p(h->container_full_path, 0755);
-       if (ret < 0) {
-               ERROR("Failed to create cgroup \"%s\"", h->container_full_path);
-               return false;
-       }
-
        return cg_unified_create_cgroup(h, cgname);
 }
 
index ff6ea3fd73ecc9f749dcbe99988364ba60db48bf..1af6f512c7cc841b67b201cdc27b289d35ffbb83 100644 (file)
@@ -221,26 +221,31 @@ extern int get_u16(unsigned short *val, const char *arg, int base)
        return 0;
 }
 
-extern int mkdir_p(const char *dir, mode_t mode)
+int mkdir_p(const char *dir, mode_t mode)
 {
        const char *tmp = dir;
        const char *orig = dir;
-       char *makeme;
-
        do {
+               int ret;
+               char *makeme;
+
                dir = tmp + strspn(tmp, "/");
                tmp = dir + strcspn(dir, "/");
 
+               errno = ENOMEM;
                makeme = strndup(orig, dir - orig);
-               if (*makeme) {
-                       if (mkdir(makeme, mode) && errno != EEXIST) {
-                               SYSERROR("failed to create directory '%s'", makeme);
-                               free(makeme);
-                               return -1;
-                       }
+               if (!makeme)
+                       return -1;
+
+               ret = mkdir(makeme, mode);
+               if (ret < 0 && errno != EEXIST) {
+                       SYSERROR("Failed to create directory \"%s\"", makeme);
+                       free(makeme);
+                       return -1;
                }
                free(makeme);
-       } while(tmp != dir);
+
+       } while (tmp != dir);
 
        return 0;
 }