core, systemctl: add support for irreversible jobs

Add a new job mode: replace-irreversibly. Jobs enqueued using this mode
cannot be implicitly canceled by later enqueued conflicting jobs.
They can however still be canceled with an explicit "systemctl cancel"
call.
This commit is contained in:
Michal Schmidt 2013-02-22 11:21:37 +01:00
parent b7cf6049a3
commit 23ade460e5
7 changed files with 46 additions and 13 deletions

View file

@ -170,6 +170,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
</listitem>
</varlistentry>
<varlistentry>
<term><option>--irreversible</option></term>
<listitem>
<para>Mark this transaction's jobs as irreversible. This prevents
future conflicting transactions from replacing these jobs.
The jobs can still be cancelled using the <command>cancel</command>
command.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--ignore-dependencies</option></term>

View file

@ -169,6 +169,7 @@ static void job_merge_into_installed(Job *j, Job *other) {
assert(other->type == JOB_NOP);
j->override = j->override || other->override;
j->irreversible = j->irreversible || other->irreversible;
j->ignore_order = j->ignore_order || other->ignore_order;
}
@ -294,11 +295,13 @@ void job_dump(Job *j, FILE*f, const char *prefix) {
"%s-> Job %u:\n"
"%s\tAction: %s -> %s\n"
"%s\tState: %s\n"
"%s\tForced: %s\n",
"%s\tForced: %s\n"
"%s\tIrreversible: %s\n",
prefix, j->id,
prefix, j->unit->id, job_type_to_string(j->type),
prefix, job_state_to_string(j->state),
prefix, yes_no(j->override));
prefix, yes_no(j->override),
prefix, yes_no(j->irreversible));
}
/*
@ -947,6 +950,7 @@ int job_serialize(Job *j, FILE *f, FDSet *fds) {
fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
fprintf(f, "job-override=%s\n", yes_no(j->override));
fprintf(f, "job-irreversible=%s\n", yes_no(j->irreversible));
fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal));
fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order));
/* Cannot save bus clients. Just note the fact that we're losing
@ -1014,6 +1018,12 @@ int job_deserialize(Job *j, FILE *f, FDSet *fds) {
log_debug("Failed to parse job override flag %s", v);
else
j->override = j->override || b;
} else if (streq(l, "job-irreversible")) {
int b = parse_boolean(v);
if (b < 0)
log_debug("Failed to parse job irreversible flag %s", v);
else
j->irreversible = j->irreversible || b;
} else if (streq(l, "job-sent-dbus-new-signal")) {
int b = parse_boolean(v);
if (b < 0)
@ -1110,6 +1120,7 @@ DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
static const char* const job_mode_table[_JOB_MODE_MAX] = {
[JOB_FAIL] = "fail",
[JOB_REPLACE] = "replace",
[JOB_REPLACE_IRREVERSIBLY] = "replace-irreversibly",
[JOB_ISOLATE] = "isolate",
[JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
[JOB_IGNORE_REQUIREMENTS] = "ignore-requirements"

View file

@ -83,6 +83,7 @@ enum JobState {
enum JobMode {
JOB_FAIL, /* Fail if a conflicting job is already queued */
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 */
JOB_IGNORE_DEPENDENCIES, /* Ignore both requirement and ordering dependencies */
JOB_IGNORE_REQUIREMENTS, /* Ignore requirement dependencies */
@ -161,6 +162,7 @@ struct Job {
bool sent_dbus_new_signal:1;
bool ignore_order:1;
bool forgot_bus_clients:1;
bool irreversible:1;
};
JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name);

View file

@ -766,7 +766,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
job_type_collapse(&type, unit);
tr = transaction_new();
tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
if (!tr)
return -ENOMEM;

View file

@ -97,6 +97,7 @@ static void transaction_merge_and_delete_job(Transaction *tr, Job *j, Job *other
j->type = t;
j->state = JOB_WAITING;
j->override = j->override || other->override;
j->irreversible = j->irreversible || other->irreversible;
j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;
@ -488,7 +489,7 @@ rescan:
}
}
static int transaction_is_destructive(Transaction *tr, DBusError *e) {
static int transaction_is_destructive(Transaction *tr, JobMode mode, DBusError *e) {
Iterator i;
Job *j;
@ -503,7 +504,7 @@ static int transaction_is_destructive(Transaction *tr, DBusError *e) {
assert(!j->transaction_prev);
assert(!j->transaction_next);
if (j->unit->job &&
if (j->unit->job && (mode == JOB_FAIL || j->unit->job->irreversible) &&
!job_type_is_superset(j->type, j->unit->job->type)) {
dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive.");
@ -709,12 +710,10 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e
transaction_drop_redundant(tr);
/* Ninth step: check whether we can actually apply this */
if (mode == JOB_FAIL) {
r = transaction_is_destructive(tr, e);
if (r < 0) {
log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r));
return r;
}
r = transaction_is_destructive(tr, mode, e);
if (r < 0) {
log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r));
return r;
}
/* Tenth step: apply changes */
@ -770,6 +769,7 @@ static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, b
j->marker = NULL;
j->matters_to_anchor = false;
j->override = override;
j->irreversible = tr->irreversible;
LIST_PREPEND(Job, transaction, f, j);
@ -1106,7 +1106,7 @@ int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
return 0;
}
Transaction *transaction_new(void) {
Transaction *transaction_new(bool irreversible) {
Transaction *tr;
tr = new0(Transaction, 1);
@ -1119,6 +1119,8 @@ Transaction *transaction_new(void) {
return NULL;
}
tr->irreversible = irreversible;
return tr;
}

View file

@ -33,9 +33,10 @@ struct Transaction {
/* Jobs to be added */
Hashmap *jobs; /* Unit object => Job object list 1:1 */
Job *anchor_job; /* the job the user asked for */
bool irreversible;
};
Transaction *transaction_new(void);
Transaction *transaction_new(bool irreversible);
void transaction_free(Transaction *tr);
int transaction_add_job_and_dependencies(

View file

@ -4306,6 +4306,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
enum {
ARG_FAIL = 0x100,
ARG_IRREVERSIBLE,
ARG_IGNORE_DEPENDENCIES,
ARG_VERSION,
ARG_USER,
@ -4334,6 +4335,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "failed", no_argument, NULL, ARG_FAILED },
{ "full", no_argument, NULL, ARG_FULL },
{ "fail", no_argument, NULL, ARG_FAIL },
{ "irreversible", no_argument, NULL, ARG_IRREVERSIBLE },
{ "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES },
{ "ignore-inhibitors", no_argument, NULL, 'i' },
{ "user", no_argument, NULL, ARG_USER },
@ -4433,6 +4435,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
arg_job_mode = "fail";
break;
case ARG_IRREVERSIBLE:
arg_job_mode = "replace-irreversibly";
break;
case ARG_IGNORE_DEPENDENCIES:
arg_job_mode = "ignore-dependencies";
break;