X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fcore%2Ftransaction.c;h=a8b7e4c25d9b60fef8c474353cf7c5927d791a8b;hb=78ff1acdfe6a1f50d4ac62dc354c667999be0508;hp=09abe007fb43ea3acda56c1abce9ccb964553fd5;hpb=4483f694983382b4092e3e295ffb59926cff96d9;p=elogind.git diff --git a/src/core/transaction.c b/src/core/transaction.c index 09abe007f..a8b7e4c25 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -1,3 +1,24 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + #include "transaction.h" #include "bus-errors.h" @@ -11,8 +32,7 @@ static void transaction_delete_job(Transaction *tr, Job *j, bool delete_dependen transaction_unlink_job(tr, j, delete_dependencies); - if (!j->installed) - job_free(j); + job_free(j); } static void transaction_delete_unit(Transaction *tr, Unit *u) { @@ -34,26 +54,20 @@ void transaction_abort(Transaction *tr) { transaction_delete_job(tr, j, true); assert(hashmap_isempty(tr->jobs)); - - assert(!tr->anchor); } -static void transaction_find_jobs_that_matter_to_anchor(Transaction *tr, Job *j, unsigned generation) { +static void transaction_find_jobs_that_matter_to_anchor(Job *j, unsigned generation) { JobDependency *l; - assert(tr); - /* A recursive sweep through the graph that marks all units * that matter to the anchor job, i.e. are directly or * indirectly a dependency of the anchor job via paths that * are fully marked as mattering. */ - if (j) - l = j->subject_list; - else - l = tr->anchor; + j->matters_to_anchor = true; + j->generation = generation; - LIST_FOREACH(subject, l, l) { + LIST_FOREACH(subject, l, j->subject_list) { /* This link does not matter */ if (!l->matters) @@ -63,10 +77,7 @@ static void transaction_find_jobs_that_matter_to_anchor(Transaction *tr, Job *j, if (l->object->generation == generation) continue; - l->object->matters_to_anchor = true; - l->object->generation = generation; - - transaction_find_jobs_that_matter_to_anchor(tr, l->object, generation); + transaction_find_jobs_that_matter_to_anchor(l->object, generation); } } @@ -252,21 +263,14 @@ static int transaction_merge_jobs(Transaction *tr, DBusError *e) { LIST_FOREACH(transaction, k, j->transaction_next) assert_se(job_type_merge(&t, k->type) == 0); - /* If an active job is mergeable, merge it too */ - if (j->unit->job) - job_type_merge(&t, j->unit->job->type); /* Might fail. Which is OK */ - while ((k = j->transaction_next)) { - if (j->installed) { + if (tr->anchor_job == k) { transaction_merge_and_delete_job(tr, k, j, t); j = k; } else transaction_merge_and_delete_job(tr, j, k, t); } - if (j->unit->job && !j->installed) - transaction_merge_and_delete_job(tr, j, j->unit->job, t); - assert(!j->transaction_next); assert(!j->transaction_prev); } @@ -294,8 +298,8 @@ static void transaction_drop_redundant(Transaction *tr) { LIST_FOREACH(transaction, k, j) { - if (!job_is_anchor(k) && - (k->installed || job_type_is_redundant(k->type, unit_active_state(k->unit))) && + if (tr->anchor_job != k && + job_type_is_redundant(k->type, unit_active_state(k->unit)) && (!k->unit->job || !job_type_is_conflicting(k->type, k->unit->job->type))) continue; @@ -365,7 +369,6 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi log_info("Walked on cycle path to %s/%s", k->unit->id, job_type_to_string(k->type)); if (!delete && - !k->installed && !unit_matters_to_anchor(k->unit, k)) { /* Ok, we can drop this one, so let's * do so. */ @@ -461,7 +464,7 @@ static void transaction_collect_garbage(Transaction *tr) { again = false; HASHMAP_FOREACH(j, tr->jobs, i) { - if (j->object_list) { + if (tr->anchor_job == j || j->object_list) { /* log_debug("Keeping job %s/%s because of %s/%s", */ /* j->unit->id, job_type_to_string(j->type), */ /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */ @@ -494,7 +497,6 @@ static int transaction_is_destructive(Transaction *tr, DBusError *e) { assert(!j->transaction_next); if (j->unit->job && - j->unit->job != j && !job_type_is_superset(j->type, j->unit->job->type)) { dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive."); @@ -592,59 +594,38 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) { assert(!j->transaction_prev); assert(!j->transaction_next); - if (j->installed) - continue; - r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j); if (r < 0) goto rollback; } while ((j = hashmap_steal_first(tr->jobs))) { - Job *uj; - if (j->installed) { - /* log_debug("Skipping already installed job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); */ - continue; - } - - uj = j->unit->job; - if (uj) { - job_uninstall(uj); - job_free(uj); - } - - j->unit->job = j; - j->installed = true; - m->n_installed_jobs ++; - - /* We're fully installed. Now let's free data we don't - * need anymore. */ - - assert(!j->transaction_next); - assert(!j->transaction_prev); + Job *installed_job; /* Clean the job dependencies */ transaction_unlink_job(tr, j, false); + installed_job = job_install(j); + if (installed_job != j) { + /* j has been merged into a previously installed job */ + if (tr->anchor_job == j) + tr->anchor_job = installed_job; + hashmap_remove(m->jobs, UINT32_TO_PTR(j->id)); + job_free(j); + j = installed_job; + } + job_add_to_run_queue(j); job_add_to_dbus_queue(j); job_start_timer(j); - - log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); } - assert(!tr->anchor); - return 0; rollback: - HASHMAP_FOREACH(j, tr->jobs, i) { - if (j->installed) - continue; - + HASHMAP_FOREACH(j, tr->jobs, i) hashmap_remove(m->jobs, UINT32_TO_PTR(j->id)); - } return r; } @@ -659,7 +640,7 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e * the actual list of jobs, if possible. */ /* First step: figure out which jobs matter */ - transaction_find_jobs_that_matter_to_anchor(tr, NULL, generation++); + 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 @@ -733,7 +714,6 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e } assert(hashmap_isempty(tr->jobs)); - assert(!tr->anchor); return 0; } @@ -785,12 +765,6 @@ static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, b return j; } -static void transaction_job_dependency_free(Transaction *tr, JobDependency *l) { - if (!l->subject) - LIST_REMOVE(JobDependency, subject, tr->anchor, l); - job_dependency_free(l); -} - static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) { assert(tr); assert(j); @@ -808,12 +782,12 @@ static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependen j->transaction_prev = j->transaction_next = NULL; while (j->subject_list) - transaction_job_dependency_free(tr, j->subject_list); + job_dependency_free(j->subject_list); while (j->object_list) { Job *other = j->object_list->matters ? j->object_list->subject : NULL; - transaction_job_dependency_free(tr, j->object_list); + job_dependency_free(j->object_list); if (other && delete_dependencies) { log_debug("Deleting job %s/%s as dependency of job %s/%s", @@ -836,7 +810,6 @@ int transaction_add_job_and_dependencies( bool ignore_order, DBusError *e) { Job *ret; - JobDependency *l; Iterator i; Unit *dep; int r; @@ -870,7 +843,7 @@ int transaction_add_job_and_dependencies( if (type != JOB_STOP && unit->load_state == UNIT_MASKED) { dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->id); - return -EINVAL; + return -EADDRNOTAVAIL; } if (!unit_job_is_applicable(unit, type)) { @@ -886,17 +859,14 @@ int transaction_add_job_and_dependencies( ret->ignore_order = ret->ignore_order || ignore_order; /* Then, add a link to the job. */ - l = job_dependency_new(by, ret, matters, conflicts); - if (!l) - return -ENOMEM; - - /* If the link has no subject job, it's the anchor link. */ - if (!by) { - LIST_PREPEND(JobDependency, subject, tr->anchor, l); + if (by) { + if (!job_dependency_new(by, ret, matters, conflicts)) + return -ENOMEM; + } else { + /* If the job has no parent job, it is the anchor job. */ assert(!tr->anchor_job); tr->anchor_job = ret; } - if (is_new && !ignore_requirements) { Set *following; @@ -917,7 +887,7 @@ int transaction_add_job_and_dependencies( } /* Finally, recursively add in all dependencies. */ - if (type == JOB_START || type == JOB_RELOAD_OR_START) { + if (type == JOB_START || type == JOB_RELOAD_OR_START || type == JOB_RESTART) { SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) { r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e); if (r < 0) { @@ -943,7 +913,8 @@ int transaction_add_job_and_dependencies( SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) { r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e); if (r < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); + log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, + "Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); if (e) dbus_error_free(e); @@ -953,7 +924,8 @@ int transaction_add_job_and_dependencies( SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) { r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e); if (r < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); + log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, + "Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); if (e) dbus_error_free(e); @@ -974,7 +946,8 @@ int transaction_add_job_and_dependencies( SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) { r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e); if (r < 0) { - log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); + log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, + "Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r)); if (e) dbus_error_free(e);