mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-07-27 11:13:50 +00:00
Merge pull request #3120 from brauner/2019-08-15/cgroup2_freezer
cgroups: support cgroup2 freezer
This commit is contained in:
commit
b14cd8ac4f
@ -43,6 +43,8 @@
|
||||
#include <grp.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <linux/types.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -1793,8 +1795,23 @@ __cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops,
|
||||
else if (type == LXC_AUTO_CGROUP_FULL_NOSPEC)
|
||||
type = LXC_AUTO_CGROUP_FULL_MIXED;
|
||||
|
||||
/* Mount tmpfs */
|
||||
tmpfspath = must_make_path(root, "/sys/fs/cgroup", NULL);
|
||||
if (ops->cgroup_layout == CGROUP_LAYOUT_UNIFIED) {
|
||||
__do_free char *unified_path = NULL;
|
||||
|
||||
unified_path = must_make_path(root, "/sys/fs/cgroup", NULL);
|
||||
if (has_cgns && wants_force_mount) {
|
||||
/* If cgroup namespaces are supported but the container
|
||||
* will not have CAP_SYS_ADMIN after it has started we
|
||||
* need to mount the cgroups manually.
|
||||
*/
|
||||
return cg_mount_in_cgroup_namespace(type, ops->unified,
|
||||
unified_path) == 0;
|
||||
}
|
||||
|
||||
return cg_mount_cgroup_full(type, ops->unified, unified_path) == 0;
|
||||
}
|
||||
|
||||
/* mount tmpfs */
|
||||
ret = safe_mount(NULL, tmpfspath, "tmpfs",
|
||||
MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME,
|
||||
"size=10240k,mode=755", root);
|
||||
@ -1958,30 +1975,107 @@ __cgfsng_ops static bool cgfsng_get_hierarchies(struct cgroup_ops *ops, int n, c
|
||||
return true;
|
||||
}
|
||||
|
||||
#define THAWED "THAWED"
|
||||
#define THAWED_LEN (strlen(THAWED))
|
||||
|
||||
/* TODO: If the unified cgroup hierarchy grows a freezer controller this needs
|
||||
* to be adapted.
|
||||
*/
|
||||
__cgfsng_ops static bool cgfsng_unfreeze(struct cgroup_ops *ops)
|
||||
static bool poll_file_ready(int lfd)
|
||||
{
|
||||
int ret;
|
||||
__do_free char *fullpath = NULL;
|
||||
struct pollfd pfd = {
|
||||
.fd = lfd,
|
||||
.events = POLLIN,
|
||||
.revents = 0,
|
||||
};
|
||||
|
||||
again:
|
||||
ret = poll(&pfd, 1, 60000);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
goto again;
|
||||
|
||||
SYSERROR("Failed to poll() on file descriptor");
|
||||
return false;
|
||||
}
|
||||
|
||||
return (pfd.revents & POLLIN);
|
||||
}
|
||||
|
||||
__cgfsng_ops static bool cgfsng_freeze(struct cgroup_ops *ops)
|
||||
{
|
||||
int ret;
|
||||
__do_close_prot_errno int fd = -EBADF;
|
||||
__do_free char *events_file = NULL, *fullpath = NULL, *line = NULL;
|
||||
__do_fclose FILE *f = NULL;
|
||||
struct hierarchy *h;
|
||||
|
||||
if (ops->cgroup_layout != CGROUP_LAYOUT_UNIFIED) {
|
||||
h = get_hierarchy(ops, "freezer");
|
||||
if (!h)
|
||||
return false;
|
||||
|
||||
fullpath = must_make_path(h->container_full_path, "freezer.state", NULL);
|
||||
ret = lxc_write_to_file(fullpath, THAWED, THAWED_LEN, false, 0666);
|
||||
fullpath = must_make_path(h->container_full_path,
|
||||
"freezer.state", NULL);
|
||||
return lxc_write_to_file(fullpath, "FROZEN",
|
||||
STRLITERALLEN("FROZEN"), false,
|
||||
0666) == 0;
|
||||
}
|
||||
|
||||
h = ops->unified;
|
||||
if (!h)
|
||||
return false;
|
||||
|
||||
fullpath = must_make_path(h->container_full_path, "cgroup.freeze", NULL);
|
||||
ret = lxc_write_to_file(fullpath, "1", 1, false, 0666);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
|
||||
events_file =
|
||||
must_make_path(h->container_full_path, "cgroup.events", NULL);
|
||||
fd = open(events_file, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return false;
|
||||
|
||||
f = fdopen(fd, "re");
|
||||
if (!f)
|
||||
return false;
|
||||
move_fd(fd);
|
||||
|
||||
for (int i = 0; i < 10 && poll_file_ready(fd); i++) {
|
||||
size_t len;
|
||||
|
||||
while (getline(&line, &len, f) != -1) {
|
||||
if (strcmp(line, "frozen 1") == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
fseek(f, 0, SEEK_SET);
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
__cgfsng_ops static bool cgfsng_unfreeze(struct cgroup_ops *ops)
|
||||
{
|
||||
__do_free char *fullpath = NULL;
|
||||
struct hierarchy *h;
|
||||
|
||||
if (ops->cgroup_layout != CGROUP_LAYOUT_UNIFIED) {
|
||||
h = get_hierarchy(ops, "freezer");
|
||||
if (!h)
|
||||
return false;
|
||||
|
||||
fullpath = must_make_path(h->container_full_path,
|
||||
"freezer.state", NULL);
|
||||
return lxc_write_to_file(fullpath, "THAWED",
|
||||
STRLITERALLEN("THAWED"), false,
|
||||
0666) == 0;
|
||||
}
|
||||
|
||||
h = ops->unified;
|
||||
if (!h)
|
||||
return false;
|
||||
|
||||
fullpath = must_make_path(h->container_full_path, "cgroup.freeze", NULL);
|
||||
return lxc_write_to_file(fullpath, "0", 1, false, 0666) == 0;
|
||||
}
|
||||
|
||||
__cgfsng_ops static const char *cgfsng_get_cgroup(struct cgroup_ops *ops,
|
||||
const char *controller)
|
||||
{
|
||||
@ -2767,6 +2861,7 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf)
|
||||
cgfsng_ops->get_cgroup = cgfsng_get_cgroup;
|
||||
cgfsng_ops->get = cgfsng_get;
|
||||
cgfsng_ops->set = cgfsng_set;
|
||||
cgfsng_ops->freeze = cgfsng_freeze;
|
||||
cgfsng_ops->unfreeze = cgfsng_unfreeze;
|
||||
cgfsng_ops->setup_limits = cgfsng_setup_limits;
|
||||
cgfsng_ops->driver = "cgfsng";
|
||||
|
@ -154,6 +154,7 @@ struct cgroup_ops {
|
||||
const char *value, const char *name, const char *lxcpath);
|
||||
int (*get)(struct cgroup_ops *ops, const char *filename, char *value,
|
||||
size_t len, const char *name, const char *lxcpath);
|
||||
bool (*freeze)(struct cgroup_ops *ops);
|
||||
bool (*unfreeze)(struct cgroup_ops *ops);
|
||||
bool (*setup_limits)(struct cgroup_ops *ops, struct lxc_conf *conf,
|
||||
bool with_devices);
|
||||
|
@ -62,17 +62,20 @@ static int do_freeze_thaw(bool freeze, struct lxc_conf *conf, const char *name,
|
||||
if (!cgroup_ops)
|
||||
return -1;
|
||||
|
||||
ret = cgroup_ops->set(cgroup_ops, "freezer.state", state, name, lxcpath);
|
||||
if (cgroup_ops->cgroup_layout != CGROUP_LAYOUT_UNIFIED) {
|
||||
ret = cgroup_ops->set(cgroup_ops, "freezer.state", state, name,
|
||||
lxcpath);
|
||||
if (ret < 0) {
|
||||
cgroup_exit(cgroup_ops);
|
||||
ERROR("Failed to %s %s",
|
||||
(new_state == FROZEN ? "freeze" : "unfreeze"), name);
|
||||
(new_state == FROZEN ? "freeze" : "unfreeze"),
|
||||
name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
ret = cgroup_ops->get(cgroup_ops, "freezer.state", v, sizeof(v),
|
||||
name, lxcpath);
|
||||
ret = cgroup_ops->get(cgroup_ops, "freezer.state", v,
|
||||
sizeof(v), name, lxcpath);
|
||||
if (ret < 0) {
|
||||
cgroup_exit(cgroup_ops);
|
||||
ERROR("Failed to get freezer state of %s", name);
|
||||
@ -85,7 +88,8 @@ static int do_freeze_thaw(bool freeze, struct lxc_conf *conf, const char *name,
|
||||
ret = strncmp(v, state, state_len);
|
||||
if (ret == 0) {
|
||||
cgroup_exit(cgroup_ops);
|
||||
lxc_cmd_serve_state_clients(name, lxcpath, new_state);
|
||||
lxc_cmd_serve_state_clients(name, lxcpath,
|
||||
new_state);
|
||||
lxc_monitor_send_state(name, new_state, lxcpath);
|
||||
return 0;
|
||||
}
|
||||
@ -94,6 +98,15 @@ static int do_freeze_thaw(bool freeze, struct lxc_conf *conf, const char *name,
|
||||
}
|
||||
}
|
||||
|
||||
ret = cgroup_ops->freeze(cgroup_ops);
|
||||
cgroup_exit(cgroup_ops);
|
||||
if (ret < 0)
|
||||
return error_log_errno(-1, "Failed to %s container",
|
||||
freeze ? "freeze" : "unfreeze");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lxc_freeze(struct lxc_conf *conf, const char *name, const char *lxcpath)
|
||||
{
|
||||
lxc_cmd_serve_state_clients(name, lxcpath, FREEZING);
|
||||
|
Loading…
Reference in New Issue
Block a user