mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
core/transaction: add job mode "lenient" as an even weaker version of _FAIL
This commit is contained in:
@@ -2197,6 +2197,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
|
||||
<listitem>
|
||||
<para>When queuing a new job, this option controls how to deal with
|
||||
already queued jobs. It takes one of <literal>fail</literal>,
|
||||
<literal>lenient</literal>,
|
||||
<literal>replace</literal>,
|
||||
<literal>replace-irreversibly</literal>,
|
||||
<literal>isolate</literal>,
|
||||
@@ -2209,10 +2210,12 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
|
||||
<command>isolate</command> command is used which implies the
|
||||
<literal>isolate</literal> job mode.</para>
|
||||
|
||||
<para>If <literal>fail</literal> is specified and a requested
|
||||
operation conflicts with a pending job (more specifically:
|
||||
causes an already pending start job to be reversed into a stop
|
||||
job or vice versa), cause the operation to fail.</para>
|
||||
<para>If <literal>fail</literal> is specified and a requested operation on weak dependencies
|
||||
conflicts with a pending job (more specifically: causes an already pending start job to be reversed
|
||||
into a stop job or vice versa), cause the operation to fail.</para>
|
||||
|
||||
<para>If <literal>lenient</literal> is specified and a requested operation conflicts with any
|
||||
active/activating unit, cause the operation to fail.</para>
|
||||
|
||||
<para>If <literal>replace</literal> (the default) is
|
||||
specified, any conflicting pending job will be replaced, as
|
||||
|
||||
@@ -341,6 +341,7 @@ DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess);
|
||||
|
||||
static const char* const job_mode_table[_JOB_MODE_MAX] = {
|
||||
[JOB_FAIL] = "fail",
|
||||
[JOB_LENIENT] = "lenient",
|
||||
[JOB_REPLACE] = "replace",
|
||||
[JOB_REPLACE_IRREVERSIBLY] = "replace-irreversibly",
|
||||
[JOB_ISOLATE] = "isolate",
|
||||
|
||||
@@ -282,6 +282,7 @@ typedef enum NotifyAccess {
|
||||
|
||||
typedef enum JobMode {
|
||||
JOB_FAIL, /* Fail if a conflicting job is already queued */
|
||||
JOB_LENIENT, /* Fail if any conflicting unit is active (even weaker than JOB_FAIL) */
|
||||
JOB_REPLACE, /* Replace an existing conflicting job */
|
||||
JOB_REPLACE_IRREVERSIBLY, /* Like JOB_REPLACE + produce irreversible jobs */
|
||||
JOB_ISOLATE, /* Start a unit, and stop all others */
|
||||
|
||||
@@ -565,7 +565,7 @@ static int transaction_is_destructive(Transaction *tr, JobMode mode, sd_bus_erro
|
||||
assert(!j->transaction_prev);
|
||||
assert(!j->transaction_next);
|
||||
|
||||
if (j->unit->job && (mode == JOB_FAIL || j->unit->job->irreversible) &&
|
||||
if (j->unit->job && (IN_SET(mode, JOB_FAIL, JOB_LENIENT) || j->unit->job->irreversible) &&
|
||||
job_type_is_conflicting(j->unit->job->type, j->type))
|
||||
return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE,
|
||||
"Transaction for %s/%s is destructive (%s has '%s' job queued, but '%s' is included in transaction).",
|
||||
@@ -576,7 +576,7 @@ static int transaction_is_destructive(Transaction *tr, JobMode mode, sd_bus_erro
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void transaction_minimize_impact(Transaction *tr) {
|
||||
static int transaction_minimize_impact(Transaction *tr, JobMode mode, sd_bus_error *e) {
|
||||
Job *head;
|
||||
|
||||
assert(tr);
|
||||
@@ -584,13 +584,16 @@ static void transaction_minimize_impact(Transaction *tr) {
|
||||
/* Drops all unnecessary jobs that reverse already active jobs
|
||||
* or that stop a running service. */
|
||||
|
||||
if (!IN_SET(mode, JOB_FAIL, JOB_LENIENT))
|
||||
return 0;
|
||||
|
||||
rescan:
|
||||
HASHMAP_FOREACH(head, tr->jobs) {
|
||||
LIST_FOREACH(transaction, j, head) {
|
||||
bool stops_running_service, changes_existing_job;
|
||||
|
||||
/* If it matters, we shouldn't drop it */
|
||||
if (j->matters_to_anchor)
|
||||
if (j->matters_to_anchor && mode != JOB_LENIENT)
|
||||
continue;
|
||||
|
||||
/* Would this stop a running service?
|
||||
@@ -607,6 +610,13 @@ rescan:
|
||||
if (!stops_running_service && !changes_existing_job)
|
||||
continue;
|
||||
|
||||
if (j->matters_to_anchor) {
|
||||
assert(mode == JOB_LENIENT);
|
||||
return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE,
|
||||
"%s/%s would stop a running unit or change existing job, bailing",
|
||||
j->unit->id, job_type_to_string(j->type));
|
||||
}
|
||||
|
||||
if (stops_running_service)
|
||||
log_unit_debug(j->unit,
|
||||
"%s/%s would stop a running service.",
|
||||
@@ -626,6 +636,8 @@ rescan:
|
||||
goto rescan;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int transaction_apply(
|
||||
@@ -734,11 +746,12 @@ int transaction_activate(
|
||||
/* First step: figure out which jobs matter */
|
||||
transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++);
|
||||
|
||||
/* Second step: Try not to stop any running services if
|
||||
* we don't have to. Don't try to reverse running
|
||||
* jobs if we don't have to. */
|
||||
if (mode == JOB_FAIL)
|
||||
transaction_minimize_impact(tr);
|
||||
/* Second step: Try not to stop any running services if we don't have to. Don't try to reverse
|
||||
* running jobs if we don't have to. */
|
||||
r = transaction_minimize_impact(tr, mode, e);
|
||||
if (r < 0)
|
||||
return r; /* Note that we don't log here, because for JOB_LENIENT conflicts are very much expected
|
||||
and shouldn't appear to be fatal for the unit. Only inform the caller via bus error. */
|
||||
|
||||
/* Third step: Drop redundant jobs */
|
||||
transaction_drop_redundant(tr);
|
||||
|
||||
Reference in New Issue
Block a user