Skip to content

Commit

Permalink
cgroups: fd-based only cgroup creation
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
  • Loading branch information
Christian Brauner committed Feb 26, 2021
1 parent 8acaf48 commit b7b1e3a
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 54 deletions.
126 changes: 75 additions & 51 deletions src/lxc/cgroups/cgfsng.c
Expand Up @@ -1130,67 +1130,88 @@ __cgfsng_ops static void cgfsng_monitor_destroy(struct cgroup_ops *ops,
}
}

static int mkdir_eexist_on_last(const char *dir, mode_t mode)
static int __cgroup_tree_create(int dfd_base, const char *path, mode_t mode)
{
const char *tmp = dir;
const char *orig = dir;
size_t orig_len;
__do_close int dfd_final = -EBADF;
int dfd_cur = dfd_base;
int ret = 0;
size_t len;
char *cur;
char buf[PATH_MAX];

orig_len = strlen(dir);
do {
__do_free char *makeme = NULL;
int ret;
size_t cur_len;
if (is_empty_string(path))
return ret_errno(-EINVAL);

dir = tmp + strspn(tmp, "/");
tmp = dir + strcspn(dir, "/");
len = strlcpy(buf, path, sizeof(buf));
if (len >= sizeof(buf))
return -E2BIG;

cur_len = dir - orig;
makeme = strndup(orig, cur_len);
if (!makeme)
return ret_set_errno(-1, ENOMEM);
lxc_iterate_parts(cur, buf, "/") {
/*
* Even though we vetted the paths when we parsed the config
* we're paranoid here and check that the path is neither
* absolute nor walks upwards.
*/
if (abspath(buf))
return syserrno_set(-EINVAL, "No absolute paths allowed");

ret = mkdir(makeme, mode);
if (ret < 0 && ((errno != EEXIST) || (orig_len == cur_len)))
return log_warn_errno(-1, errno, "Failed to create directory \"%s\"", makeme);
} while (tmp != dir);
if (strnequal(buf, "..", STRLITERALLEN("..")))
return syserrno_set(-EINVAL, "No upward walking paths allowed");

return 0;
ret = mkdirat(dfd_cur, cur, mode);
if (ret < 0) {
if (errno != EEXIST)
return syserrno(-errno, "Failed to create %d(%s)", dfd_cur, cur);

ret = -EEXIST;
}
TRACE("%s %d(%s) cgroup", !ret ? "Created" : "Reusing", dfd_cur, cur);

dfd_final = open_at(dfd_cur, cur, PROTECT_OPATH_DIRECTORY, PROTECT_LOOKUP_BENEATH, 0);
if (dfd_final < 0)
return syserrno(-errno, "Fail to open%s directory %d(%s)",
!ret ? " newly created" : "", dfd_base, cur);
if (dfd_cur != dfd_base)
close(dfd_cur);

/*
* Leave dfd_final pointing to the last fd we opened so it will
* be automatically zapped if we return early.
*/
dfd_cur = dfd_final;
}

/* The final cgroup must be succesfully creatd by us. */
if (ret)
return syserrno_set(ret, "Creating the final cgroup %d(%s) failed", dfd_base, path);

return move_fd(dfd_final);
}

static bool cgroup_tree_create(struct cgroup_ops *ops, struct lxc_conf *conf,
struct hierarchy *h, const char *cgroup_tree,
const char *cgroup_leaf, bool payload,
const char *cgroup_limit_dir)
{
__do_close int fd_limit = -EBADF, fd_final = -EBADF;
__do_free char *path = NULL, *limit_path = NULL;
int ret, ret_cpuset;
int ret_cpuset;

path = must_make_path(h->mountpoint, h->container_base_path, cgroup_leaf, NULL);
if (dir_exists(path))
return log_warn_errno(false, errno, "The %s cgroup already existed", path);
/* Don't bother with all the rest if the final cgroup already exists. */
if (exists_dir_at(h->dfd_base, cgroup_leaf))
return syswarn(false, "The %d(%s) cgroup already existed", h->dfd_base, cgroup_leaf);

ret_cpuset = cg_legacy_handle_cpuset_hierarchy(h, cgroup_leaf);
if (ret_cpuset < 0)
return log_error_errno(false, errno, "Failed to handle legacy cpuset controller");

if (payload && cgroup_limit_dir) {
/* with isolation both parts need to not already exist */
limit_path = must_make_path(h->mountpoint,
h->container_base_path,
cgroup_limit_dir, NULL);
/* With isolation both parts need to not already exist. */
fd_limit = __cgroup_tree_create(h->dfd_base, cgroup_limit_dir, 0755);
if (fd_limit < 0)
return syserrno(false, "Failed to create limiting cgroup %d(%s)", h->dfd_base, cgroup_limit_dir);

ret = mkdir_eexist_on_last(limit_path, 0755);
if (ret < 0)
return log_debug_errno(false,
errno, "Failed to create %s limiting cgroup",
limit_path);

h->cgfd_limit = lxc_open_dirfd(limit_path);
if (h->cgfd_limit < 0)
return log_error_errno(false, errno,
"Failed to open %s", path);
h->container_limit_path = move_ptr(limit_path);
limit_path = must_make_path(h->mountpoint, h->container_base_path, cgroup_limit_dir, NULL);

/*
* With isolation the devices legacy cgroup needs to be
Expand All @@ -1205,30 +1226,33 @@ static bool cgroup_tree_create(struct cgroup_ops *ops, struct lxc_conf *conf,
}
}

ret = mkdir_eexist_on_last(path, 0755);
if (ret < 0) {
fd_final = __cgroup_tree_create(h->dfd_base, cgroup_leaf, 0755);
if (fd_final < 0) {
/*
* This is the cpuset controller and
* cg_legacy_handle_cpuset_hierarchy() has created our target
* directory for us to ensure correct initialization.
*/
if (ret_cpuset != 1 || cgroup_tree)
return log_debug_errno(false, errno, "Failed to create %s cgroup", path);
return sysdebug(false, "Failed to create payload cgroup %d(%s)", h->dfd_base, cgroup_leaf);
}

path = must_make_path(h->mountpoint, h->container_base_path, cgroup_leaf, NULL);
if (payload) {
h->cgfd_con = lxc_open_dirfd(path);
if (h->cgfd_con < 0)
return log_error_errno(false, errno, "Failed to open %s", path);
h->cgfd_con = move_fd(fd_final);
h->container_full_path = move_ptr(path);
if (h->cgfd_limit < 0)

if (fd_limit < 0)
h->cgfd_limit = h->cgfd_con;
if (!h->container_limit_path)
else
h->cgfd_limit = move_fd(fd_limit);

if (!limit_path)
h->container_limit_path = h->container_full_path;
else
h->container_limit_path = move_ptr(limit_path);
} else {
h->cgfd_mon = lxc_open_dirfd(path);
if (h->cgfd_mon < 0)
return log_error_errno(false, errno, "Failed to open %s", path);
h->cgfd_mon = move_fd(fd_final);
h->monitor_full_path = move_ptr(path);
}

Expand Down Expand Up @@ -1355,7 +1379,7 @@ __cgfsng_ops static bool cgfsng_monitor_create(struct cgroup_ops *ops, struct lx
monitor_cgroup, false, NULL))
continue;

DEBUG("Failed to create cgroup \"%s\"", ops->hierarchies[i]->monitor_full_path ?: "(null)");
DEBUG("Failed to create cgroup \"%s\"", maybe_empty(ops->hierarchies[i]->monitor_full_path));
for (int j = 0; j < i; j++)
cgroup_tree_leaf_remove(ops->hierarchies[j], false);

Expand Down
16 changes: 13 additions & 3 deletions src/lxc/file_utils.c
Expand Up @@ -630,21 +630,31 @@ int timens_offset_write(clockid_t clk_id, int64_t s_offset, int64_t ns_offset)

bool exists_dir_at(int dir_fd, const char *path)
{
struct stat sb;
int ret;
struct stat sb;

ret = fstatat(dir_fd, path, &sb, 0);
if (ret < 0)
return false;

return S_ISDIR(sb.st_mode);
ret = S_ISDIR(sb.st_mode);
if (ret)
errno = EEXIST;
else
errno = ENOTDIR;

return ret;
}

bool exists_file_at(int dir_fd, const char *path)
{
int ret;
struct stat sb;

return fstatat(dir_fd, path, &sb, 0) == 0;
ret = fstatat(dir_fd, path, &sb, 0);
if (ret == 0)
errno = EEXIST;
return ret == 0;
}

int open_at(int dfd, const char *path, unsigned int o_flags,
Expand Down
14 changes: 14 additions & 0 deletions src/lxc/log.h
Expand Up @@ -501,6 +501,20 @@ __lxc_unused static inline void LXC_##LEVEL(struct lxc_log_locinfo* locinfo, \
__internal_ret__; \
})

#define syswarn(__ret__, format, ...) \
({ \
typeof(__ret__) __internal_ret__ = (__ret__); \
SYSWARN(format, ##__VA_ARGS__); \
__internal_ret__; \
})

#define sysdebug(__ret__, format, ...) \
({ \
typeof(__ret__) __internal_ret__ = (__ret__); \
SYSDEBUG(format, ##__VA_ARGS__); \
__internal_ret__; \
})

#define syserrno_set(__ret__, format, ...) \
({ \
typeof(__ret__) __internal_ret__ = (__ret__); \
Expand Down

0 comments on commit b7b1e3a

Please sign in to comment.