summaryrefslogtreecommitdiffstats
path: root/src/core/job.c
diff options
context:
space:
mode:
authorMichal Schmidt <mschmidt@redhat.com>2012-10-25 02:31:49 +0200
committerMichal Schmidt <mschmidt@redhat.com>2012-10-25 03:21:32 +0200
commit1abc85b8d026a2d72442b0edaee5213d0ee73c1f (patch)
treecb53060d8b9af09bb21720d7534349f0e0c70c41 /src/core/job.c
parentjob: add comments to JobResult values (diff)
downloadsystemd-1abc85b8d026a2d72442b0edaee5213d0ee73c1f.tar.xz
systemd-1abc85b8d026a2d72442b0edaee5213d0ee73c1f.zip
job: avoid recursion into transaction code from job cancelation
I hit an "assert(j->installed)" failure in transaction_apply(). Looking into the backtrace I saw what happened: 1. The system was booting. var.mount/start was an installed job. 2. I pressed Ctrl+Alt+Del. 3. reboot.target was going to be isolated. 4. transaction_apply() proceeded to install a var.mount/stop job. 5. job_install() canceled the conflicting start job. 6. Depending jobs ended recursively with JOB_DEPENDENCY, among them was local-fs.target/start. 7. Its OnFailure action triggered - emergency.target was now going to be isolated. 8. We recursed back into transaction_apply() where the half-installed var.mount/stop job confused us. Recursing from job installation back into the transaction code cannot be a good idea. Avoid the problem by canceling the conflicting job non-recursively in job_install(). I don't think we'll miss anything by not recursing here. After all, we are called from transaction_apply(). We will not be installing just this one job, but all jobs from a transaction. All requirement dependencies will be included in it and will be installed separately. Every transaction job will get a chance to cancel its own conflicting installed job.
Diffstat (limited to '')
-rw-r--r--src/core/job.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/src/core/job.c b/src/core/job.c
index cb5674b5a8..f08b8cbc7d 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -180,7 +180,7 @@ Job* job_install(Job *j) {
if (uj) {
if (j->type != JOB_NOP && job_type_is_conflicting(uj->type, j->type))
- job_finish_and_invalidate(uj, JOB_CANCELED, true);
+ job_finish_and_invalidate(uj, JOB_CANCELED, false);
else {
/* not conflicting, i.e. mergeable */