[lxc-devel] [lxc/master] cgroups: implement monitor cgroup deletion

brauner on Github lxc-bot at linuxcontainers.org
Sun Sep 23 22:08:47 UTC 2018


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 1074 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20180923/c8868750/attachment.bin>
-------------- next part --------------
From a4e55b420a3d83166f0363922273e706fa479b04 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 23 Sep 2018 17:55:27 +0200
Subject: [PATCH 1/2] cgfsng: s/cgfsng_destroy/cgfsng_payload_destroy/g

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/cgroups/cgfsng.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index 3df279377..1523e4d59 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -1102,7 +1102,8 @@ static int cgroup_rmdir_wrapper(void *data)
 	return cgroup_rmdir(arg->hierarchies, arg->container_cgroup);
 }
 
-__cgfsng_ops static void cgfsng_destroy(struct cgroup_ops *ops, struct lxc_handler *handler)
+__cgfsng_ops__ static void cgfsng_payload_destroy(struct cgroup_ops *ops,
+		struct lxc_handler *handler)
 {
 	int ret;
 	struct generic_userns_exec_data wrap;
@@ -2672,7 +2673,7 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf)
 	}
 
 	cgfsng_ops->data_init = cgfsng_data_init;
-	cgfsng_ops->destroy = cgfsng_destroy;
+	cgfsng_ops->destroy = cgfsng_payload_destroy;
 	cgfsng_ops->monitor_create = cgfsng_monitor_create;
 	cgfsng_ops->monitor_enter = cgfsng_monitor_enter;
 	cgfsng_ops->payload_create = cgfsng_payload_create;

From 79d2db4443f7ce4cfbf756e48930251de894c5c4 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Sun, 23 Sep 2018 20:11:56 +0200
Subject: [PATCH 2/2] cgfsng: add cgfsng_monitor_destroy()

Since we switched to the new cgroup scoping scheme that places the
container payload into lxc.payload/<container-name> and
lxc.monitor/<container-name> deletion becomes slightly more complicated.
The monitor will be able to rm_rf(lxc.payload/<container-name>) but will
not be able to rm_rf(lxc.monitor/<container-name>) since it will be
located in that cgroup and it will thus be populated.
My current solution to this is to create a lxc.pivot cgroup that only
exists so that the monitor process on container stop can pivot into it,
call rm_rf(lxc.monitor/<container-name>) and can then exit. This group
has not function whatsoever apart from this and can thus be shared by
all monitor processes.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/cgroups/cgfsng.c | 62 ++++++++++++++++++++++++++++++++++++++--
 src/lxc/cgroups/cgroup.h |  3 +-
 src/lxc/start.c          | 13 ++++++---
 src/lxc/start.h          |  3 ++
 4 files changed, 73 insertions(+), 8 deletions(-)

diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index 1523e4d59..dd27860bc 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -1102,8 +1102,8 @@ static int cgroup_rmdir_wrapper(void *data)
 	return cgroup_rmdir(arg->hierarchies, arg->container_cgroup);
 }
 
-__cgfsng_ops__ static void cgfsng_payload_destroy(struct cgroup_ops *ops,
-		struct lxc_handler *handler)
+__cgfsng_ops static void cgfsng_payload_destroy(struct cgroup_ops *ops,
+						struct lxc_handler *handler)
 {
 	int ret;
 	struct generic_userns_exec_data wrap;
@@ -1124,6 +1124,61 @@ __cgfsng_ops__ static void cgfsng_payload_destroy(struct cgroup_ops *ops,
 	}
 }
 
+__cgfsng_ops static void cgfsng_monitor_destroy(struct cgroup_ops *ops,
+						struct lxc_handler *handler)
+{
+	int len;
+	char *pivot_path;
+	struct lxc_conf *conf = handler->conf;
+	char pidstr[25];
+
+	if (!ops->hierarchies)
+		return;
+
+	len = snprintf(pidstr, 25, "%d", handler->monitor_pid);
+	if (len < 0 || len >= 25)
+		return;
+
+	for (int i = 0; ops->hierarchies[i]; i++) {
+		int ret;
+		char *monitor_cgroup;
+		struct hierarchy *h = ops->hierarchies[i];
+
+		if (!h->monitor_full_path)
+			continue;
+
+		if (conf && conf->cgroup_meta.dir)
+			monitor_cgroup = lxc_string_join("/",
+							(const char *[]){conf->cgroup_meta.dir,
+									 "lxc.pivot",
+									 NULL},
+							false);
+		else
+			monitor_cgroup = must_make_path("lxc.pivot", NULL);
+		if (!monitor_cgroup)
+			return;
+
+		pivot_path = must_make_path(h->mountpoint, h->container_base_path,
+					    monitor_cgroup, "cgroup.procs", NULL);
+		free(monitor_cgroup);
+
+		ret = mkdir_p(pivot_path, 0755);
+		if (ret < 0 && errno != EEXIST)
+			goto next;
+
+		ret = lxc_write_to_file(pivot_path, pidstr, len, false, 0666);
+		if (ret != 0)
+			goto next;
+
+		ret = recursive_destroy(h->monitor_full_path);
+		if (ret < 0)
+			WARN("Failed to destroy \"%s\"", h->monitor_full_path);
+
+	next:
+		free(pivot_path);
+	}
+}
+
 static bool cg_unified_create_cgroup(struct hierarchy *h, char *cgname)
 {
 	size_t i, parts_len;
@@ -2673,7 +2728,8 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf)
 	}
 
 	cgfsng_ops->data_init = cgfsng_data_init;
-	cgfsng_ops->destroy = cgfsng_payload_destroy;
+	cgfsng_ops->payload_destroy = cgfsng_payload_destroy;
+	cgfsng_ops->monitor_destroy = cgfsng_monitor_destroy;
 	cgfsng_ops->monitor_create = cgfsng_monitor_create;
 	cgfsng_ops->monitor_enter = cgfsng_monitor_enter;
 	cgfsng_ops->payload_create = cgfsng_payload_create;
diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h
index 16b880942..f40313aed 100644
--- a/src/lxc/cgroups/cgroup.h
+++ b/src/lxc/cgroups/cgroup.h
@@ -128,7 +128,8 @@ struct cgroup_ops {
 	cgroup_layout_t cgroup_layout;
 
 	bool (*data_init)(struct cgroup_ops *ops);
-	void (*destroy)(struct cgroup_ops *ops, struct lxc_handler *handler);
+	void (*payload_destroy)(struct cgroup_ops *ops, struct lxc_handler *handler);
+	void (*monitor_destroy)(struct cgroup_ops *ops, struct lxc_handler *handler);
 	bool (*monitor_create)(struct cgroup_ops *ops, struct lxc_handler *handler);
 	bool (*monitor_enter)(struct cgroup_ops *ops, pid_t pid);
 	bool (*payload_create)(struct cgroup_ops *ops, struct lxc_handler *handler);
diff --git a/src/lxc/start.c b/src/lxc/start.c
index 0629e90c4..27b677f72 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -725,6 +725,8 @@ int lxc_init(const char *name, struct lxc_handler *handler)
 	const char *loglevel;
 	struct lxc_conf *conf = handler->conf;
 
+	handler->monitor_pid = lxc_raw_getpid();
+
 	lsm_init();
 	TRACE("Initialized LSM");
 
@@ -857,7 +859,8 @@ int lxc_init(const char *name, struct lxc_handler *handler)
 	return 0;
 
 out_destroy_cgroups:
-	handler->cgroup_ops->destroy(handler->cgroup_ops, handler);
+	handler->cgroup_ops->payload_destroy(handler->cgroup_ops, handler);
+	handler->cgroup_ops->monitor_destroy(handler->cgroup_ops, handler);
 
 out_delete_terminal:
 	lxc_terminal_delete(&handler->conf->console);
@@ -951,8 +954,7 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
 
 	lsm_process_cleanup(handler->conf, handler->lxcpath);
 
-	cgroup_ops->destroy(cgroup_ops, handler);
-	cgroup_exit(cgroup_ops);
+	cgroup_ops->payload_destroy(cgroup_ops, handler);
 
 	if (handler->conf->reboot == REBOOT_NONE) {
 		/* For all new state clients simply close the command socket.
@@ -1022,6 +1024,9 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
 	if (handler->conf->ephemeral == 1 && handler->conf->reboot != REBOOT_REQ)
 		lxc_destroy_container_on_signal(handler, name);
 
+	cgroup_ops->monitor_destroy(cgroup_ops, handler);
+	cgroup_exit(cgroup_ops);
+
 	lxc_free_handler(handler);
 }
 
@@ -1971,7 +1976,7 @@ int __lxc_start(const char *name, struct lxc_handler *handler,
 		goto out_fini_nonet;
 	}
 
-	if (!cgroup_ops->monitor_enter(cgroup_ops, lxc_raw_getpid())) {
+	if (!cgroup_ops->monitor_enter(cgroup_ops, handler->monitor_pid)) {
 		ERROR("Failed to enter monitor cgroup");
 		goto out_fini_nonet;
 	}
diff --git a/src/lxc/start.h b/src/lxc/start.h
index bcb852e8b..c3e68f3ae 100644
--- a/src/lxc/start.h
+++ b/src/lxc/start.h
@@ -103,6 +103,9 @@ struct lxc_handler {
 	/* The child's pid. */
 	pid_t pid;
 
+	/* The monitor's pid. */
+	pid_t monitor_pid;
+
 	/* Whether the child has already exited. */
 	bool init_died;
 


More information about the lxc-devel mailing list