summaryrefslogtreecommitdiff
path: root/src/core/swap.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-01-28 00:38:38 +0100
committerLennart Poettering <lennart@poettering.net>2015-01-28 00:38:38 +0100
commit37cf8fee46025d704660a9fc1d1349fe7d0b139d (patch)
treead519ff7f56ec9e494fa47f3e438fe57351f5a31 /src/core/swap.c
parentcaac2704d57ef6d95f7053456479353bae3638de (diff)
core: if two start jobs for the same swap device node are queued, only dispatch one of them at a time
If two start jobs for two seperate .swap device nodes are queued, which then turns out to be referring to the same device node, refuse dispatching more than one of them at the same time. This should solve an issue when the same swap partition is found via GPT auto-discovery and via /etc/fstab, where one uses a symlink path, and the other the raw devce node. So far we might have ended up invoking mkswap on the same node at the very same time with the two device node names. With this change only one mkswap should be executed at a time. THis mkswap should have immediate effect on the other swap unit, due to the state in /proc/swaps changing, and thus suppressing actual invocation of the second mkswap. http://lists.freedesktop.org/archives/systemd-devel/2015-January/027314.html
Diffstat (limited to 'src/core/swap.c')
-rw-r--r--src/core/swap.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/src/core/swap.c b/src/core/swap.c
index b97f102d64..1ef672f7e9 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -473,6 +473,7 @@ static int swap_process_new_swap(Manager *m, const char *device, int prio, bool
static void swap_set_state(Swap *s, SwapState state) {
SwapState old_state;
+ Swap *other;
assert(s);
@@ -500,6 +501,15 @@ static void swap_set_state(Swap *s, SwapState state) {
swap_state_to_string(state));
unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
+
+ /* If there other units for the same device node have a job
+ queued it might be worth checking again if it is runnable
+ now. This is necessary, since swap_start() refuses
+ operation with EAGAIN if there's already another job for
+ the same device node queued. */
+ LIST_FOREACH_OTHERS(same_devnode, other, s)
+ if (UNIT(other)->job)
+ job_add_to_run_queue(UNIT(other)->job);
}
static int swap_coldplug(Unit *u) {
@@ -796,7 +806,7 @@ fail:
}
static int swap_start(Unit *u) {
- Swap *s = SWAP(u);
+ Swap *s = SWAP(u), *other;
assert(s);
@@ -818,6 +828,13 @@ static int swap_start(Unit *u) {
if (detect_container(NULL) > 0)
return -EPERM;
+ /* If there's a job for another swap unit for the same node
+ * running, then let's not dispatch this one for now, and wait
+ * until that other job has finished. */
+ LIST_FOREACH_OTHERS(same_devnode, other, s)
+ if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING)
+ return -EAGAIN;
+
s->result = SWAP_SUCCESS;
swap_enter_activating(s);
return 0;