job: Ensure JobRunningTimeoutSec= survives serialization (#6128)

This is a fixup of commit a2df3ea4ae.
When there is a running job with JobRunningTimeoutSec= and systemd serializes
its state (e.g. during daemon-reload), the timer event source won't be properly
restored in job_coldplug().
Thus save and serialize begin_running_usec too and reinitialize the timer based
on that value.
This commit is contained in:
Michal Koutný 2017-06-18 17:51:17 +02:00 committed by Zbigniew Jędrzejewski-Szmek
parent f7b1c8d1fc
commit 171f12ced8
2 changed files with 29 additions and 5 deletions

View file

@ -952,14 +952,15 @@ static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *user
int job_start_timer(Job *j, bool job_running) {
int r;
usec_t run_begin, timeout_time, old_timeout_time;
usec_t timeout_time, old_timeout_time;
if (job_running) {
j->begin_running_usec = now(CLOCK_MONOTONIC);
if (j->unit->job_running_timeout == USEC_INFINITY)
return 0;
run_begin = now(CLOCK_MONOTONIC);
timeout_time = usec_add(run_begin, j->unit->job_running_timeout);
timeout_time = usec_add(j->begin_running_usec, j->unit->job_running_timeout);
if (j->timer_event_source) {
/* Update only if JobRunningTimeoutSec= results in earlier timeout */
@ -1051,6 +1052,8 @@ int job_serialize(Job *j, FILE *f) {
if (j->begin_usec > 0)
fprintf(f, "job-begin="USEC_FMT"\n", j->begin_usec);
if (j->begin_running_usec > 0)
fprintf(f, "job-begin-running="USEC_FMT"\n", j->begin_running_usec);
bus_track_serialize(j->bus_track, f, "subscribed");
@ -1148,6 +1151,14 @@ int job_deserialize(Job *j, FILE *f) {
else
j->begin_usec = ull;
} else if (streq(l, "job-begin-running")) {
unsigned long long ull;
if (sscanf(v, "%llu", &ull) != 1)
log_debug("Failed to parse job-begin-running value %s", v);
else
j->begin_running_usec = ull;
} else if (streq(l, "subscribed")) {
if (strv_extend(&j->deserialized_clients, v) < 0)
@ -1158,6 +1169,7 @@ int job_deserialize(Job *j, FILE *f) {
int job_coldplug(Job *j) {
int r;
usec_t timeout_time = USEC_INFINITY;
assert(j);
@ -1171,7 +1183,18 @@ int job_coldplug(Job *j) {
/* Maybe due to new dependencies we don't actually need this job anymore? */
job_add_to_gc_queue(j);
if (j->begin_usec == 0 || j->unit->job_timeout == USEC_INFINITY)
/* Create timer only when job began or began running and the respective timeout is finite.
* Follow logic of job_start_timer() if both timeouts are finite */
if (j->begin_usec == 0)
return 0;
if (j->unit->job_timeout != USEC_INFINITY)
timeout_time = usec_add(j->begin_usec, j->unit->job_timeout);
if (j->begin_running_usec > 0 && j->unit->job_running_timeout != USEC_INFINITY)
timeout_time = MIN(timeout_time, usec_add(j->begin_running_usec, j->unit->job_running_timeout));
if (timeout_time == USEC_INFINITY)
return 0;
j->timer_event_source = sd_event_source_unref(j->timer_event_source);
@ -1180,7 +1203,7 @@ int job_coldplug(Job *j) {
j->manager->event,
&j->timer_event_source,
CLOCK_MONOTONIC,
usec_add(j->begin_usec, j->unit->job_timeout), 0,
timeout_time, 0,
job_dispatch_timer, j);
if (r < 0)
log_debug_errno(r, "Failed to restart timeout for job: %m");

View file

@ -150,6 +150,7 @@ struct Job {
sd_event_source *timer_event_source;
usec_t begin_usec;
usec_t begin_running_usec;
/*
* This tracks where to send signals, and also which clients