1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-12 09:17:44 +03:00

core: unify kill code of mount, service, socket, swap units

This commit is contained in:
Lennart Poettering 2013-01-26 05:53:30 +01:00
parent f2956e80c9
commit cd2086fe65
6 changed files with 122 additions and 191 deletions

View File

@ -877,56 +877,23 @@ static void mount_enter_mounted(Mount *m, MountResult f) {
static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
int r;
Set *pid_set = NULL;
bool wait_for_exit = false;
assert(m);
if (f != MOUNT_SUCCESS)
m->result = f;
if (m->kill_context.kill_mode != KILL_NONE) {
int sig = (state == MOUNT_MOUNTING_SIGTERM ||
state == MOUNT_UNMOUNTING_SIGTERM ||
state == MOUNT_REMOUNTING_SIGTERM) ? m->kill_context.kill_signal : SIGKILL;
r = unit_kill_context(
UNIT(m),
&m->kill_context,
state != MOUNT_MOUNTING_SIGTERM && state != MOUNT_UNMOUNTING_SIGTERM && state != MOUNT_REMOUNTING_SIGTERM,
-1,
m->control_pid,
false);
if (r < 0)
goto fail;
if (m->control_pid > 0) {
if (kill_and_sigcont(m->control_pid, sig) < 0 && errno != ESRCH)
log_warning_unit(UNIT(m)->id,
"Failed to kill control process %li: %m",
(long) m->control_pid);
else
wait_for_exit = true;
}
if (m->kill_context.kill_mode == KILL_CONTROL_GROUP) {
if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
r = -ENOMEM;
goto fail;
}
/* Exclude the control pid from being killed via the cgroup */
if (m->control_pid > 0)
if ((r = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0)
goto fail;
r = cgroup_bonding_kill_list(UNIT(m)->cgroup_bondings, sig, true, false, pid_set, NULL);
if (r < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
log_warning_unit(UNIT(m)->id,
"Failed to kill control group: %s",
strerror(-r));
} else if (r > 0)
wait_for_exit = true;
set_free(pid_set);
pid_set = NULL;
}
}
if (wait_for_exit) {
if (r > 0) {
r = unit_watch_timer(UNIT(m), CLOCK_MONOTONIC, true, m->timeout_usec, &m->timer_watch);
if (r < 0)
goto fail;
@ -947,14 +914,15 @@ fail:
mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
else
mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
if (pid_set)
set_free(pid_set);
}
void warn_if_dir_nonempty(const char *unit, const char* where) {
assert(unit);
assert(where);
if (dir_is_empty(where) > 0)
return;
log_struct_unit(LOG_NOTICE,
unit,
"MESSAGE=%s: Directory %s to mount over is not empty, mounting anyway.",

View File

@ -1955,64 +1955,23 @@ fail:
static void service_enter_signal(Service *s, ServiceState state, ServiceResult f) {
int r;
Set *pid_set = NULL;
bool wait_for_exit = false;
assert(s);
if (f != SERVICE_SUCCESS)
s->result = f;
if (s->kill_context.kill_mode != KILL_NONE) {
int sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? s->kill_context.kill_signal : SIGKILL;
r = unit_kill_context(
UNIT(s),
&s->kill_context,
state != SERVICE_STOP_SIGTERM && state != SERVICE_FINAL_SIGTERM,
s->main_pid,
s->control_pid,
s->main_pid_alien);
if (r < 0)
goto fail;
if (s->main_pid > 0) {
if (kill_and_sigcont(s->main_pid, sig) < 0 && errno != ESRCH)
log_warning_unit(UNIT(s)->id,
"Failed to kill main process %li: %m", (long) s->main_pid);
else
wait_for_exit = !s->main_pid_alien;
}
if (s->control_pid > 0) {
if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
log_warning_unit(UNIT(s)->id,
"Failed to kill control process %li: %m", (long) s->control_pid);
else
wait_for_exit = true;
}
if (s->kill_context.kill_mode == KILL_CONTROL_GROUP) {
pid_set = set_new(trivial_hash_func, trivial_compare_func);
if (!pid_set) {
r = -ENOMEM;
goto fail;
}
/* Exclude the main/control pids from being killed via the cgroup */
if (s->main_pid > 0)
if ((r = set_put(pid_set, LONG_TO_PTR(s->main_pid))) < 0)
goto fail;
if (s->control_pid > 0)
if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0)
goto fail;
r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, false, pid_set, NULL);
if (r < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
log_warning_unit(UNIT(s)->id,
"Failed to kill control group: %s", strerror(-r));
} else if (r > 0)
wait_for_exit = true;
set_free(pid_set);
pid_set = NULL;
}
}
if (wait_for_exit) {
if (r > 0) {
if (s->timeout_stop_usec > 0) {
r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_stop_usec, &s->timer_watch);
if (r < 0)
@ -2035,9 +1994,6 @@ fail:
service_enter_stop_post(s, SERVICE_FAILURE_RESOURCES);
else
service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
if (pid_set)
set_free(pid_set);
}
static void service_enter_stop(Service *s, ServiceResult f) {

View File

@ -1288,54 +1288,23 @@ fail:
static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
int r;
Set *pid_set = NULL;
bool wait_for_exit = false;
assert(s);
if (f != SOCKET_SUCCESS)
s->result = f;
if (s->kill_context.kill_mode != KILL_NONE) {
int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? s->kill_context.kill_signal : SIGKILL;
r = unit_kill_context(
UNIT(s),
&s->kill_context,
state != SOCKET_STOP_PRE_SIGTERM && state != SOCKET_FINAL_SIGTERM,
-1,
s->control_pid,
false);
if (r < 0)
goto fail;
if (s->control_pid > 0) {
if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
log_warning_unit(UNIT(s)->id,
"Failed to kill control process %li: %m",
(long) s->control_pid);
else
wait_for_exit = true;
}
if (s->kill_context.kill_mode == KILL_CONTROL_GROUP) {
if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
r = -ENOMEM;
goto fail;
}
/* Exclude the control pid from being killed via the cgroup */
if (s->control_pid > 0)
if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0)
goto fail;
r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, false, pid_set, NULL);
if (r < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
log_warning_unit(UNIT(s)->id,
"Failed to kill control group: %s",
strerror(-r));
} else if (r > 0)
wait_for_exit = true;
set_free(pid_set);
pid_set = NULL;
}
}
if (wait_for_exit) {
if (r > 0) {
r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_usec, &s->timer_watch);
if (r < 0)
goto fail;
@ -1357,9 +1326,6 @@ fail:
socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
else
socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
if (pid_set)
set_free(pid_set);
}
static void socket_enter_stop_pre(Socket *s, SocketResult f) {

View File

@ -646,57 +646,23 @@ static void swap_enter_active(Swap *s, SwapResult f) {
static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
int r;
Set *pid_set = NULL;
bool wait_for_exit = false;
assert(s);
if (f != SWAP_SUCCESS)
s->result = f;
if (s->kill_context.kill_mode != KILL_NONE) {
int sig = (state == SWAP_ACTIVATING_SIGTERM ||
state == SWAP_DEACTIVATING_SIGTERM) ? s->kill_context.kill_signal : SIGKILL;
r = unit_kill_context(
UNIT(s),
&s->kill_context,
state != SWAP_ACTIVATING_SIGTERM && state != SWAP_DEACTIVATING_SIGTERM,
-1,
s->control_pid,
false);
if (r < 0)
goto fail;
if (s->control_pid > 0) {
if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
log_warning_unit(UNIT(s)->id,
"Failed to kill control process %li: %m",
(long) s->control_pid);
else
wait_for_exit = true;
}
if (s->kill_context.kill_mode == KILL_CONTROL_GROUP) {
pid_set = set_new(trivial_hash_func, trivial_compare_func);
if (!pid_set) {
r = log_oom();
goto fail;
}
/* Exclude the control pid from being killed via the cgroup */
if (s->control_pid > 0) {
r = set_put(pid_set, LONG_TO_PTR(s->control_pid));
if (r < 0)
goto fail;
}
r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, false, pid_set, NULL);
if (r < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
log_warning_unit(UNIT(s)->id,
"Failed to kill control group: %s", strerror(-r));
} else if (r > 0)
wait_for_exit = true;
set_free(pid_set);
pid_set = NULL;
}
}
if (wait_for_exit) {
if (r > 0) {
r = unit_watch_timer(UNIT(s), CLOCK_MONOTONIC, true, s->timeout_usec, &s->timer_watch);
if (r < 0)
goto fail;
@ -712,9 +678,6 @@ fail:
"%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
if (pid_set)
set_free(pid_set);
}
static void swap_enter_activating(Swap *s) {

View File

@ -2807,6 +2807,82 @@ int unit_remove_drop_in(Unit *u, bool runtime, const char *name) {
return 0;
}
int unit_kill_context(
Unit *u,
KillContext *c,
bool sigkill,
pid_t main_pid,
pid_t control_pid,
bool main_pid_alien) {
int sig, wait_for_exit = 0, r;
assert(u);
assert(c);
if (c->kill_mode == KILL_NONE)
return 0;
sig = sigkill ? SIGKILL : c->kill_signal;
if (main_pid > 0) {
r = kill_and_sigcont(main_pid, sig);
if (r < 0 && r != -ESRCH) {
_cleanup_free_ char *comm = NULL;
get_process_comm(main_pid, &comm);
log_warning_unit(u->id, "Failed to kill main process %li (%s): %s",
(long) main_pid, strna(comm), strerror(-r));
} else
wait_for_exit = !main_pid_alien;
}
if (control_pid > 0) {
r = kill_and_sigcont(control_pid, sig);
if (r < 0 && r != -ESRCH) {
_cleanup_free_ char *comm = NULL;
get_process_comm(control_pid, &comm);
log_warning_unit(u->id,
"Failed to kill control process %li (%s): %s",
(long) control_pid, strna(comm), strerror(-r));
} else
wait_for_exit = true;
}
if (c->kill_mode == KILL_CONTROL_GROUP) {
_cleanup_set_free_ Set *pid_set = NULL;
pid_set = set_new(trivial_hash_func, trivial_compare_func);
if (!pid_set)
return -ENOMEM;
/* Exclude the main/control pids from being killed via the cgroup */
if (main_pid > 0) {
r = set_put(pid_set, LONG_TO_PTR(main_pid));
if (r < 0)
return r;
}
if (control_pid > 0) {
r = set_put(pid_set, LONG_TO_PTR(control_pid));
if (r < 0)
return r;
}
r = cgroup_bonding_kill_list(u->cgroup_bondings, sig, true, false, pid_set, NULL);
if (r < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
log_warning_unit(u->id, "Failed to kill control group: %s", strerror(-r));
} else if (r > 0)
wait_for_exit = true;
}
return wait_for_exit;
}
static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
[UNIT_ACTIVE] = "active",
[UNIT_RELOADING] = "reloading",

View File

@ -557,6 +557,8 @@ ExecContext *unit_get_exec_context(Unit *u);
int unit_write_drop_in(Unit *u, bool runtime, const char *name, const char *data);
int unit_remove_drop_in(Unit *u, bool runtime, const char *name);
int unit_kill_context(Unit *u, KillContext *c, bool sigkill, pid_t main_pid, pid_t control_pid, bool main_pid_alien);
const char *unit_active_state_to_string(UnitActiveState i);
UnitActiveState unit_active_state_from_string(const char *s);