summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/device.c46
-rw-r--r--src/core/device.h3
-rw-r--r--src/core/mount.c20
-rw-r--r--src/core/unit.c3
4 files changed, 71 insertions, 1 deletions
diff --git a/src/core/device.c b/src/core/device.c
index e345552f24..bd481c8050 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -285,6 +285,37 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
}
}
+static bool device_is_bound_by_mounts(Unit *d, struct udev_device *dev) {
+ const char *bound_by;
+ int r = false;
+
+ assert(d);
+ assert(dev);
+
+ bound_by = udev_device_get_property_value(dev, "SYSTEMD_MOUNT_DEVICE_BOUND");
+ if (bound_by)
+ r = parse_boolean(bound_by) > 0;
+
+ DEVICE(d)->bind_mounts = r;
+ return r;
+}
+
+static int device_upgrade_mount_deps(Unit *u) {
+ Unit *other;
+ Iterator i;
+ int r;
+
+ SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i) {
+ if (other->type != UNIT_MOUNT)
+ continue;
+
+ r = unit_add_dependency(other, UNIT_BINDS_TO, u, true);
+ if (r < 0)
+ return r;
+ }
+ return 0;
+}
+
static int device_setup_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
_cleanup_free_ char *e = NULL;
const char *sysfs = NULL;
@@ -349,6 +380,13 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
(void) device_add_udev_wants(u, dev);
}
+ /* So the user wants the mount units to be bound to the device but a
+ * mount unit might has been seen by systemd before the device appears
+ * on its radar. In this case the device unit is partially initialized
+ * and includes the deps on the mount unit but at that time the "bind
+ * mounts" flag wasn't not present. Fix this up now. */
+ if (device_is_bound_by_mounts(u, dev))
+ device_upgrade_mount_deps(u);
/* Note that this won't dispatch the load queue, the caller
* has to do that if needed and appropriate */
@@ -824,6 +862,14 @@ int device_found_node(Manager *m, const char *node, bool add, DeviceFound found,
return device_update_found_by_name(m, node, add, found, now);
}
+bool device_shall_be_bound_by(Unit *device, Unit *u) {
+
+ if (u->type != UNIT_MOUNT)
+ return false;
+
+ return DEVICE(device)->bind_mounts;
+}
+
const UnitVTable device_vtable = {
.object_size = sizeof(Device),
.sections =
diff --git a/src/core/device.h b/src/core/device.h
index 184a1a349b..dd372fb695 100644
--- a/src/core/device.h
+++ b/src/core/device.h
@@ -40,8 +40,11 @@ struct Device {
LIST_FIELDS(struct Device, same_sysfs);
DeviceState state, deserialized_state;
+
+ bool bind_mounts;
};
extern const UnitVTable device_vtable;
int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now);
+bool device_shall_be_bound_by(Unit *device, Unit *u);
diff --git a/src/core/mount.c b/src/core/mount.c
index 997dbe3837..daf7f5697b 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -135,6 +135,16 @@ static bool mount_state_active(MountState state) {
MOUNT_REMOUNTING_SIGKILL);
}
+static bool mount_is_bound_to_device(const Mount *m) {
+ const MountParameters *p;
+
+ if (m->from_fragment)
+ return true;
+
+ p = &m->parameters_proc_self_mountinfo;
+ return fstab_test_option(p->options, "x-systemd.device-bound\0");
+}
+
static bool needs_quota(const MountParameters *p) {
assert(p);
@@ -324,6 +334,7 @@ static int mount_add_mount_links(Mount *m) {
static int mount_add_device_links(Mount *m) {
MountParameters *p;
bool device_wants_mount = false;
+ UnitDependency dep;
int r;
assert(m);
@@ -353,7 +364,14 @@ static int mount_add_device_links(Mount *m) {
if (mount_is_auto(p) && !mount_is_automount(p) && MANAGER_IS_SYSTEM(UNIT(m)->manager))
device_wants_mount = true;
- r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, m->from_fragment ? UNIT_BINDS_TO : UNIT_REQUIRES);
+ /* Mount units from /proc/self/mountinfo are not bound to devices
+ * by default since they're subject to races when devices are
+ * unplugged. But the user can still force this dep with an
+ * appropriate option (or udev property) so the mount units are
+ * automatically stopped when the device disappears suddenly. */
+ dep = mount_is_bound_to_device(m) ? UNIT_BINDS_TO : UNIT_REQUIRES;
+
+ r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, dep);
if (r < 0)
return r;
diff --git a/src/core/unit.c b/src/core/unit.c
index ab40135736..5d0b17425b 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -3048,6 +3048,9 @@ int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep
if (r < 0)
return r;
+ if (dep == UNIT_REQUIRES && device_shall_be_bound_by(device, u))
+ dep = UNIT_BINDS_TO;
+
r = unit_add_two_dependencies(u, UNIT_AFTER,
MANAGER_IS_SYSTEM(u->manager) ? dep : UNIT_WANTS,
device, true);