X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fmanager.c;h=ddb253ae4eb0a240721297d79adb76528374ea25;hb=47342320a097523d93040cdd627e237a420572c5;hp=58848356ea9aec577068650514cfe5b4df30b766;hpb=3dda9fc3a738241e42df43dbebf9e479e5ad1da8;p=elogind.git diff --git a/src/manager.c b/src/manager.c index 58848356e..ddb253ae4 100644 --- a/src/manager.c +++ b/src/manager.c @@ -715,6 +715,20 @@ static void transaction_merge_and_delete_job(Manager *m, Job *j, Job *other, Job other->object_list = NULL; transaction_delete_job(m, other, true); } +static bool job_is_conflicted_by(Job *j) { + JobDependency *l; + + assert(j); + + /* Returns true if this job is pulled in by a least one + * ConflictedBy dependency. */ + + LIST_FOREACH(object, l, j->object_list) + if (l->conflicts) + return true; + + return false; +} static int delete_one_unmergeable_job(Manager *m, Job *j) { Job *k; @@ -738,7 +752,36 @@ static int delete_one_unmergeable_job(Manager *m, Job *j) { /* Ok, we found two that conflict, let's see if we can * drop one of them */ - if (!j->matters_to_anchor) + if (!j->matters_to_anchor && !k->matters_to_anchor) { + + /* Both jobs don't matter, so let's + * find the one that is smarter to + * remove. Let's think positive and + * rather remove stops then starts -- + * except if something is being + * stopped because it is conflicted by + * another unit in which case we + * rather remove the start. */ + + log_debug("Looking at job %s/%s conflicted_by=%s", j->unit->meta.id, job_type_to_string(j->type), yes_no(j->type == JOB_STOP && job_is_conflicted_by(j))); + log_debug("Looking at job %s/%s conflicted_by=%s", k->unit->meta.id, job_type_to_string(k->type), yes_no(k->type == JOB_STOP && job_is_conflicted_by(k))); + + if (j->type == JOB_STOP) { + + if (job_is_conflicted_by(j)) + d = k; + else + d = j; + + } else if (k->type == JOB_STOP) { + + if (job_is_conflicted_by(k)) + d = j; + else + d = k; + } + + } else if (!j->matters_to_anchor) d = j; else if (!k->matters_to_anchor) d = k; @@ -746,7 +789,7 @@ static int delete_one_unmergeable_job(Manager *m, Job *j) { return -ENOEXEC; /* Ok, we can drop one, so let's do so. */ - log_notice("Trying to fix job merging by deleting job %s/%s", d->unit->meta.id, job_type_to_string(d->type)); + log_debug("Fixing conflicting jobs by deleting job %s/%s", d->unit->meta.id, job_type_to_string(d->type)); transaction_delete_job(m, d, true); return 0; } @@ -885,7 +928,7 @@ static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned /* Have we seen this before? */ if (j->generation == generation) { - Job *k; + Job *k, *delete; /* If the marker is NULL we have been here already and * decided the job was loop-free from here. Hence @@ -901,17 +944,17 @@ static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned * in there. */ log_warning("Found ordering cycle on %s/%s", j->unit->meta.id, job_type_to_string(j->type)); + delete = NULL; for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) { log_info("Walked on cycle path to %s/%s", k->unit->meta.id, job_type_to_string(k->type)); - if (!k->installed && + if (!delete && + !k->installed && !unit_matters_to_anchor(k->unit, k)) { /* Ok, we can drop this one, so let's * do so. */ - log_warning("Breaking order cycle by deleting job %s/%s", k->unit->meta.id, job_type_to_string(k->type)); - transaction_delete_unit(m, k->unit); - return -EAGAIN; + delete = k; } /* Check if this in fact was the beginning of @@ -920,6 +963,13 @@ static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned break; } + + if (delete) { + log_warning("Breaking ordering cycle by deleting job %s/%s", k->unit->meta.id, job_type_to_string(k->type)); + transaction_delete_unit(m, delete->unit); + return -EAGAIN; + } + log_error("Unable to break cycle"); dbus_set_error(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, "Transaction order is cyclic. See logs for details."); @@ -1061,7 +1111,7 @@ static void transaction_minimize_impact(Manager *m) { j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit)); changes_existing_job = - j->unit->meta.job && job_type_is_conflicting(j->type, j->unit->meta.job->state); + j->unit->meta.job && job_type_is_conflicting(j->type, j->unit->meta.job->type); if (!stops_running_service && !changes_existing_job) continue; @@ -1124,6 +1174,7 @@ static int transaction_apply(Manager *m) { job_add_to_run_queue(j); job_add_to_dbus_queue(j); + job_start_timer(j); } /* As last step, kill all remaining job dependencies. */ @@ -1301,7 +1352,7 @@ void manager_transaction_unlink_job(Manager *m, Job *j, bool delete_dependencies job_dependency_free(j->object_list); if (other && delete_dependencies) { - log_info("Deleting job %s/%s as dependency of job %s/%s", + log_debug("Deleting job %s/%s as dependency of job %s/%s", other->unit->meta.id, job_type_to_string(other->type), j->unit->meta.id, job_type_to_string(j->type)); transaction_delete_job(m, other, delete_dependencies); @@ -1316,6 +1367,7 @@ static int transaction_add_job_and_dependencies( Job *by, bool matters, bool override, + bool conflicts, DBusError *e, Job **_ret) { Job *ret; @@ -1344,46 +1396,50 @@ static int transaction_add_job_and_dependencies( return -ENOMEM; /* Then, add a link to the job. */ - if (!job_dependency_new(by, ret, matters)) + if (!job_dependency_new(by, ret, matters, conflicts)) return -ENOMEM; if (is_new) { /* Finally, recursively add in all dependencies. */ if (type == JOB_START || type == JOB_RELOAD_OR_START) { SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, e, NULL)) < 0 && r != -EBADR) + if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, e, NULL)) < 0 && r != -EBADR) goto fail; SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, e, NULL)) < 0 && r != -EBADR) { + if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, false, e, NULL)) < 0 && r != -EBADR) { log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r)); dbus_error_free(e); } SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_WANTS], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, e, NULL)) < 0) { + if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, false, e, NULL)) < 0) { log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r)); dbus_error_free(e); } SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, e, NULL)) < 0 && r != -EBADR) + if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, e, NULL)) < 0 && r != -EBADR) goto fail; SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, e, NULL)) < 0 && r != -EBADR) { + if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, e, NULL)) < 0 && r != -EBADR) { log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r)); dbus_error_free(e); } SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTS], i) - if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, e, NULL)) < 0 && r != -EBADR) + if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, true, e, NULL)) < 0 && r != -EBADR) + goto fail; + + SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTED_BY], i) + if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, false, e, NULL)) < 0 && r != -EBADR) goto fail; } else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) { SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRED_BY], i) - if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, e, NULL)) < 0 && r != -EBADR) + if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, e, NULL)) < 0 && r != -EBADR) goto fail; } @@ -1424,7 +1480,7 @@ static int transaction_add_isolate_jobs(Manager *m) { if (hashmap_get(m->transaction_jobs, u)) continue; - if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, u, NULL, true, false, NULL, NULL)) < 0) + if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, u, NULL, true, false, false, NULL, NULL)) < 0) log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->meta.id, strerror(-r)); } @@ -1447,7 +1503,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove log_debug("Trying to enqueue job %s/%s", unit->meta.id, job_type_to_string(type)); - if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, e, &ret)) < 0) { + if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, false, e, &ret)) < 0) { transaction_abort(m); return r; } @@ -2022,7 +2078,8 @@ static int process_event(Manager *m, struct epoll_event *ev) { UNIT_VTABLE(w->data.unit)->fd_event(w->data.unit, w->fd, ev->events, w); break; - case WATCH_TIMER: { + case WATCH_UNIT_TIMER: + case WATCH_JOB_TIMER: { uint64_t v; ssize_t k; @@ -2035,7 +2092,10 @@ static int process_event(Manager *m, struct epoll_event *ev) { return k < 0 ? -errno : -EIO; } - UNIT_VTABLE(w->data.unit)->timer_event(w->data.unit, v, w); + if (w->type == WATCH_UNIT_TIMER) + UNIT_VTABLE(w->data.unit)->timer_event(w->data.unit, v, w); + else + job_timer_event(w->data.job, v, w); break; } @@ -2274,7 +2334,7 @@ void manager_dispatch_bus_query_pid_done( UNIT_VTABLE(u)->bus_query_pid_done(u, name, pid); } -int manager_open_serialization(FILE **_f) { +int manager_open_serialization(Manager *m, FILE **_f) { char *path; mode_t saved_umask; int fd; @@ -2282,8 +2342,15 @@ int manager_open_serialization(FILE **_f) { assert(_f); - if (asprintf(&path, "/dev/shm/systemd-%u.dump-XXXXXX", (unsigned) getpid()) < 0) - return -ENOMEM; + if (m->running_as == MANAGER_SYSTEM) { + mkdir_p("/dev/.systemd", 0755); + + if (asprintf(&path, "/dev/.systemd/dump-%lu-XXXXXX", (unsigned long) getpid()) < 0) + return -ENOMEM; + } else { + if (asprintf(&path, "/tmp/systemd-dump-%lu-XXXXXX", (unsigned long) getpid()) < 0) + return -ENOMEM; + } saved_umask = umask(0077); fd = mkostemp(path, O_RDWR|O_CLOEXEC); @@ -2391,7 +2458,7 @@ int manager_reload(Manager *m) { assert(m); - if ((r = manager_open_serialization(&f)) < 0) + if ((r = manager_open_serialization(m, &f)) < 0) return r; if (!(fds = fdset_new())) { @@ -2461,6 +2528,16 @@ bool manager_is_booting_or_shutting_down(Manager *m) { return false; } +void manager_reset_maintenance(Manager *m) { + Unit *u; + Iterator i; + + assert(m); + + HASHMAP_FOREACH(u, m->units, i) + unit_reset_maintenance(u); +} + static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = { [MANAGER_SYSTEM] = "system", [MANAGER_SESSION] = "session"