diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/device.c | 46 | ||||
-rw-r--r-- | src/core/device.h | 3 | ||||
-rw-r--r-- | src/core/mount.c | 20 | ||||
-rw-r--r-- | src/core/unit.c | 3 |
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); |