Fix a daemon crash when removing children

If the device has a child with a longer remove_delay we actually crash because
the FuDeviceList tries to remove the child device twice. Just remove all the
children when the parent remove delay elapsed rather than set up each device
with a unique timeout.
This commit is contained in:
Richard Hughes 2020-03-10 16:08:34 +00:00
parent c3afed36d5
commit 1e571730d0

View File

@ -318,10 +318,28 @@ fu_device_list_device_delayed_remove_cb (gpointer user_data)
{
FuDeviceItem *item = (FuDeviceItem *) user_data;
FuDeviceList *self = FU_DEVICE_LIST (item->self);
GPtrArray *children;
/* no longer valid */
item->remove_id = 0;
/* remove any children associated with device */
children = fu_device_get_children (item->device);
for (guint j = 0; j < children->len; j++) {
FuDevice *child = g_ptr_array_index (children, j);
FuDeviceItem *child_item = fu_device_list_find_by_id (self,
fu_device_get_id (child),
NULL);
if (child_item == NULL) {
g_debug ("device %s not found", fu_device_get_id (child));
continue;
}
fu_device_list_emit_device_removed (self, child);
g_rw_lock_writer_lock (&self->devices_mutex);
g_ptr_array_remove (self->devices, child_item);
g_rw_lock_writer_unlock (&self->devices_mutex);
}
/* just remove now */
g_debug ("doing delayed removal");
fu_device_list_emit_device_removed (self, item->device);
@ -385,6 +403,12 @@ fu_device_list_remove (FuDeviceList *self, FuDevice *device)
item->remove_id = 0;
}
/* delay the removal and check for replug */
if (fu_device_get_remove_delay (item->device) > 0) {
fu_device_list_remove_with_delay (item);
return;
}
/* remove any children associated with device */
children = fu_device_get_children (device);
for (guint j = 0; j < children->len; j++) {
@ -396,22 +420,12 @@ fu_device_list_remove (FuDeviceList *self, FuDevice *device)
g_debug ("device %s not found", fu_device_get_id (child));
continue;
}
if (fu_device_get_remove_delay (child_item->device) > 0) {
fu_device_list_remove_with_delay (child_item);
continue;
}
fu_device_list_emit_device_removed (self, child);
g_rw_lock_writer_lock (&self->devices_mutex);
g_ptr_array_remove (self->devices, child_item);
g_rw_lock_writer_unlock (&self->devices_mutex);
}
/* delay the removal and check for replug */
if (fu_device_get_remove_delay (item->device) > 0) {
fu_device_list_remove_with_delay (item);
return;
}
/* remove right now */
fu_device_list_emit_device_removed (self, item->device);
g_rw_lock_writer_lock (&self->devices_mutex);