From 171f12ced8465ff8483b0bb5e6f26ec7c4bb024c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Michal=20Koutn=C3=BD?= Date: Sun, 18 Jun 2017 17:51:17 +0200 Subject: [PATCH] job: Ensure JobRunningTimeoutSec= survives serialization (#6128) This is a fixup of commit a2df3ea4ae058693bc7bf203d144e8af3c9493d2. 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. --- src/core/job.c | 33 ++++++++++++++++++++++++++++----- src/core/job.h | 1 + 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/core/job.c b/src/core/job.c index 5067006d631..899c011db43 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -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"); diff --git a/src/core/job.h b/src/core/job.h index 8b3d38fc601..b17001889ef 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -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 -- 2.47.3