summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremy Kerr <jk@ozlabs.org>2014-03-07 13:46:49 +0800
committerJeremy Kerr <jk@ozlabs.org>2014-03-07 14:40:31 +0800
commit34c5230774ee2797b9f80b7f483e009cbb9f25f5 (patch)
treef73199bec9ba2716cfbaf8fc3ad25a5dc74e2468
parentdedff99aae78a8af387e39fb0c5d3518689ee328 (diff)
downloadtalos-petitboot-34c5230774ee2797b9f80b7f483e009cbb9f25f5.tar.gz
talos-petitboot-34c5230774ee2797b9f80b7f483e009cbb9f25f5.zip
discover/udev: Register udev monitor before enumerating devices
Currently, we enumerate udev devices before setting up our monitor. This means that we may lose devices that udev discovers after we start the enumeration, but before the monitor is registered. This change enables the monitor before enumeration, so we don't lose devices. We add a filter to the enumeration code to only parse completely initialised devices. This means we may need to handle change events as the main source of device notifications. We keep the existing CDROM event handler, but check for new devices and handle those as an add. Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
-rw-r--r--discover/udev.c67
1 files changed, 47 insertions, 20 deletions
diff --git a/discover/udev.c b/discover/udev.c
index e3495e9..0b2ec2f 100644
--- a/discover/udev.c
+++ b/discover/udev.c
@@ -183,18 +183,16 @@ static int udev_handle_dev_remove(struct pb_udev *udev, struct udev_device *dev)
return 0;
}
-static int udev_handle_dev_change(struct pb_udev *udev, struct udev_device *dev)
+/* returns true if further event processing should stop (eg., we've
+ * ejected the cdrom)
+ */
+static bool udev_handle_cdrom_events(struct pb_udev *udev,
+ struct udev_device *dev, struct discover_device *ddev)
{
- struct discover_device *ddev;
- const char *name, *node;
+ const char *node;
- name = udev_device_get_sysname(dev);
node = udev_device_get_devnode(dev);
- /* we're only interested in CDROM change events at present */
- if (!udev_device_get_property_value(dev, "ID_CDROM"))
- return 0;
-
/* handle CDROM eject requests */
if (udev_device_get_property_value(dev, "DISK_EJECT_REQUEST")) {
bool eject = false;
@@ -204,26 +202,51 @@ static int udev_handle_dev_change(struct pb_udev *udev, struct udev_device *dev)
/* If the device is mounted, cdrom_id's own eject request may
* have failed. So, we'll need to do our own here.
*/
- ddev = device_lookup_by_id(udev->handler, name);
if (ddev) {
eject = ddev->mounted;
udev_handle_dev_remove(udev, dev);
+ return false;
}
if (eject)
cdrom_eject(node);
- return 0;
+ return true;
}
if (udev_device_get_property_value(dev, "DISK_MEDIA_CHANGE")) {
if (cdrom_media_present(node))
- return udev_handle_dev_add(udev, dev);
+ udev_handle_dev_add(udev, dev);
else
- return udev_handle_dev_remove(udev, dev);
+ udev_handle_dev_remove(udev, dev);
+ return true;
}
- return 0;
+ return false;
+}
+
+static int udev_handle_dev_change(struct pb_udev *udev, struct udev_device *dev)
+{
+ struct discover_device *ddev;
+ const char *name;
+ int rc = 0;
+
+ name = udev_device_get_sysname(dev);
+
+ ddev = device_lookup_by_id(udev->handler, name);
+
+ /* if this is a CDROM device, process eject & media change requests;
+ * these may stop further processing */
+ if (!udev_device_get_property_value(dev, "ID_CDROM")) {
+ if (udev_handle_cdrom_events(udev, dev, ddev))
+ return 0;
+ }
+
+ /* if this is a new device, treat it as an add */
+ if (!ddev)
+ rc = udev_handle_dev_add(udev, dev);
+
+ return rc;
}
static int udev_handle_dev_action(struct udev_device *dev, const char *action)
@@ -273,12 +296,17 @@ static int udev_enumerate(struct udev *udev)
}
result = udev_enumerate_add_match_subsystem(enumerate, "block");
-
if (result) {
pb_log("udev_enumerate_add_match_subsystem failed\n");
goto fail;
}
+ result = udev_enumerate_add_match_is_initialized(enumerate);
+ if (result) {
+ pb_log("udev_enumerate_add_match_is_initialised failed\n");
+ goto fail;
+ }
+
udev_enumerate_scan_devices(enumerate);
list = udev_enumerate_get_list_entry(enumerate);
@@ -407,16 +435,14 @@ struct pb_udev *udev_init(struct waitset *waitset,
udev_set_log_fn(udev->udev, udev_log_fn);
- result = udev_enumerate(udev->udev);
-
- if (result)
- goto fail_enumerate;
-
result = udev_setup_monitor(udev->udev, &udev->monitor);
-
if (result)
goto fail_monitor;
+ result = udev_enumerate(udev->udev);
+ if (result)
+ goto fail_enumerate;
+
waiter_register_io(waitset, udev_monitor_get_fd(udev->monitor), WAIT_IN,
udev_process, udev->monitor);
@@ -425,6 +451,7 @@ struct pb_udev *udev_init(struct waitset *waitset,
return udev;
fail_monitor:
+ udev_monitor_unref(udev->monitor);
fail_enumerate:
udev_unref(udev->udev);
fail_new:
OpenPOWER on IntegriCloud