]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
job: Don't mark as redundant if deps are relevant
authorKevin Kuehler <keur@xcf.berkeley.edu>
Tue, 19 Nov 2019 21:43:58 +0000 (13:43 -0800)
committerLennart Poettering <lennart@poettering.net>
Fri, 3 Jan 2020 14:58:10 +0000 (15:58 +0100)
In the steps given in #13850, the resulting graph looks like:

    C (Anchor) -> B -> A

Since B is inactive, it will be flagged as redundant and removed from
the transaction, causing A to get garbage collected. The proposed fix is
to not mark nodes as redundant if doing so causes a relevant node to be
garbage collected.

Fixes #13850

src/core/job.c
src/core/job.h
src/core/transaction.c

index 5048a5093e7053e9f67c59da57f9592b19fd6c3b..5982404cf0ceca7f56f44a63578314ba70be0385 100644 (file)
@@ -383,25 +383,62 @@ JobType job_type_lookup_merge(JobType a, JobType b) {
         return job_merging_table[(a - 1) * a / 2 + b];
 }
 
-bool job_type_is_redundant(JobType a, UnitActiveState b) {
-        switch (a) {
+bool job_later_link_matters(Job *j, JobType type, unsigned generation) {
+        JobDependency *l;
+
+        assert(j);
+
+        j->generation = generation;
+
+        LIST_FOREACH(subject, l, j->subject_list) {
+                UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
+
+                /* Have we seen this before? */
+                if (l->object->generation == generation)
+                        continue;
+
+                state = unit_active_state(l->object->unit);
+                switch (type) {
+
+                case JOB_START:
+                        return IN_SET(state, UNIT_INACTIVE, UNIT_FAILED) ||
+                               job_later_link_matters(l->object, type, generation);
+
+                case JOB_STOP:
+                        return IN_SET(state, UNIT_ACTIVE, UNIT_RELOADING) ||
+                               job_later_link_matters(l->object, type, generation);
+
+                default:
+                        assert_not_reached("Invalid job type");
+                }
+        }
+
+        return false;
+}
+
+bool job_is_redundant(Job *j, unsigned generation) {
+
+        assert(j);
+
+        UnitActiveState state = unit_active_state(j->unit);
+        switch (j->type) {
 
         case JOB_START:
-                return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING);
+                return IN_SET(state, UNIT_ACTIVE, UNIT_RELOADING) && !job_later_link_matters(j, JOB_START, generation);
 
         case JOB_STOP:
-                return IN_SET(b, UNIT_INACTIVE, UNIT_FAILED);
+                return IN_SET(state, UNIT_INACTIVE, UNIT_FAILED) && !job_later_link_matters(j, JOB_STOP, generation);
 
         case JOB_VERIFY_ACTIVE:
-                return IN_SET(b, UNIT_ACTIVE, UNIT_RELOADING);
+                return IN_SET(state, UNIT_ACTIVE, UNIT_RELOADING);
 
         case JOB_RELOAD:
                 return
-                        b == UNIT_RELOADING;
+                        state == UNIT_RELOADING;
 
         case JOB_RESTART:
                 return
-                        b == UNIT_ACTIVATING;
+                        state == UNIT_ACTIVATING;
 
         case JOB_NOP:
                 return true;
index 03ad640618e7bf047f9139a2d9df59fa4134dd76..02b057ee0641709d7c26c3a3ea331628c4ed3536 100644 (file)
@@ -196,7 +196,8 @@ _pure_ static inline bool job_type_is_superset(JobType a, JobType b) {
         return a == job_type_lookup_merge(a, b);
 }
 
-bool job_type_is_redundant(JobType a, UnitActiveState b) _pure_;
+bool job_later_link_matters(Job *j, JobType type, unsigned generation);
+bool job_is_redundant(Job *j, unsigned generation);
 
 /* Collapses a state-dependent job type into a simpler type by observing
  * the state of the unit which it is going to be applied to. */
index a0ea0f04897d7d764b73869d6f3d63fd1d1c1af1..8d67f9ce1abe285374b9bd7d80bfd9573976af87 100644 (file)
@@ -279,7 +279,7 @@ static int transaction_merge_jobs(Transaction *tr, sd_bus_error *e) {
         return 0;
 }
 
-static void transaction_drop_redundant(Transaction *tr) {
+static void transaction_drop_redundant(Transaction *tr, unsigned generation) {
         bool again;
 
         /* Goes through the transaction and removes all jobs of the units whose jobs are all noops. If not
@@ -299,7 +299,7 @@ static void transaction_drop_redundant(Transaction *tr) {
 
                         LIST_FOREACH(transaction, k, j)
                                 if (tr->anchor_job == k ||
-                                    !job_type_is_redundant(k->type, unit_active_state(k->unit)) ||
+                                    !job_is_redundant(k, generation) ||
                                     (k->unit->job && job_type_is_conflicting(k->type, k->unit->job->type))) {
                                         keep = true;
                                         break;
@@ -730,7 +730,7 @@ int transaction_activate(
                 transaction_minimize_impact(tr);
 
         /* Third step: Drop redundant jobs */
-        transaction_drop_redundant(tr);
+        transaction_drop_redundant(tr, generation++);
 
         for (;;) {
                 /* Fourth step: Let's remove unneeded jobs that might
@@ -772,7 +772,7 @@ int transaction_activate(
         }
 
         /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
-        transaction_drop_redundant(tr);
+        transaction_drop_redundant(tr, generation++);
 
         /* Ninth step: check whether we can actually apply this */
         r = transaction_is_destructive(tr, mode, e);