core: warn about left-over processes in cgroup on unit start

Now that we don't kill control processes anymore, let's at least warn
about any processes left-over in the unit cgroup at the moment of
starting the unit.
This commit is contained in:
Lennart Poettering 2017-11-24 22:02:22 +01:00
parent e98b2fbbe9
commit a4634b214c
8 changed files with 71 additions and 16 deletions

View File

@ -1394,6 +1394,31 @@ int unit_watch_cgroup(Unit *u) {
return 0;
}
int unit_pick_cgroup_path(Unit *u) {
_cleanup_free_ char *path = NULL;
int r;
assert(u);
if (u->cgroup_path)
return 0;
if (!UNIT_HAS_CGROUP_CONTEXT(u))
return -EINVAL;
path = unit_default_cgroup_path(u);
if (!path)
return log_oom();
r = unit_set_cgroup_path(u, path);
if (r == -EEXIST)
return log_unit_error_errno(u, r, "Control group %s exists already.", path);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to set unit's control group path to %s: %m", path);
return 0;
}
static int unit_create_cgroup(
Unit *u,
CGroupMask target_mask,
@ -1409,19 +1434,10 @@ static int unit_create_cgroup(
if (!c)
return 0;
if (!u->cgroup_path) {
_cleanup_free_ char *path = NULL;
path = unit_default_cgroup_path(u);
if (!path)
return log_oom();
r = unit_set_cgroup_path(u, path);
if (r == -EEXIST)
return log_unit_error_errno(u, r, "Control group %s exists already.", path);
if (r < 0)
return log_unit_error_errno(u, r, "Failed to set unit's control group path to %s: %m", path);
}
/* Figure out our cgroup path */
r = unit_pick_cgroup_path(u);
if (r < 0)
return r;
/* First, create our own group */
r = cg_create_everywhere(u->manager->cgroup_supported, target_mask, u->cgroup_path);

View File

@ -169,6 +169,7 @@ void unit_update_cgroup_members_masks(Unit *u);
char *unit_default_cgroup_path(Unit *u);
int unit_set_cgroup_path(Unit *u, const char *path);
int unit_pick_cgroup_path(Unit *u);
int unit_realize_cgroup(Unit *u);
void unit_release_cgroup(Unit *u);

View File

@ -938,9 +938,6 @@ static void mount_enter_mounting(Mount *m) {
assert(m);
m->control_command_id = MOUNT_EXEC_MOUNT;
m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
r = unit_fail_if_symlink(UNIT(m), m->where);
if (r < 0)
goto fail;
@ -949,6 +946,11 @@ static void mount_enter_mounting(Mount *m) {
unit_warn_if_dir_nonempty(UNIT(m), m->where);
unit_warn_leftover_processes(UNIT(m));
m->control_command_id = MOUNT_EXEC_MOUNT;
m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
/* Create the source directory for bind-mounts if needed */
p = get_mount_parameters_fragment(m);
if (p && mount_is_bind(p))

View File

@ -1814,6 +1814,8 @@ static void service_enter_start(Service *s) {
service_unwatch_control_pid(s);
service_unwatch_main_pid(s);
unit_warn_leftover_processes(UNIT(s));
if (s->type == SERVICE_FORKING) {
s->control_command_id = SERVICE_EXEC_START;
c = s->control_command = s->exec_command[SERVICE_EXEC_START];
@ -1901,6 +1903,8 @@ static void service_enter_start_pre(Service *s) {
s->control_command = s->exec_command[SERVICE_EXEC_START_PRE];
if (s->control_command) {
unit_warn_leftover_processes(UNIT(s));
s->control_command_id = SERVICE_EXEC_START_PRE;
r = service_spawn(s,

View File

@ -2187,6 +2187,9 @@ static void socket_enter_start_pre(Socket *s) {
assert(s);
socket_unwatch_control_pid(s);
unit_warn_leftover_processes(UNIT(s));
s->control_command_id = SOCKET_EXEC_START_PRE;
s->control_command = s->exec_command[SOCKET_EXEC_START_PRE];

View File

@ -734,6 +734,8 @@ static void swap_enter_activating(Swap *s) {
assert(s);
unit_warn_leftover_processes(UNIT(s));
s->control_command_id = SWAP_EXEC_ACTIVATE;
s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE;

View File

@ -5196,6 +5196,31 @@ int unit_prepare_exec(Unit *u) {
return 0;
}
static void log_leftover(pid_t pid, int sig, void *userdata) {
_cleanup_free_ char *comm = NULL;
(void) get_process_comm(pid, &comm);
if (comm && comm[0] == '(') /* Most likely our own helper process (PAM?), ignore */
return;
log_unit_warning(userdata,
"Found left-over process " PID_FMT " (%s) in control group while starting unit. Ignoring.\n"
"This usually indicates unclean termination of a previous run, or service implementation deficiencies.",
pid, strna(comm));
}
void unit_warn_leftover_processes(Unit *u) {
assert(u);
(void) unit_pick_cgroup_path(u);
if (!u->cgroup_path)
return;
(void) cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, 0, 0, NULL, log_leftover, u);
}
static const char* const collect_mode_table[_COLLECT_MODE_MAX] = {
[COLLECT_INACTIVE] = "inactive",
[COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed",

View File

@ -768,6 +768,8 @@ void unit_unlink_state_files(Unit *u);
int unit_prepare_exec(Unit *u);
void unit_warn_leftover_processes(Unit *u);
/* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full(unit, level, error, ...) \