From 1f0f9f21c1b19e1e450c3c2696955fd6f442ca2b Mon Sep 17 00:00:00 2001 From: Kevin Kuehler Date: Fri, 1 Nov 2019 00:54:03 -0700 Subject: [PATCH] core: Add triggering job mode When used with systemctl stop, follows TRIGGERED_BY dependencies and adds them to the same transaction. Fixes: #3043 --- TODO | 2 -- src/core/job.c | 1 + src/core/job.h | 1 + src/core/manager.c | 9 +++++++++ src/core/transaction.c | 25 +++++++++++++++++++++++++ src/core/transaction.h | 1 + 6 files changed, 37 insertions(+), 2 deletions(-) diff --git a/TODO b/TODO index 03d38da9a0..b86784bb28 100644 --- a/TODO +++ b/TODO @@ -483,8 +483,6 @@ Features: * cache sd_event_now() result from before the first iteration... -* add systemctl stop --job-mode=triggering that follows TRIGGERED_BY deps and adds them to the same transaction - * PID1: find a way how we can reload unit file configuration for specific units only, without reloading the whole of systemd diff --git a/src/core/job.c b/src/core/job.c index 9537366eb9..86185296dd 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -1610,6 +1610,7 @@ static const char* const job_mode_table[_JOB_MODE_MAX] = { [JOB_FLUSH] = "flush", [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies", [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements", + [JOB_TRIGGERING] = "triggering", }; DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode); diff --git a/src/core/job.h b/src/core/job.h index 0781328a56..03ad640618 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -75,6 +75,7 @@ enum JobMode { JOB_FLUSH, /* Flush out all other queued jobs when queueing this one */ JOB_IGNORE_DEPENDENCIES, /* Ignore both requirement and ordering dependencies */ JOB_IGNORE_REQUIREMENTS, /* Ignore requirement dependencies */ + JOB_TRIGGERING, /* Adds TRIGGERED_BY dependencies to the same transaction */ _JOB_MODE_MAX, _JOB_MODE_INVALID = -1 }; diff --git a/src/core/manager.c b/src/core/manager.c index c9032fced8..8f523e1151 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1740,6 +1740,9 @@ int manager_add_job( if (mode == JOB_ISOLATE && !unit->allow_isolate) return sd_bus_error_setf(error, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated."); + if (mode == JOB_TRIGGERING && type != JOB_STOP) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "--job-mode=triggering is only valid for stop."); + log_unit_debug(unit, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode)); type = job_type_collapse(type, unit); @@ -1760,6 +1763,12 @@ int manager_add_job( goto tr_abort; } + if (mode == JOB_TRIGGERING) { + r = transaction_add_triggering_jobs(tr, unit); + if (r < 0) + goto tr_abort; + } + r = transaction_activate(tr, m, mode, affected_jobs, error); if (r < 0) goto tr_abort; diff --git a/src/core/transaction.c b/src/core/transaction.c index a0825c595c..34647281a4 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -1141,6 +1141,31 @@ int transaction_add_isolate_jobs(Transaction *tr, Manager *m) { return 0; } +int transaction_add_triggering_jobs(Transaction *tr, Unit *u) { + Iterator i; + void *v; + Unit *trigger; + int r; + + assert(tr); + + HASHMAP_FOREACH_KEY(v, trigger, u->dependencies[UNIT_TRIGGERED_BY], i) { + /* No need to stop inactive jobs */ + if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(trigger)) && !trigger->job) + continue; + + /* Is there already something listed for this? */ + if (hashmap_get(tr->jobs, trigger)) + continue; + + r = transaction_add_job_and_dependencies(tr, JOB_STOP, trigger, tr->anchor_job, true, false, false, false, NULL); + if (r < 0) + log_unit_warning_errno(u, r, "Cannot add triggered by job, ignoring: %m"); + } + + return 0; +} + Transaction *transaction_new(bool irreversible) { Transaction *tr; diff --git a/src/core/transaction.h b/src/core/transaction.h index 4b5620f5c8..ba42f58e07 100644 --- a/src/core/transaction.h +++ b/src/core/transaction.h @@ -31,4 +31,5 @@ int transaction_add_job_and_dependencies( sd_bus_error *e); int transaction_activate(Transaction *tr, Manager *m, JobMode mode, Set *affected, sd_bus_error *e); int transaction_add_isolate_jobs(Transaction *tr, Manager *m); +int transaction_add_triggering_jobs(Transaction *tr, Unit *u); void transaction_abort(Transaction *tr);