mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-07-27 12:37:35 +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 <grp.h>
|
||||||
#include <linux/kdev_t.h>
|
#include <linux/kdev_t.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -1759,8 +1761,8 @@ static inline int cg_mount_cgroup_full(int type, struct hierarchy *h,
|
|||||||
}
|
}
|
||||||
|
|
||||||
__cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops,
|
__cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops,
|
||||||
struct lxc_handler *handler,
|
struct lxc_handler *handler,
|
||||||
const char *root, int type)
|
const char *root, int type)
|
||||||
{
|
{
|
||||||
__do_free char *tmpfspath = NULL;
|
__do_free char *tmpfspath = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
@ -1793,8 +1795,23 @@ __cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops,
|
|||||||
else if (type == LXC_AUTO_CGROUP_FULL_NOSPEC)
|
else if (type == LXC_AUTO_CGROUP_FULL_NOSPEC)
|
||||||
type = LXC_AUTO_CGROUP_FULL_MIXED;
|
type = LXC_AUTO_CGROUP_FULL_MIXED;
|
||||||
|
|
||||||
/* Mount tmpfs */
|
if (ops->cgroup_layout == CGROUP_LAYOUT_UNIFIED) {
|
||||||
tmpfspath = must_make_path(root, "/sys/fs/cgroup", NULL);
|
__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",
|
ret = safe_mount(NULL, tmpfspath, "tmpfs",
|
||||||
MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME,
|
MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME,
|
||||||
"size=10240k,mode=755", root);
|
"size=10240k,mode=755", root);
|
||||||
@ -1958,28 +1975,105 @@ __cgfsng_ops static bool cgfsng_get_hierarchies(struct cgroup_ops *ops, int n, c
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define THAWED "THAWED"
|
static bool poll_file_ready(int lfd)
|
||||||
#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)
|
|
||||||
{
|
{
|
||||||
int ret;
|
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;
|
struct hierarchy *h;
|
||||||
|
|
||||||
h = get_hierarchy(ops, "freezer");
|
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, "FROZEN",
|
||||||
|
STRLITERALLEN("FROZEN"), false,
|
||||||
|
0666) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h = ops->unified;
|
||||||
if (!h)
|
if (!h)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
fullpath = must_make_path(h->container_full_path, "freezer.state", NULL);
|
fullpath = must_make_path(h->container_full_path, "cgroup.freeze", NULL);
|
||||||
ret = lxc_write_to_file(fullpath, THAWED, THAWED_LEN, false, 0666);
|
ret = lxc_write_to_file(fullpath, "1", 1, false, 0666);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
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,
|
__cgfsng_ops static const char *cgfsng_get_cgroup(struct cgroup_ops *ops,
|
||||||
@ -2767,6 +2861,7 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf)
|
|||||||
cgfsng_ops->get_cgroup = cgfsng_get_cgroup;
|
cgfsng_ops->get_cgroup = cgfsng_get_cgroup;
|
||||||
cgfsng_ops->get = cgfsng_get;
|
cgfsng_ops->get = cgfsng_get;
|
||||||
cgfsng_ops->set = cgfsng_set;
|
cgfsng_ops->set = cgfsng_set;
|
||||||
|
cgfsng_ops->freeze = cgfsng_freeze;
|
||||||
cgfsng_ops->unfreeze = cgfsng_unfreeze;
|
cgfsng_ops->unfreeze = cgfsng_unfreeze;
|
||||||
cgfsng_ops->setup_limits = cgfsng_setup_limits;
|
cgfsng_ops->setup_limits = cgfsng_setup_limits;
|
||||||
cgfsng_ops->driver = "cgfsng";
|
cgfsng_ops->driver = "cgfsng";
|
||||||
|
@ -154,6 +154,7 @@ struct cgroup_ops {
|
|||||||
const char *value, const char *name, const char *lxcpath);
|
const char *value, const char *name, const char *lxcpath);
|
||||||
int (*get)(struct cgroup_ops *ops, const char *filename, char *value,
|
int (*get)(struct cgroup_ops *ops, const char *filename, char *value,
|
||||||
size_t len, const char *name, const char *lxcpath);
|
size_t len, const char *name, const char *lxcpath);
|
||||||
|
bool (*freeze)(struct cgroup_ops *ops);
|
||||||
bool (*unfreeze)(struct cgroup_ops *ops);
|
bool (*unfreeze)(struct cgroup_ops *ops);
|
||||||
bool (*setup_limits)(struct cgroup_ops *ops, struct lxc_conf *conf,
|
bool (*setup_limits)(struct cgroup_ops *ops, struct lxc_conf *conf,
|
||||||
bool with_devices);
|
bool with_devices);
|
||||||
|
@ -62,36 +62,49 @@ static int do_freeze_thaw(bool freeze, struct lxc_conf *conf, const char *name,
|
|||||||
if (!cgroup_ops)
|
if (!cgroup_ops)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
ret = cgroup_ops->set(cgroup_ops, "freezer.state", state, name, lxcpath);
|
if (cgroup_ops->cgroup_layout != CGROUP_LAYOUT_UNIFIED) {
|
||||||
if (ret < 0) {
|
ret = cgroup_ops->set(cgroup_ops, "freezer.state", state, name,
|
||||||
cgroup_exit(cgroup_ops);
|
lxcpath);
|
||||||
ERROR("Failed to %s %s",
|
|
||||||
(new_state == FROZEN ? "freeze" : "unfreeze"), name);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
ret = cgroup_ops->get(cgroup_ops, "freezer.state", v, sizeof(v),
|
|
||||||
name, lxcpath);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
cgroup_exit(cgroup_ops);
|
cgroup_exit(cgroup_ops);
|
||||||
ERROR("Failed to get freezer state of %s", name);
|
ERROR("Failed to %s %s",
|
||||||
|
(new_state == FROZEN ? "freeze" : "unfreeze"),
|
||||||
|
name);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
v[sizeof(v) - 1] = '\0';
|
for (;;) {
|
||||||
v[lxc_char_right_gc(v, strlen(v))] = '\0';
|
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);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ret = strncmp(v, state, state_len);
|
v[sizeof(v) - 1] = '\0';
|
||||||
if (ret == 0) {
|
v[lxc_char_right_gc(v, strlen(v))] = '\0';
|
||||||
cgroup_exit(cgroup_ops);
|
|
||||||
lxc_cmd_serve_state_clients(name, lxcpath, new_state);
|
ret = strncmp(v, state, state_len);
|
||||||
lxc_monitor_send_state(name, new_state, lxcpath);
|
if (ret == 0) {
|
||||||
return 0;
|
cgroup_exit(cgroup_ops);
|
||||||
|
lxc_cmd_serve_state_clients(name, lxcpath,
|
||||||
|
new_state);
|
||||||
|
lxc_monitor_send_state(name, new_state, lxcpath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
int lxc_freeze(struct lxc_conf *conf, const char *name, const char *lxcpath)
|
||||||
|
Loading…
Reference in New Issue
Block a user