Merge pull request #23508 from yuwata/core-device
core/device: fix devlink handling
This commit is contained in:
+328
-187
@@ -31,7 +31,6 @@ static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
|
||||
};
|
||||
|
||||
static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata);
|
||||
static void device_update_found_one(Device *d, DeviceFound found, DeviceFound mask);
|
||||
|
||||
static void device_unset_sysfs(Device *d) {
|
||||
Hashmap *devices;
|
||||
@@ -116,6 +115,7 @@ static void device_done(Unit *u) {
|
||||
|
||||
device_unset_sysfs(d);
|
||||
d->wants_property = strv_free(d->wants_property);
|
||||
d->path = mfree(d->path);
|
||||
}
|
||||
|
||||
static int device_load(Unit *u) {
|
||||
@@ -156,6 +156,85 @@ static void device_set_state(Device *d, DeviceState state) {
|
||||
unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], 0);
|
||||
}
|
||||
|
||||
static void device_found_changed(Device *d, DeviceFound previous, DeviceFound now) {
|
||||
assert(d);
|
||||
|
||||
/* Didn't exist before, but does now? if so, generate a new invocation ID for it */
|
||||
if (previous == DEVICE_NOT_FOUND && now != DEVICE_NOT_FOUND)
|
||||
(void) unit_acquire_invocation_id(UNIT(d));
|
||||
|
||||
if (FLAGS_SET(now, DEVICE_FOUND_UDEV))
|
||||
/* When the device is known to udev we consider it plugged. */
|
||||
device_set_state(d, DEVICE_PLUGGED);
|
||||
else if (now != DEVICE_NOT_FOUND && !FLAGS_SET(previous, DEVICE_FOUND_UDEV))
|
||||
/* If the device has not been seen by udev yet, but is now referenced by the kernel, then we assume the
|
||||
* kernel knows it now, and udev might soon too. */
|
||||
device_set_state(d, DEVICE_TENTATIVE);
|
||||
else
|
||||
/* If nobody sees the device, or if the device was previously seen by udev and now is only referenced
|
||||
* from the kernel, then we consider the device is gone, the kernel just hasn't noticed it yet. */
|
||||
device_set_state(d, DEVICE_DEAD);
|
||||
}
|
||||
|
||||
static void device_update_found_one(Device *d, DeviceFound found, DeviceFound mask) {
|
||||
assert(d);
|
||||
|
||||
if (MANAGER_IS_RUNNING(UNIT(d)->manager)) {
|
||||
DeviceFound n, previous;
|
||||
|
||||
/* When we are already running, then apply the new mask right-away, and trigger state changes
|
||||
* right-away */
|
||||
|
||||
n = (d->found & ~mask) | (found & mask);
|
||||
if (n == d->found)
|
||||
return;
|
||||
|
||||
previous = d->found;
|
||||
d->found = n;
|
||||
|
||||
device_found_changed(d, previous, n);
|
||||
} else
|
||||
/* We aren't running yet, let's apply the new mask to the shadow variable instead, which we'll apply as
|
||||
* soon as we catch-up with the state. */
|
||||
d->enumerated_found = (d->enumerated_found & ~mask) | (found & mask);
|
||||
}
|
||||
|
||||
static void device_update_found_by_sysfs(Manager *m, const char *sysfs, DeviceFound found, DeviceFound mask) {
|
||||
Device *l;
|
||||
|
||||
assert(m);
|
||||
assert(sysfs);
|
||||
|
||||
if (mask == 0)
|
||||
return;
|
||||
|
||||
l = hashmap_get(m->devices_by_sysfs, sysfs);
|
||||
LIST_FOREACH(same_sysfs, d, l)
|
||||
device_update_found_one(d, found, mask);
|
||||
}
|
||||
|
||||
static void device_update_found_by_name(Manager *m, const char *path, DeviceFound found, DeviceFound mask) {
|
||||
_cleanup_free_ char *e = NULL;
|
||||
Unit *u;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(path);
|
||||
|
||||
if (mask == 0)
|
||||
return;
|
||||
|
||||
r = unit_name_from_path(path, ".device", &e);
|
||||
if (r < 0)
|
||||
return (void) log_debug_errno(r, "Failed to generate unit name from device path, ignoring: %m");
|
||||
|
||||
u = manager_get_unit(m, e);
|
||||
if (!u)
|
||||
return;
|
||||
|
||||
device_update_found_one(DEVICE(u), found, mask);
|
||||
}
|
||||
|
||||
static int device_coldplug(Unit *u) {
|
||||
Device *d = DEVICE(u);
|
||||
|
||||
@@ -191,9 +270,8 @@ static int device_coldplug(Unit *u) {
|
||||
* OPTIONS="db_persist". Hence, almost no devices are enumerated in the step 2. However, in general,
|
||||
* we have several serialized devices. So, DEVICE_FOUND_UDEV bit in the deserialized_found must be
|
||||
* ignored, as udev rules in initramfs and the main system are often different. If the deserialized
|
||||
* state is DEVICE_PLUGGED, we need to downgrade it to DEVICE_TENTATIVE (or DEVICE_DEAD if nobody
|
||||
* sees the device). Unlike the other starting mode, Manager.honor_device_enumeration == false
|
||||
* (maybe, it is better to rename the flag) when device_coldplug() and device_catchup() are called.
|
||||
* state is DEVICE_PLUGGED, we need to downgrade it to DEVICE_TENTATIVE. Unlike the other starting
|
||||
* mode, MANAGER_IS_SWITCHING_ROOT() is true when device_coldplug() and device_catchup() are called.
|
||||
* Hence, let's conditionalize the operations by using the flag. After switch-root, systemd-udevd
|
||||
* will (re-)process all devices, and the Device.found and Device.state will be adjusted.
|
||||
*
|
||||
@@ -201,7 +279,7 @@ static int device_coldplug(Unit *u) {
|
||||
* Of course, deserialized parameters may be outdated, but the unit state can be adjusted later by
|
||||
* device_catchup() or uevents. */
|
||||
|
||||
if (!m->honor_device_enumeration && !MANAGER_IS_USER(m) &&
|
||||
if (MANAGER_IS_SWITCHING_ROOT(m) &&
|
||||
!FLAGS_SET(d->enumerated_found, DEVICE_FOUND_UDEV)) {
|
||||
found &= ~DEVICE_FOUND_UDEV; /* ignore DEVICE_FOUND_UDEV bit */
|
||||
if (state == DEVICE_PLUGGED)
|
||||
@@ -294,6 +372,9 @@ static int device_serialize(Unit *u, FILE *f, FDSet *fds) {
|
||||
assert(f);
|
||||
assert(fds);
|
||||
|
||||
if (d->path)
|
||||
(void) serialize_item(f, "path", d->path);
|
||||
|
||||
(void) serialize_item(f, "state", device_state_to_string(d->state));
|
||||
|
||||
if (device_found_to_string_many(d->found, &s) >= 0)
|
||||
@@ -312,7 +393,14 @@ static int device_deserialize_item(Unit *u, const char *key, const char *value,
|
||||
assert(value);
|
||||
assert(fds);
|
||||
|
||||
if (streq(key, "state")) {
|
||||
if (streq(key, "path")) {
|
||||
if (!d->path) {
|
||||
d->path = strdup(value);
|
||||
if (!d->path)
|
||||
log_oom_debug();
|
||||
}
|
||||
|
||||
} else if (streq(key, "state")) {
|
||||
DeviceState state;
|
||||
|
||||
state = device_state_from_string(value);
|
||||
@@ -342,9 +430,11 @@ static void device_dump(Unit *u, FILE *f, const char *prefix) {
|
||||
|
||||
fprintf(f,
|
||||
"%sDevice State: %s\n"
|
||||
"%sDevice Path: %s\n"
|
||||
"%sSysfs Path: %s\n"
|
||||
"%sFound: %s\n",
|
||||
prefix, device_state_to_string(d->state),
|
||||
prefix, strna(d->path),
|
||||
prefix, strna(d->sysfs),
|
||||
prefix, strna(s));
|
||||
|
||||
@@ -542,16 +632,9 @@ static int device_setup_unit(Manager *m, sd_device *dev, const char *path, bool
|
||||
* dependency on the mount unit which was added during the loading of the later. When the device is
|
||||
* plugged the sysfs might not be initialized yet, as we serialize the device's state but do not
|
||||
* serialize the sysfs path across reloads/reexecs. Hence, when coming back from a reload/restart we
|
||||
* might have the state valid, but not the sysfs path. Hence, let's filter out conflicting devices, but
|
||||
* let's accept devices in any state with no sysfs path set. */
|
||||
|
||||
if (DEVICE(u)->state == DEVICE_PLUGGED &&
|
||||
DEVICE(u)->sysfs &&
|
||||
sysfs &&
|
||||
!path_equal(DEVICE(u)->sysfs, sysfs))
|
||||
return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EEXIST),
|
||||
"Device %s appeared twice with different sysfs paths %s and %s, ignoring the latter.",
|
||||
e, DEVICE(u)->sysfs, sysfs);
|
||||
* might have the state valid, but not the sysfs path. Also, there is another possibility; when multiple
|
||||
* devices have the same devlink (e.g. /dev/disk/by-uuid/xxxx), adding/updating/removing one of the
|
||||
* device causes syspath change. Hence, let's always update sysfs path.*/
|
||||
|
||||
/* Let's remove all dependencies generated due to udev properties. We'll re-add whatever is configured
|
||||
* now below. */
|
||||
@@ -567,6 +650,12 @@ static int device_setup_unit(Manager *m, sd_device *dev, const char *path, bool
|
||||
unit_add_to_load_queue(u);
|
||||
}
|
||||
|
||||
if (!DEVICE(u)->path) {
|
||||
DEVICE(u)->path = strdup(path);
|
||||
if (!DEVICE(u)->path)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
/* If this was created via some dependency and has not actually been seen yet ->sysfs will not be
|
||||
* initialized. Hence initialize it if necessary. */
|
||||
if (sysfs) {
|
||||
@@ -592,158 +681,6 @@ static int device_setup_unit(Manager *m, sd_device *dev, const char *path, bool
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void device_process_new(Manager *m, sd_device *dev, const char *sysfs) {
|
||||
const char *dn, *alias;
|
||||
dev_t devnum;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(dev);
|
||||
assert(sysfs);
|
||||
|
||||
/* Add the main unit named after the sysfs path. If this one fails, don't bother with the rest, as
|
||||
* this one shall be the main device unit the others just follow. (Compare with how
|
||||
* device_following() is implemented, see below, which looks for the sysfs device.) */
|
||||
if (device_setup_unit(m, dev, sysfs, true) < 0)
|
||||
return;
|
||||
|
||||
/* Add an additional unit for the device node */
|
||||
if (sd_device_get_devname(dev, &dn) >= 0)
|
||||
(void) device_setup_unit(m, dev, dn, false);
|
||||
|
||||
/* Add additional units for all symlinks */
|
||||
if (sd_device_get_devnum(dev, &devnum) >= 0) {
|
||||
const char *p;
|
||||
|
||||
FOREACH_DEVICE_DEVLINK(dev, p) {
|
||||
struct stat st;
|
||||
|
||||
if (PATH_STARTSWITH_SET(p, "/dev/block/", "/dev/char/"))
|
||||
continue;
|
||||
|
||||
/* Verify that the symlink in the FS actually belongs to this device. This is useful
|
||||
* to deal with conflicting devices, e.g. when two disks want the same
|
||||
* /dev/disk/by-label/xxx link because they have the same label. We want to make sure
|
||||
* that the same device that won the symlink wins in systemd, so we check the device
|
||||
* node major/minor */
|
||||
if (stat(p, &st) >= 0 &&
|
||||
((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
|
||||
st.st_rdev != devnum)) {
|
||||
log_device_debug(dev, "Skipping device unit creation for symlink %s not owned by device", p);
|
||||
continue;
|
||||
}
|
||||
|
||||
(void) device_setup_unit(m, dev, p, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add additional units for all explicitly configured aliases */
|
||||
r = sd_device_get_property_value(dev, "SYSTEMD_ALIAS", &alias);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
log_device_error_errno(dev, r, "Failed to get SYSTEMD_ALIAS property, ignoring: %m");
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
|
||||
r = extract_first_word(&alias, &word, NULL, EXTRACT_UNQUOTE);
|
||||
if (r == 0)
|
||||
break;
|
||||
if (r == -ENOMEM)
|
||||
return (void) log_oom();
|
||||
if (r < 0)
|
||||
return (void) log_device_warning_errno(dev, r, "Failed to parse SYSTEMD_ALIAS property, ignoring: %m");
|
||||
|
||||
if (!path_is_absolute(word))
|
||||
log_device_warning(dev, "SYSTEMD_ALIAS is not an absolute path, ignoring: %s", word);
|
||||
else if (!path_is_normalized(word))
|
||||
log_device_warning(dev, "SYSTEMD_ALIAS is not a normalized path, ignoring: %s", word);
|
||||
else
|
||||
(void) device_setup_unit(m, dev, word, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void device_found_changed(Device *d, DeviceFound previous, DeviceFound now) {
|
||||
assert(d);
|
||||
|
||||
/* Didn't exist before, but does now? if so, generate a new invocation ID for it */
|
||||
if (previous == DEVICE_NOT_FOUND && now != DEVICE_NOT_FOUND)
|
||||
(void) unit_acquire_invocation_id(UNIT(d));
|
||||
|
||||
if (FLAGS_SET(now, DEVICE_FOUND_UDEV))
|
||||
/* When the device is known to udev we consider it plugged. */
|
||||
device_set_state(d, DEVICE_PLUGGED);
|
||||
else if (now != DEVICE_NOT_FOUND && !FLAGS_SET(previous, DEVICE_FOUND_UDEV))
|
||||
/* If the device has not been seen by udev yet, but is now referenced by the kernel, then we assume the
|
||||
* kernel knows it now, and udev might soon too. */
|
||||
device_set_state(d, DEVICE_TENTATIVE);
|
||||
else
|
||||
/* If nobody sees the device, or if the device was previously seen by udev and now is only referenced
|
||||
* from the kernel, then we consider the device is gone, the kernel just hasn't noticed it yet. */
|
||||
device_set_state(d, DEVICE_DEAD);
|
||||
}
|
||||
|
||||
static void device_update_found_one(Device *d, DeviceFound found, DeviceFound mask) {
|
||||
assert(d);
|
||||
|
||||
if (MANAGER_IS_RUNNING(UNIT(d)->manager)) {
|
||||
DeviceFound n, previous;
|
||||
|
||||
/* When we are already running, then apply the new mask right-away, and trigger state changes
|
||||
* right-away */
|
||||
|
||||
n = (d->found & ~mask) | (found & mask);
|
||||
if (n == d->found)
|
||||
return;
|
||||
|
||||
previous = d->found;
|
||||
d->found = n;
|
||||
|
||||
device_found_changed(d, previous, n);
|
||||
} else
|
||||
/* We aren't running yet, let's apply the new mask to the shadow variable instead, which we'll apply as
|
||||
* soon as we catch-up with the state. */
|
||||
d->enumerated_found = (d->enumerated_found & ~mask) | (found & mask);
|
||||
}
|
||||
|
||||
static void device_update_found_by_sysfs(Manager *m, const char *sysfs, DeviceFound found, DeviceFound mask) {
|
||||
Device *l;
|
||||
|
||||
assert(m);
|
||||
assert(sysfs);
|
||||
|
||||
if (mask == 0)
|
||||
return;
|
||||
|
||||
l = hashmap_get(m->devices_by_sysfs, sysfs);
|
||||
LIST_FOREACH(same_sysfs, d, l)
|
||||
device_update_found_one(d, found, mask);
|
||||
}
|
||||
|
||||
static void device_update_found_by_name(Manager *m, const char *path, DeviceFound found, DeviceFound mask) {
|
||||
_cleanup_free_ char *e = NULL;
|
||||
Unit *u;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(path);
|
||||
|
||||
if (mask == 0)
|
||||
return;
|
||||
|
||||
r = unit_name_from_path(path, ".device", &e);
|
||||
if (r < 0)
|
||||
return (void) log_debug_errno(r, "Failed to generate unit name from device path, ignoring: %m");
|
||||
|
||||
u = manager_get_unit(m, e);
|
||||
if (!u)
|
||||
return;
|
||||
|
||||
device_update_found_one(DEVICE(u), found, mask);
|
||||
}
|
||||
|
||||
static bool device_is_ready(sd_device *dev) {
|
||||
int r;
|
||||
|
||||
@@ -775,6 +712,155 @@ static bool device_is_ready(sd_device *dev) {
|
||||
return r != 0;
|
||||
}
|
||||
|
||||
static int device_setup_devlink_unit_one(Manager *m, const char *devlink, sd_device **ret) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(devlink);
|
||||
|
||||
if (sd_device_new_from_devname(&dev, devlink) < 0 || !device_is_ready(dev)) {
|
||||
/* the devlink is already removed or not ready */
|
||||
device_update_found_by_name(m, devlink, 0, DEVICE_FOUND_UDEV);
|
||||
*ret = NULL;
|
||||
return 0; /* not ready */
|
||||
}
|
||||
|
||||
r = device_setup_unit(m, dev, devlink, /* main = */ false);
|
||||
if (r < 0)
|
||||
return log_device_warning_errno(dev, r, "Failed to setup unit for '%s': %m", devlink);
|
||||
|
||||
*ret = TAKE_PTR(dev);
|
||||
return 1; /* ready */
|
||||
}
|
||||
|
||||
static int device_setup_devlink_units(Manager *m, sd_device *dev, char ***ret_ready_devlinks) {
|
||||
_cleanup_strv_free_ char **ready_devlinks = NULL;
|
||||
const char *devlink, *syspath;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(dev);
|
||||
assert(ret_ready_devlinks);
|
||||
|
||||
r = sd_device_get_syspath(dev, &syspath);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
FOREACH_DEVICE_DEVLINK(dev, devlink) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *assigned = NULL;
|
||||
const char *s;
|
||||
|
||||
if (PATH_STARTSWITH_SET(devlink, "/dev/block/", "/dev/char/"))
|
||||
continue;
|
||||
|
||||
if (device_setup_devlink_unit_one(m, devlink, &assigned) <= 0)
|
||||
continue;
|
||||
|
||||
if (sd_device_get_syspath(assigned, &s) < 0)
|
||||
continue;
|
||||
|
||||
if (path_equal(s, syspath))
|
||||
continue;
|
||||
|
||||
r = strv_extend(&ready_devlinks, devlink);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*ret_ready_devlinks = TAKE_PTR(ready_devlinks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int device_setup_devlink_units_on_remove(Manager *m, sd_device *dev, char ***ret_ready_devlinks) {
|
||||
_cleanup_strv_free_ char **ready_devlinks = NULL;
|
||||
const char *syspath;
|
||||
Device *l;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(dev);
|
||||
assert(ret_ready_devlinks);
|
||||
|
||||
r = sd_device_get_syspath(dev, &syspath);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
l = hashmap_get(m->devices_by_sysfs, syspath);
|
||||
LIST_FOREACH(same_sysfs, d, l) {
|
||||
_cleanup_(sd_device_unrefp) sd_device *assigned = NULL;
|
||||
const char *s;
|
||||
|
||||
if (!d->path)
|
||||
continue;
|
||||
|
||||
if (!path_startswith(d->path, "/dev/"))
|
||||
continue;
|
||||
|
||||
if (device_setup_devlink_unit_one(m, d->path, &assigned) <= 0)
|
||||
continue;
|
||||
|
||||
if (sd_device_get_syspath(assigned, &s) < 0)
|
||||
continue;
|
||||
|
||||
if (path_equal(s, syspath))
|
||||
continue;
|
||||
|
||||
r = strv_extend(&ready_devlinks, d->path);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*ret_ready_devlinks = TAKE_PTR(ready_devlinks);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void device_process_new(Manager *m, sd_device *dev, const char *sysfs) {
|
||||
const char *dn, *alias;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(dev);
|
||||
assert(sysfs);
|
||||
|
||||
/* Add the main unit named after the sysfs path. If this one fails, don't bother with the rest, as
|
||||
* this one shall be the main device unit the others just follow. (Compare with how
|
||||
* device_following() is implemented, see below, which looks for the sysfs device.) */
|
||||
if (device_setup_unit(m, dev, sysfs, /* main = */ true) < 0)
|
||||
return;
|
||||
|
||||
/* Add an additional unit for the device node */
|
||||
if (sd_device_get_devname(dev, &dn) >= 0)
|
||||
(void) device_setup_unit(m, dev, dn, /* main = */ false);
|
||||
|
||||
/* Add additional units for all explicitly configured aliases */
|
||||
r = sd_device_get_property_value(dev, "SYSTEMD_ALIAS", &alias);
|
||||
if (r < 0) {
|
||||
if (r != -ENOENT)
|
||||
log_device_error_errno(dev, r, "Failed to get SYSTEMD_ALIAS property, ignoring: %m");
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
|
||||
r = extract_first_word(&alias, &word, NULL, EXTRACT_UNQUOTE);
|
||||
if (r == 0)
|
||||
break;
|
||||
if (r == -ENOMEM)
|
||||
return (void) log_oom();
|
||||
if (r < 0)
|
||||
return (void) log_device_warning_errno(dev, r, "Failed to parse SYSTEMD_ALIAS property, ignoring: %m");
|
||||
|
||||
if (!path_is_absolute(word))
|
||||
log_device_warning(dev, "SYSTEMD_ALIAS is not an absolute path, ignoring: %s", word);
|
||||
else if (!path_is_normalized(word))
|
||||
log_device_warning(dev, "SYSTEMD_ALIAS is not a normalized path, ignoring: %s", word);
|
||||
else
|
||||
(void) device_setup_unit(m, dev, word, /* main = */ false);
|
||||
}
|
||||
}
|
||||
|
||||
static Unit *device_following(Unit *u) {
|
||||
Device *d = DEVICE(u);
|
||||
Device *first = NULL;
|
||||
@@ -890,10 +976,9 @@ static void device_enumerate(Manager *m) {
|
||||
}
|
||||
|
||||
FOREACH_DEVICE(e, dev) {
|
||||
_cleanup_strv_free_ char **ready_devlinks = NULL;
|
||||
const char *sysfs;
|
||||
|
||||
if (!device_is_ready(dev))
|
||||
continue;
|
||||
bool ready;
|
||||
|
||||
r = sd_device_get_syspath(dev, &sysfs);
|
||||
if (r < 0) {
|
||||
@@ -901,8 +986,18 @@ static void device_enumerate(Manager *m) {
|
||||
continue;
|
||||
}
|
||||
|
||||
device_process_new(m, dev, sysfs);
|
||||
device_update_found_by_sysfs(m, sysfs, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV);
|
||||
ready = device_is_ready(dev);
|
||||
if (ready)
|
||||
device_process_new(m, dev, sysfs);
|
||||
|
||||
/* Add additional units for all symlinks */
|
||||
(void) device_setup_devlink_units(m, dev, &ready_devlinks);
|
||||
|
||||
if (ready)
|
||||
device_update_found_by_sysfs(m, sysfs, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV);
|
||||
|
||||
STRV_FOREACH(devlink, ready_devlinks)
|
||||
device_update_found_by_name(m, *devlink, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -925,10 +1020,34 @@ static void device_propagate_reload_by_sysfs(Manager *m, const char *sysfs) {
|
||||
|
||||
r = manager_propagate_reload(m, UNIT(d), JOB_REPLACE, NULL);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to propagate reload, ignoring: %m");
|
||||
log_unit_warning_errno(UNIT(d), r, "Failed to propagate reload, ignoring: %m");
|
||||
}
|
||||
}
|
||||
|
||||
static void device_propagate_reload_by_name(Manager *m, const char *path) {
|
||||
_cleanup_free_ char *e = NULL;
|
||||
Unit *u;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(path);
|
||||
|
||||
r = unit_name_from_path(path, ".device", &e);
|
||||
if (r < 0)
|
||||
return (void) log_debug_errno(r, "Failed to generate unit name from device path, ignoring: %m");
|
||||
|
||||
u = manager_get_unit(m, e);
|
||||
if (!u)
|
||||
return;
|
||||
|
||||
if (DEVICE(u)->state == DEVICE_DEAD)
|
||||
return;
|
||||
|
||||
r = manager_propagate_reload(m, u, JOB_REPLACE, NULL);
|
||||
if (r < 0)
|
||||
log_unit_warning_errno(u, r, "Failed to propagate reload, ignoring: %m");
|
||||
}
|
||||
|
||||
static void device_remove_old_on_move(Manager *m, sd_device *dev) {
|
||||
_cleanup_free_ char *syspath_old = NULL;
|
||||
const char *devpath_old;
|
||||
@@ -949,9 +1068,11 @@ static void device_remove_old_on_move(Manager *m, sd_device *dev) {
|
||||
}
|
||||
|
||||
static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
|
||||
_cleanup_strv_free_ char **ready_devlinks = NULL;
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
sd_device_action_t action;
|
||||
const char *sysfs;
|
||||
bool ready;
|
||||
int r;
|
||||
|
||||
assert(dev);
|
||||
@@ -970,9 +1091,6 @@ static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!IN_SET(action, SD_DEVICE_ADD, SD_DEVICE_REMOVE, SD_DEVICE_MOVE))
|
||||
device_propagate_reload_by_sysfs(m, sysfs);
|
||||
|
||||
if (action == SD_DEVICE_MOVE)
|
||||
device_remove_old_on_move(m, dev);
|
||||
|
||||
@@ -984,27 +1102,50 @@ static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *
|
||||
if (r < 0)
|
||||
log_device_warning_errno(dev, r, "Failed to process swap device remove event, ignoring: %m");
|
||||
|
||||
/* If we get notified that a device was removed by udev, then it's completely gone, hence
|
||||
* unset all found bits */
|
||||
device_update_found_by_sysfs(m, sysfs, DEVICE_NOT_FOUND, DEVICE_FOUND_MASK);
|
||||
ready = false;
|
||||
|
||||
} else if (device_is_ready(dev)) {
|
||||
(void) device_setup_devlink_units_on_remove(m, dev, &ready_devlinks);
|
||||
|
||||
device_process_new(m, dev, sysfs);
|
||||
} else {
|
||||
ready = device_is_ready(dev);
|
||||
|
||||
r = swap_process_device_new(m, dev);
|
||||
if (r < 0)
|
||||
log_device_warning_errno(dev, r, "Failed to process swap device new event, ignoring: %m");
|
||||
if (ready) {
|
||||
device_process_new(m, dev, sysfs);
|
||||
|
||||
r = swap_process_device_new(m, dev);
|
||||
if (r < 0)
|
||||
log_device_warning_errno(dev, r, "Failed to process swap device new event, ignoring: %m");
|
||||
}
|
||||
|
||||
/* Add additional units for all symlinks */
|
||||
(void) device_setup_devlink_units(m, dev, &ready_devlinks);
|
||||
}
|
||||
|
||||
if (!IN_SET(action, SD_DEVICE_ADD, SD_DEVICE_REMOVE, SD_DEVICE_MOVE)) {
|
||||
device_propagate_reload_by_sysfs(m, sysfs);
|
||||
|
||||
STRV_FOREACH(devlink, ready_devlinks)
|
||||
device_propagate_reload_by_name(m, *devlink);
|
||||
}
|
||||
|
||||
if (ready || !strv_isempty(ready_devlinks))
|
||||
manager_dispatch_load_queue(m);
|
||||
|
||||
if (action == SD_DEVICE_REMOVE)
|
||||
/* If we get notified that a device was removed by udev, then it's completely gone, hence
|
||||
* unset all found bits */
|
||||
device_update_found_by_sysfs(m, sysfs, 0, DEVICE_FOUND_MASK);
|
||||
else if (ready)
|
||||
/* The device is found now, set the udev found bit */
|
||||
device_update_found_by_sysfs(m, sysfs, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV);
|
||||
} else
|
||||
else
|
||||
/* The device is nominally around, but not ready for us. Hence unset the udev bit, but leave
|
||||
* the rest around. */
|
||||
device_update_found_by_sysfs(m, sysfs, DEVICE_NOT_FOUND, DEVICE_FOUND_UDEV);
|
||||
|
||||
STRV_FOREACH(devlink, ready_devlinks)
|
||||
device_update_found_by_name(m, *devlink, DEVICE_FOUND_UDEV, DEVICE_FOUND_UDEV);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1047,7 +1188,7 @@ void device_found_node(Manager *m, const char *node, DeviceFound found, DeviceFo
|
||||
return;
|
||||
}
|
||||
|
||||
(void) device_setup_unit(m, dev, node, false); /* 'dev' may be NULL. */
|
||||
(void) device_setup_unit(m, dev, node, /* main = */ false); /* 'dev' may be NULL. */
|
||||
}
|
||||
|
||||
/* Update the device unit's state, should it exist */
|
||||
|
||||
@@ -21,6 +21,7 @@ struct Device {
|
||||
Unit meta;
|
||||
|
||||
char *sysfs;
|
||||
char *path; /* syspath, device node, alias, or devlink */
|
||||
|
||||
/* In order to be able to distinguish dependencies on different device nodes we might end up creating multiple
|
||||
* devices for the same sysfs path. We chain them up here. */
|
||||
|
||||
@@ -1966,6 +1966,8 @@ static int invoke_main_loop(
|
||||
return objective;
|
||||
|
||||
case MANAGER_SWITCH_ROOT:
|
||||
manager_set_switching_root(m, true);
|
||||
|
||||
if (!m->switch_root_init) {
|
||||
r = prepare_reexecute(m, &arg_serialization, ret_fds, true);
|
||||
if (r < 0) {
|
||||
@@ -2943,6 +2945,7 @@ int main(int argc, char *argv[]) {
|
||||
set_manager_defaults(m);
|
||||
set_manager_settings(m);
|
||||
manager_set_first_boot(m, first_boot);
|
||||
manager_set_switching_root(m, arg_switched_root);
|
||||
|
||||
/* Remember whether we should queue the default job */
|
||||
queue_default_job = !arg_serialization || arg_switched_root;
|
||||
|
||||
@@ -103,9 +103,6 @@ int manager_serialize(
|
||||
(void) serialize_bool(f, "taint-logged", m->taint_logged);
|
||||
(void) serialize_bool(f, "service-watchdogs", m->service_watchdogs);
|
||||
|
||||
/* After switching root, udevd has not been started yet. So, enumeration results should not be emitted. */
|
||||
(void) serialize_bool(f, "honor-device-enumeration", !switching_root);
|
||||
|
||||
if (m->show_status_overridden != _SHOW_STATUS_INVALID)
|
||||
(void) serialize_item(f, "show-status-overridden",
|
||||
show_status_to_string(m->show_status_overridden));
|
||||
@@ -399,15 +396,6 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
||||
else
|
||||
m->service_watchdogs = b;
|
||||
|
||||
} else if ((val = startswith(l, "honor-device-enumeration="))) {
|
||||
int b;
|
||||
|
||||
b = parse_boolean(val);
|
||||
if (b < 0)
|
||||
log_notice("Failed to parse honor-device-enumeration flag '%s', ignoring.", val);
|
||||
else
|
||||
m->honor_device_enumeration = b;
|
||||
|
||||
} else if ((val = startswith(l, "show-status-overridden="))) {
|
||||
ShowStatus s;
|
||||
|
||||
@@ -544,7 +532,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
|
||||
|
||||
if (q < _MANAGER_TIMESTAMP_MAX) /* found it */
|
||||
(void) deserialize_dual_timestamp(val, m->timestamps + q);
|
||||
else if (!startswith(l, "kdbus-fd=")) /* ignore kdbus */
|
||||
else if (!STARTSWITH_SET(l, "kdbus-fd=", "honor-device-enumeration=")) /* ignore deprecated values */
|
||||
log_notice("Unknown serialization item '%s', ignoring.", l);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-7
@@ -807,6 +807,10 @@ static int manager_find_credentials_dirs(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void manager_set_switching_root(Manager *m, bool switching_root) {
|
||||
m->switching_root = MANAGER_IS_SYSTEM(m) && switching_root;
|
||||
}
|
||||
|
||||
int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager **_m) {
|
||||
_cleanup_(manager_freep) Manager *m = NULL;
|
||||
int r;
|
||||
@@ -1760,8 +1764,6 @@ static void manager_ready(Manager *m) {
|
||||
(void) touch_file("/run/systemd/systemd-units-load", false,
|
||||
m->timestamps[MANAGER_TIMESTAMP_UNITS_LOAD].realtime ?: now(CLOCK_REALTIME),
|
||||
UID_INVALID, GID_INVALID, 0444);
|
||||
|
||||
m->honor_device_enumeration = true;
|
||||
}
|
||||
|
||||
Manager* manager_reloading_start(Manager *m) {
|
||||
@@ -1872,6 +1874,8 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds, const char *roo
|
||||
|
||||
manager_ready(m);
|
||||
|
||||
manager_set_switching_root(m, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3418,11 +3422,6 @@ int manager_reload(Manager *m) {
|
||||
assert(m->n_reloading > 0);
|
||||
m->n_reloading--;
|
||||
|
||||
/* On manager reloading, device tag data should exists, thus, we should honor the results of device
|
||||
* enumeration. The flag should be always set correctly by the serialized data, but it may fail. So,
|
||||
* let's always set the flag here for safety. */
|
||||
m->honor_device_enumeration = true;
|
||||
|
||||
manager_ready(m);
|
||||
|
||||
m->send_reloading_done = true;
|
||||
|
||||
+6
-2
@@ -406,6 +406,9 @@ struct Manager {
|
||||
char *switch_root;
|
||||
char *switch_root_init;
|
||||
|
||||
/* This is true before and after switching root. */
|
||||
bool switching_root;
|
||||
|
||||
/* This maps all possible path prefixes to the units needing
|
||||
* them. It's a hashmap with a path string as key and a Set as
|
||||
* value where Unit objects are contained. */
|
||||
@@ -446,8 +449,6 @@ struct Manager {
|
||||
unsigned sigchldgen;
|
||||
unsigned notifygen;
|
||||
|
||||
bool honor_device_enumeration;
|
||||
|
||||
VarlinkServer *varlink_server;
|
||||
/* When we're a system manager, this object manages the subscription from systemd-oomd to PID1 that's
|
||||
* used to report changes in ManagedOOM settings (systemd server - oomd client). When
|
||||
@@ -476,6 +477,8 @@ static inline usec_t manager_default_timeout_abort_usec(Manager *m) {
|
||||
/* The objective is set to OK as soon as we enter the main loop, and set otherwise as soon as we are done with it */
|
||||
#define MANAGER_IS_RUNNING(m) ((m)->objective == MANAGER_OK)
|
||||
|
||||
#define MANAGER_IS_SWITCHING_ROOT(m) ((m)->switching_root)
|
||||
|
||||
#define MANAGER_IS_TEST_RUN(m) ((m)->test_run_flags != 0)
|
||||
|
||||
int manager_new(LookupScope scope, ManagerTestRunFlags test_run_flags, Manager **m);
|
||||
@@ -541,6 +544,7 @@ void manager_set_show_status(Manager *m, ShowStatus mode, const char *reason);
|
||||
void manager_override_show_status(Manager *m, ShowStatus mode, const char *reason);
|
||||
|
||||
void manager_set_first_boot(Manager *m, bool b);
|
||||
void manager_set_switching_root(Manager *m, bool switching_root);
|
||||
|
||||
void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) _printf_(4,5);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user