Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 31 additions & 16 deletions src/cgroups/cgfsng.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,24 +399,39 @@ static void trim(char *s)
*/
static int __cg_mount_direct(struct hierarchy *h, const char *controllerpath)
{
__do_free char *controllers = NULL;
char *fstype = "cgroup2";
unsigned long flags = 0;
int ret;

flags |= MS_NOSUID;
flags |= MS_NOEXEC;
flags |= MS_NODEV;
flags |= MS_RELATIME;

if (h->version != CGROUP2_SUPER_MAGIC) {
controllers = lxc_string_join(",", (const char **)h->controllers, false);
if (!controllers)
return -ENOMEM;
fstype = "cgroup";
__do_free char *controllers = NULL;
char *fstype = "cgroup2";
unsigned long flags = 0;
int ret;

flags |= MS_NOSUID;
flags |= MS_NOEXEC;
flags |= MS_NODEV;
flags |= MS_RELATIME;

if (h->version != CGROUP2_SUPER_MAGIC) {
controllers = lxc_string_join(",", (const char **)h->controllers, false);
if (!controllers)
return -ENOMEM;
fstype = "cgroup";
ret = mount("cgroup", controllerpath, fstype, flags, controllers);
} else {
__do_free const char *sb_opts = NULL;

/*
* Before mounting cgroup2 fs we have to try out best to find
* an existing mount and extract mount existing mount options from it.
* It is important because otherwise we can change cgroup2 superblock
* options. See kernel logic in apply_cgroup_root_flags for more details:
* https://github.com/torvalds/linux/blob/18f7fcd5e69a04df57b563360b88be72471d6b62/kernel/cgroup/cgroup.c#L2047
*
* If we haven't found an existing mount, just mount a new one with
* an empty list of options.
*/
sb_opts = cgroup2_extract_sb_opts(DEFAULT_CGROUP_MOUNTPOINT);
ret = mount(fstype, controllerpath, fstype, flags, sb_opts);
}

ret = mount("cgroup", controllerpath, fstype, flags, controllers);
if (ret < 0)
return -1;

Expand Down
86 changes: 86 additions & 0 deletions src/cgroups/cgroup_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <sys/types.h>
#include <sys/vfs.h>
#include <unistd.h>
#include <mntent.h>

#include "../macro.h"
#include "../memory_utils.h"
Expand Down Expand Up @@ -810,3 +811,88 @@ int cgroup_walkup_to_root(int cgroup2_root_fd, int hierarchy_fd,

return log_error_errno(-ELOOP, ELOOP, "To many nested cgroups or invalid mount tree. Terminating walk");
}

/**
* get_mount_opts() - Returns the mount options for a given mnt and with fs_type
*
* @mnt: Mount point.
* @fs_type: File system type.
*
* Returns: mount options if success, NULL if mount is not found or error occurred.
*/
static char *get_mount_opts(const char *mnt, const char *fs_type) {
FILE *fp;
char *mnt_opts = NULL;
struct mntent *ent;

if (mnt == NULL || fs_type == NULL)
return NULL;

fp = setmntent("/proc/self/mounts", "r");
if (!fp)
return NULL;

while ((ent = getmntent(fp)) != NULL) {
if (strncmp(ent->mnt_dir, mnt, strlen(mnt)) == 0 &&
strncmp(ent->mnt_type, fs_type, strlen(fs_type)) == 0) {
mnt_opts = strdup(ent->mnt_opts); /* allocate, caller frees */
goto out;
}
}

out:
endmntent(fp);
return mnt_opts;
}

/**
* cgroup2_extract_sb_opts() - Returns cgroup2 fs superblock options for a given mount point
*
* @mnt: cgroup2 fs mount point.
*
* Returns: sb options if success, NULL if mount is not found or error occurred.
*/
const char *cgroup2_extract_sb_opts(const char *mnt)
{
__do_free char *mnt_opts = NULL;
char *tok;
char *buf;
size_t buf_len = 0;
static const char *wanted_opts[] = {
"nsdelegate",
"favordynmods",
"memory_localevents",
"memory_recursiveprot",
"memory_hugetlb_accounting",
"pids_localevents",
NULL
};

mnt_opts = get_mount_opts(mnt, "cgroup2");
if (mnt_opts == NULL) {
/* report as info, because it is not critical */
lxcfs_info("Failed to find an existing cgroup2 mount and get mount options from it");
return NULL;
}

for (int i = 0; wanted_opts[i] != NULL; i++)
buf_len += strlen(wanted_opts[i]) + 1; /* for comma or null terminator */

buf = calloc(buf_len, 1);
if (!buf)
return NULL;
buf[0] = '\0';

lxc_iterate_parts(tok, mnt_opts, ",") {
for (int i = 0; wanted_opts[i] != NULL; i++) {
if (strcmp(tok, wanted_opts[i]) != 0)
continue;

if (buf[0] != '\0')
(void)strlcat(buf, ",", buf_len);
(void)strlcat(buf, tok, buf_len);
}
}

return buf;
}
2 changes: 2 additions & 0 deletions src/cgroups/cgroup_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,6 @@ static inline bool is_empty_string(const char *s)
return !s || strcmp(s, "") == 0;
}

const char *cgroup2_extract_sb_opts(const char *mnt);

#endif /* __LXC_CGROUP_UTILS_H */
Loading