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; 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( static int unit_create_cgroup(
Unit *u, Unit *u,
CGroupMask target_mask, CGroupMask target_mask,
@ -1409,19 +1434,10 @@ static int unit_create_cgroup(
if (!c) if (!c)
return 0; return 0;
if (!u->cgroup_path) { /* Figure out our cgroup path */
_cleanup_free_ char *path = NULL; r = unit_pick_cgroup_path(u);
if (r < 0)
path = unit_default_cgroup_path(u); return r;
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);
}
/* First, create our own group */ /* First, create our own group */
r = cg_create_everywhere(u->manager->cgroup_supported, target_mask, u->cgroup_path); 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); char *unit_default_cgroup_path(Unit *u);
int unit_set_cgroup_path(Unit *u, const char *path); int unit_set_cgroup_path(Unit *u, const char *path);
int unit_pick_cgroup_path(Unit *u);
int unit_realize_cgroup(Unit *u); int unit_realize_cgroup(Unit *u);
void unit_release_cgroup(Unit *u); void unit_release_cgroup(Unit *u);

View File

@ -938,9 +938,6 @@ static void mount_enter_mounting(Mount *m) {
assert(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); r = unit_fail_if_symlink(UNIT(m), m->where);
if (r < 0) if (r < 0)
goto fail; goto fail;
@ -949,6 +946,11 @@ static void mount_enter_mounting(Mount *m) {
unit_warn_if_dir_nonempty(UNIT(m), m->where); 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 */ /* Create the source directory for bind-mounts if needed */
p = get_mount_parameters_fragment(m); p = get_mount_parameters_fragment(m);
if (p && mount_is_bind(p)) 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_control_pid(s);
service_unwatch_main_pid(s); service_unwatch_main_pid(s);
unit_warn_leftover_processes(UNIT(s));
if (s->type == SERVICE_FORKING) { if (s->type == SERVICE_FORKING) {
s->control_command_id = SERVICE_EXEC_START; s->control_command_id = SERVICE_EXEC_START;
c = s->control_command = s->exec_command[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]; s->control_command = s->exec_command[SERVICE_EXEC_START_PRE];
if (s->control_command) { if (s->control_command) {
unit_warn_leftover_processes(UNIT(s));
s->control_command_id = SERVICE_EXEC_START_PRE; s->control_command_id = SERVICE_EXEC_START_PRE;
r = service_spawn(s, r = service_spawn(s,

View File

@ -2187,6 +2187,9 @@ static void socket_enter_start_pre(Socket *s) {
assert(s); assert(s);
socket_unwatch_control_pid(s); socket_unwatch_control_pid(s);
unit_warn_leftover_processes(UNIT(s));
s->control_command_id = SOCKET_EXEC_START_PRE; s->control_command_id = SOCKET_EXEC_START_PRE;
s->control_command = s->exec_command[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); assert(s);
unit_warn_leftover_processes(UNIT(s));
s->control_command_id = SWAP_EXEC_ACTIVATE; s->control_command_id = SWAP_EXEC_ACTIVATE;
s->control_command = s->exec_command + 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; 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] = { static const char* const collect_mode_table[_COLLECT_MODE_MAX] = {
[COLLECT_INACTIVE] = "inactive", [COLLECT_INACTIVE] = "inactive",
[COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed", [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); int unit_prepare_exec(Unit *u);
void unit_warn_leftover_processes(Unit *u);
/* Macros which append UNIT= or USER_UNIT= to the message */ /* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full(unit, level, error, ...) \ #define log_unit_full(unit, level, error, ...) \