mirror of
https://github.com/systemd/systemd
synced 2024-10-15 12:34:37 +00:00
udev: use device ID to find blockers
If two devices have the same devnum and subsystem (more specifically, if the device is block or not), or have the same ifindex, then IDs of these devices are equivalent. Hence, the previous conditions are covered by comparing device IDs. Of course, events with a same ID should be already blocked by the devpath check. So, this should not change anything. However, udevd saves many kinds of data under /run/udev named with the device ID. If multiple workers processes events for the same device ID, then the database may become corrupted. Let's explicitly check the device IDs for safety and simplicity.
This commit is contained in:
parent
fa2ba7aea8
commit
29d0245832
|
@ -131,6 +131,9 @@ typedef struct Event {
|
|||
sd_device_action_t action;
|
||||
uint64_t seqnum;
|
||||
uint64_t blocker_seqnum;
|
||||
const char *id;
|
||||
const char *devpath;
|
||||
const char *devpath_old;
|
||||
usec_t retry_again_next_usec;
|
||||
usec_t retry_again_timeout_usec;
|
||||
|
||||
|
@ -852,12 +855,9 @@ static int event_run(Event *event) {
|
|||
}
|
||||
|
||||
static int event_is_blocked(Event *event) {
|
||||
const char *subsystem, *devpath, *devpath_old = NULL;
|
||||
dev_t devnum = makedev(0, 0);
|
||||
Event *loop_event = NULL;
|
||||
size_t devpath_len;
|
||||
int r, ifindex = 0;
|
||||
bool is_block;
|
||||
int r;
|
||||
|
||||
/* lookup event for identical, parent, child device */
|
||||
|
||||
|
@ -903,34 +903,11 @@ static int event_is_blocked(Event *event) {
|
|||
assert(loop_event->seqnum > event->blocker_seqnum &&
|
||||
loop_event->seqnum < event->seqnum);
|
||||
|
||||
r = sd_device_get_subsystem(event->dev, &subsystem);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
is_block = streq(subsystem, "block");
|
||||
|
||||
r = sd_device_get_devpath(event->dev, &devpath);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
devpath_len = strlen(devpath);
|
||||
|
||||
r = sd_device_get_property_value(event->dev, "DEVPATH_OLD", &devpath_old);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
|
||||
r = sd_device_get_devnum(event->dev, &devnum);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
|
||||
r = sd_device_get_ifindex(event->dev, &ifindex);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
devpath_len = strlen(event->devpath);
|
||||
|
||||
/* check if queue contains events we depend on */
|
||||
LIST_FOREACH(event, e, loop_event) {
|
||||
size_t loop_devpath_len, common;
|
||||
const char *loop_devpath;
|
||||
|
||||
loop_event = e;
|
||||
|
||||
|
@ -938,42 +915,20 @@ static int event_is_blocked(Event *event) {
|
|||
if (loop_event->seqnum >= event->seqnum)
|
||||
goto no_blocker;
|
||||
|
||||
/* check major/minor */
|
||||
if (major(devnum) != 0) {
|
||||
const char *s;
|
||||
dev_t d;
|
||||
|
||||
if (sd_device_get_subsystem(loop_event->dev, &s) < 0)
|
||||
continue;
|
||||
|
||||
if (sd_device_get_devnum(loop_event->dev, &d) >= 0 &&
|
||||
devnum == d && is_block == streq(s, "block"))
|
||||
break;
|
||||
}
|
||||
|
||||
/* check network device ifindex */
|
||||
if (ifindex > 0) {
|
||||
int i;
|
||||
|
||||
if (sd_device_get_ifindex(loop_event->dev, &i) >= 0 &&
|
||||
ifindex == i)
|
||||
break;
|
||||
}
|
||||
|
||||
if (sd_device_get_devpath(loop_event->dev, &loop_devpath) < 0)
|
||||
continue;
|
||||
|
||||
/* check our old name */
|
||||
if (devpath_old && streq(devpath_old, loop_devpath))
|
||||
if (streq_ptr(loop_event->id, event->id))
|
||||
break;
|
||||
|
||||
loop_devpath_len = strlen(loop_devpath);
|
||||
/* check our old name */
|
||||
if (event->devpath_old && streq(event->devpath_old, loop_event->devpath))
|
||||
break;
|
||||
|
||||
loop_devpath_len = strlen(loop_event->devpath);
|
||||
|
||||
/* compare devpath */
|
||||
common = MIN(devpath_len, loop_devpath_len);
|
||||
|
||||
/* one devpath is contained in the other? */
|
||||
if (!strneq(devpath, loop_devpath, common))
|
||||
if (!strneq(event->devpath, loop_event->devpath, common))
|
||||
continue;
|
||||
|
||||
/* identical device event found */
|
||||
|
@ -981,11 +936,11 @@ static int event_is_blocked(Event *event) {
|
|||
break;
|
||||
|
||||
/* parent device event found */
|
||||
if (devpath[common] == '/')
|
||||
if (event->devpath[common] == '/')
|
||||
break;
|
||||
|
||||
/* child device event found */
|
||||
if (loop_devpath[common] == '/')
|
||||
if (loop_event->devpath[common] == '/')
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1134,6 +1089,7 @@ static int event_queue_assume_block_device_unlocked(Manager *manager, sd_device
|
|||
}
|
||||
|
||||
static int event_queue_insert(Manager *manager, sd_device *dev) {
|
||||
const char *devpath, *devpath_old = NULL, *id = NULL;
|
||||
sd_device_action_t action;
|
||||
uint64_t seqnum;
|
||||
Event *event;
|
||||
|
@ -1154,6 +1110,18 @@ static int event_queue_insert(Manager *manager, sd_device *dev) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_device_get_devpath(dev, &devpath);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_device_get_property_value(dev, "DEVPATH_OLD", &devpath_old);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
|
||||
r = device_get_device_id(dev, &id);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
|
||||
event = new(Event, 1);
|
||||
if (!event)
|
||||
return -ENOMEM;
|
||||
|
@ -1163,6 +1131,9 @@ static int event_queue_insert(Manager *manager, sd_device *dev) {
|
|||
.dev = sd_device_ref(dev),
|
||||
.seqnum = seqnum,
|
||||
.action = action,
|
||||
.id = id,
|
||||
.devpath = devpath,
|
||||
.devpath_old = devpath_old,
|
||||
.state = EVENT_QUEUED,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue