803fb7
From 75b183700853e616362cf2f22831e1e9dc8a5515 Mon Sep 17 00:00:00 2001
803fb7
From: Harald Hoyer <harald@redhat.com>
803fb7
Date: Tue, 24 Nov 2015 09:41:26 +0100
803fb7
Subject: [PATCH] core: Do not bind a mount unit to a device, if it was from
803fb7
 mountinfo
803fb7
803fb7
If a mount unit is bound to a device, systemd tries to umount the
803fb7
mount point, if it thinks the device has gone away.
803fb7
803fb7
Due to the uevent queue and inotify of /proc/self/mountinfo being two
803fb7
different sources, systemd can never get the ordering reliably correct.
803fb7
803fb7
It can happen, that in the uevent queue ADD,REMOVE,ADD is queued
803fb7
and an inotify of mountinfo (or libmount event) happend with the
803fb7
device in question.
803fb7
803fb7
systemd cannot know, at which point of time the mount happend in the
803fb7
ADD,REMOVE,ADD sequence.
803fb7
803fb7
The real ordering might have been ADD,REMOVE,ADD,mount
803fb7
and systemd might think ADD,mount,REMOVE,ADD and would umount the
803fb7
mountpoint.
803fb7
803fb7
A test script which triggered this behaviour is:
803fb7
rm -f test-efi-disk.img
803fb7
dd if=/dev/null of=test-efi-disk.img bs=1M seek=512 count=1
803fb7
parted --script test-efi-disk.img \
803fb7
  "mklabel gpt" \
803fb7
  "mkpart ESP fat32 1MiB 511MiB" \
803fb7
  "set 1 boot on"
803fb7
LOOP=$(losetup --show -f -P test-efi-disk.img)
803fb7
udevadm settle
803fb7
mkfs.vfat -F32 ${LOOP}p1
803fb7
mkdir -p mnt
803fb7
mount ${LOOP}p1 mnt
803fb7
... <dostuffwith mnt>
803fb7
803fb7
Without the "udevadm settle" systemd unmounted mnt while the script was
803fb7
operating on mnt.
803fb7
803fb7
Of course the question is, why there was a REMOVE in the first place,
803fb7
but this is not part of this patch.
803fb7
803fb7
Cherry-picked from: 9d06297e262966de71095debd1537fc223f940a3
803fb7
Resolves: #1283579
803fb7
---
803fb7
 src/core/mount.c  | 2 +-
803fb7
 src/core/socket.c | 2 +-
803fb7
 src/core/swap.c   | 2 +-
803fb7
 src/core/unit.c   | 4 ++--
803fb7
 src/core/unit.h   | 2 +-
803fb7
 5 files changed, 6 insertions(+), 6 deletions(-)
803fb7
803fb7
diff --git a/src/core/mount.c b/src/core/mount.c
803fb7
index 1f1a41ab6..23f63ce32 100644
803fb7
--- a/src/core/mount.c
803fb7
+++ b/src/core/mount.c
803fb7
@@ -321,7 +321,7 @@ static int mount_add_device_links(Mount *m) {
803fb7
         if (mount_is_auto(p) && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM)
803fb7
                 device_wants_mount = true;
803fb7
 
803fb7
-        r = unit_add_node_link(UNIT(m), p->what, device_wants_mount);
803fb7
+        r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, m->from_fragment ? UNIT_BINDS_TO : UNIT_REQUIRES);
803fb7
         if (r < 0)
803fb7
                 return r;
803fb7
 
803fb7
diff --git a/src/core/socket.c b/src/core/socket.c
803fb7
index 7022e77b5..bc677a20f 100644
803fb7
--- a/src/core/socket.c
803fb7
+++ b/src/core/socket.c
803fb7
@@ -267,7 +267,7 @@ static int socket_add_device_link(Socket *s) {
803fb7
                 return 0;
803fb7
 
803fb7
         t = strjoina("/sys/subsystem/net/devices/", s->bind_to_device);
803fb7
-        return unit_add_node_link(UNIT(s), t, false);
803fb7
+        return unit_add_node_link(UNIT(s), t, false, UNIT_BINDS_TO);
803fb7
 }
803fb7
 
803fb7
 static int socket_add_default_dependencies(Socket *s) {
803fb7
diff --git a/src/core/swap.c b/src/core/swap.c
803fb7
index 369abf0f5..34a2c406d 100644
803fb7
--- a/src/core/swap.c
803fb7
+++ b/src/core/swap.c
803fb7
@@ -201,7 +201,7 @@ static int swap_add_device_links(Swap *s) {
803fb7
                 return 0;
803fb7
 
803fb7
         if (is_device_path(s->what))
803fb7
-                return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == SYSTEMD_SYSTEM);
803fb7
+                return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == SYSTEMD_SYSTEM, UNIT_BINDS_TO);
803fb7
         else
803fb7
                 /* File based swap devices need to be ordered after
803fb7
                  * systemd-remount-fs.service, since they might need a
803fb7
diff --git a/src/core/unit.c b/src/core/unit.c
803fb7
index fa17567dd..ae47a2876 100644
803fb7
--- a/src/core/unit.c
803fb7
+++ b/src/core/unit.c
803fb7
@@ -2823,7 +2823,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
803fb7
         }
803fb7
 }
803fb7
 
803fb7
-int unit_add_node_link(Unit *u, const char *what, bool wants) {
803fb7
+int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep) {
803fb7
         Unit *device;
803fb7
         _cleanup_free_ char *e = NULL;
803fb7
         int r;
803fb7
@@ -2850,7 +2850,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) {
803fb7
         if (r < 0)
803fb7
                 return r;
803fb7
 
803fb7
-        r = unit_add_two_dependencies(u, UNIT_AFTER, u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_BINDS_TO : UNIT_WANTS, device, true);
803fb7
+        r = unit_add_two_dependencies(u, UNIT_AFTER, u->manager->running_as == SYSTEMD_SYSTEM ? dep : UNIT_WANTS, device, true);
803fb7
         if (r < 0)
803fb7
                 return r;
803fb7
 
803fb7
diff --git a/src/core/unit.h b/src/core/unit.h
803fb7
index 7ebc489c8..0eebc0b89 100644
803fb7
--- a/src/core/unit.h
803fb7
+++ b/src/core/unit.h
803fb7
@@ -548,7 +548,7 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *v
803fb7
 void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
803fb7
 int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
803fb7
 
803fb7
-int unit_add_node_link(Unit *u, const char *what, bool wants);
803fb7
+int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency d);
803fb7
 
803fb7
 int unit_coldplug(Unit *u, Hashmap *deferred_work);
803fb7