hal: Branch 'master'
David Zeuthen
david at kemper.freedesktop.org
Sun May 6 18:21:08 PDT 2007
NEWS | 2
doc/spec/hal-spec-properties.xml | 115 +++++++++
hald/linux/blockdev.c | 487 ++++++++++++++++++++++++++++++++++++++-
hald/linux/blockdev.h | 2
hald/linux/coldplug.c | 10
hald/linux/hotplug.c | 5
hald/linux/osspec.c | 46 +++
hald/linux/osspec_linux.h | 2
8 files changed, 650 insertions(+), 19 deletions(-)
New commits:
diff-tree c53f3e46e53204bb1d1910b7fbbd81edaf61c29b (from a5861634bc0961d379c16fdafb4e1268ecbbd37b)
Author: David Zeuthen <davidz at redhat.com>
Date: Sun May 6 21:14:08 2007 -0400
recognize Linux MD aka Software RAID devices
Since pictures says more than a thousand words...
http://people.freedesktop.org/~david/hal-md-normal.png
http://people.freedesktop.org/~david/hal-md-degraded.png
http://people.freedesktop.org/~david/hal-md-recover.png
This patch only adds detection by exploiting the fact that in Linux
2.6.19 and later /proc/mdstat is pollable. Later on we'll add D-Bus
interfaces to add methods for assembly, teardown of RAID arrays as
well as adding hot spares.
I wonder if it's worth abstracting Software RAID so FreeBSD and
Solaris can implement this too? It's probably too
different.. Thoughts?
diff --git a/NEWS b/NEWS
index 8815c36..801708d 100644
--- a/NEWS
+++ b/NEWS
@@ -4,7 +4,7 @@ HAL 0.5.10 ""
Requirements for HAL 0.5.10 "":
- - Linux kernel >= 2.6.17
+ - Linux kernel >= 2.6.19
- util-linux >= 2.12r1 (--enable-umount-helper requires patch from RH #188193)
- bash >= 2.0
- udev >= 089
diff --git a/doc/spec/hal-spec-properties.xml b/doc/spec/hal-spec-properties.xml
index e527e43..64176c1 100644
--- a/doc/spec/hal-spec-properties.xml
+++ b/doc/spec/hal-spec-properties.xml
@@ -3624,6 +3624,12 @@ org.freedesktop.Hal.Device.Volume.method
</row>
<row>
<entry></entry>
+ <entry>linux_raid</entry>
+ <entry></entry>
+ <entry>Linux MD (multi disk) RAID device</entry>
+ </row>
+ <row>
+ <entry></entry>
<entry></entry>
<entry></entry>
<entry></entry>
@@ -4107,6 +4113,115 @@ org.freedesktop.Hal.Device.Volume.method
</tgroup>
</informaltable>
</sect2>
+ <sect2 id="device-properties-storage-linux-raid">
+ <title>
+ storage.linux_raid namespace
+ </title>
+ <para>
+ This namespace is used to describe logical Software RAID
+ devices under Linux using the <literal>md</literal> driver. By
+ and large, all the same properties under
+ the <literal>storage</literal> name space applies except
+ that <literal>storage.serial</literal> is set to the UUID of
+ the RAID set, <literal>storage.firmware_version</literal> is
+ set to the version of the <literal>md</literal> driver and the
+ value of <literal>storage.hotpluggable</literal> is taken from
+ the enclosing drive of the first RAID component
+ encountered. In addition, the following properties are
+ available.
+ </para>
+ <informaltable>
+ <tgroup cols="2">
+ <thead>
+ <row>
+ <entry>Key (type)</entry>
+ <entry>Values</entry>
+ <entry>Mandatory</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>storage.linux_raid.level</literal> (string)
+ </entry>
+ <entry></entry>
+ <entry>Yes</entry>
+ <entry>the RAID level of the device as reported by the kernel (linear, raid0, raid1, raid4, raid5, raid6, raid10)</entry>
+ </row>
+ <row>
+ <entry>
+ <literal>storage.linux_raid.sysfs_path</literal> (string)
+ </entry>
+ <entry></entry>
+ <entry>Yes</entry>
+ <entry>sysfs path of device, e.g. /sys/block/md0</entry>
+ </row>
+ <row>
+ <entry>
+ <literal>storage.linux_raid.num_components</literal> (int)
+ </entry>
+ <entry></entry>
+ <entry>Yes</entry>
+ <entry>Number of components in the RAID array</entry>
+ </row>
+ <row>
+ <entry>
+ <literal>storage.linux_raid.num_components_active</literal> (int)
+ </entry>
+ <entry></entry>
+ <entry>Yes</entry>
+ <entry>
+ Number of active components in the RAID array. If less
+ than <literal>storage.linux_raid.num_components</literal>
+ it means that the RAID array is running in degraded
+ mode.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>storage.linux_raid.components</literal> (strlist)
+ </entry>
+ <entry></entry>
+ <entry>Yes</entry>
+ <entry>UDI's of the volumes constituting the array.</entry>
+ </row>
+ <row>
+ <entry>
+ <literal>storage.linux_raid.is_syncing</literal> (bool)
+ </entry>
+ <entry></entry>
+ <entry>Yes</entry>
+ <entry>TRUE if, and only if, the array is currently syncing</entry>
+ </row>
+ <row>
+ <entry>
+ <literal>storage.linux_raid.sync.action</literal> (string)
+ </entry>
+ <entry></entry>
+ <entry>only if <literal>.is_syncing</literal> is TRUE</entry>
+ <entry>The syncing mechanism as reported by the kernel (idle, resync, check, repair, recover)</entry>
+ </row>
+ <row>
+ <entry>
+ <literal>storage.linux_raid.sync.progress</literal> (double)
+ </entry>
+ <entry></entry>
+ <entry>only if <literal>.is_syncing</literal> is TRUE</entry>
+ <entry>Number between 0 and 1 representing progress of the sync operation. This is updated regulary when syncing is happening.</entry>
+ </row>
+ <row>
+ <entry>
+ <literal>storage.linux_raid.sync.speed</literal> (uint64)
+ </entry>
+ <entry></entry>
+ <entry>only if <literal>.is_syncing</literal> is TRUE</entry>
+ <entry>Speed of the sync operation, in kB/s. This is updated regulary when syncing is happening.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
+ </sect2>
<sect2 id="device-properties-net">
<title>
net namespace
diff --git a/hald/linux/blockdev.c b/hald/linux/blockdev.c
index f0c6eba..b9ad9f1 100644
--- a/hald/linux/blockdev.c
+++ b/hald/linux/blockdev.c
@@ -635,6 +635,198 @@ out:
return f;
}
+static gboolean
+refresh_md_state (HalDevice *d);
+
+static gboolean
+md_check_sync_timeout (gpointer user_data)
+{
+ HalDevice *d;
+ char *sysfs_path = (char *) user_data;
+
+ HAL_INFO (("In md_check_sync_timeout for sysfs path %s", sysfs_path));
+
+ d = hal_device_store_match_key_value_string (hald_get_gdl (),
+ "storage.linux_raid.sysfs_path",
+ sysfs_path);
+ if (d == NULL)
+ d = hal_device_store_match_key_value_string (hald_get_tdl (),
+ "storage.linux_raid.sysfs_path",
+ sysfs_path);
+ if (d == NULL) {
+ HAL_WARNING (("Cannot find md device with sysfs path '%s'", sysfs_path));
+ goto out;
+ }
+
+ refresh_md_state (d);
+
+out:
+ g_free (sysfs_path);
+ return FALSE;
+}
+
+static gboolean
+refresh_md_state (HalDevice *d)
+{
+ int n;
+ char *sync_action;
+ int num_components;
+ gboolean ret;
+ const char *sysfs_path;
+
+ ret = FALSE;
+
+ sysfs_path = hal_device_property_get_string (d, "storage.linux_raid.sysfs_path");
+ if (sysfs_path == NULL) {
+ HAL_WARNING (("Cannot get sysfs_path for udi %s", hal_device_get_udi (d)));
+ goto error;
+ }
+
+ HAL_INFO (("In refresh_md_state() for '%s'", sysfs_path));
+
+ sync_action = hal_util_get_string_from_file (sysfs_path, "md/sync_action");
+ if (sync_action == NULL) {
+ HAL_WARNING (("Cannot get sync_action for %s", sysfs_path));
+ goto error;
+ }
+ if (strcmp (sync_action, "idle") == 0) {
+ hal_device_property_set_bool (d, "storage.linux_raid.is_syncing", FALSE);
+ hal_device_property_remove (d, "storage.linux_raid.sync.action");
+ hal_device_property_remove (d, "storage.linux_raid.sync.speed");
+ hal_device_property_remove (d, "storage.linux_raid.sync.progress");
+ } else {
+ int speed;
+ char *str_completed;
+
+ hal_device_property_set_bool (d, "storage.linux_raid.is_syncing", TRUE);
+
+ hal_device_property_set_string (d, "storage.linux_raid.sync.action", sync_action);
+
+ if (!hal_util_get_int_from_file (sysfs_path, "md/sync_speed", &speed, 10)) {
+ HAL_WARNING (("Cannot get sync_speed for %s", sysfs_path));
+ } else {
+ hal_device_property_set_uint64 (d, "storage.linux_raid.sync.speed", speed);
+ }
+
+
+ if ((str_completed = hal_util_get_string_from_file (sysfs_path, "md/sync_completed")) == NULL) {
+ HAL_WARNING (("Cannot get sync_completed for %s", sysfs_path));
+ } else {
+ dbus_uint64_t sync_pos, sync_total;
+
+ if (sscanf (str_completed, "%ld / %ld", &sync_pos, &sync_total) != 2) {
+ HAL_WARNING (("Malformed sync_completed '%s'", str_completed));
+ } else {
+ double sync_progress;
+ sync_progress = ((double) sync_pos) / ((double) sync_total);
+ hal_device_property_set_double (d, "storage.linux_raid.sync.progress", sync_progress);
+ }
+ }
+
+ /* check again in two seconds */
+ g_timeout_add (2000, md_check_sync_timeout, g_strdup (sysfs_path));
+ }
+
+ if (!hal_util_get_int_from_file (sysfs_path, "md/raid_disks", &num_components, 0)) {
+ HAL_WARNING (("Cannot get number of RAID components"));
+ goto error;
+ }
+ hal_device_property_set_int (d, "storage.linux_raid.num_components", num_components);
+
+ /* add all components */
+ for (n = 0; n < num_components; n++) {
+ char *s;
+ char *link;
+ char *target;
+ HalDevice *slave_volume;
+ const char *slave_volume_stordev_udi;
+ HalDevice *slave_volume_stordev;
+
+ s = g_strdup_printf ("%s/md/rd%d", sysfs_path, n);
+ if (!g_file_test (s, G_FILE_TEST_IS_SYMLINK)) {
+ g_free (s);
+ break;
+ }
+ g_free (s);
+
+ link = g_strdup_printf ("%s/md/rd%d/block", sysfs_path, n);
+ target = resolve_symlink (link);
+ if (target == NULL) {
+ HAL_WARNING (("Cannot resolve %s", link));
+ g_free (link);
+ goto error;
+ }
+ HAL_INFO (("link->target: '%s' -> '%s'", link, target));
+
+ slave_volume = hal_device_store_match_key_value_string (hald_get_gdl (), "linux.sysfs_path", target);
+ if (slave_volume == NULL) {
+ HAL_WARNING (("No volume for sysfs path %s", target));
+ g_free (target);
+ g_free (link);
+ goto error;
+ }
+
+
+ slave_volume_stordev_udi = hal_device_property_get_string (slave_volume, "block.storage_device");
+ if (slave_volume_stordev_udi == NULL) {
+ HAL_WARNING (("No storage device for slave"));
+ g_free (target);
+ g_free (link);
+ goto error;
+ }
+ slave_volume_stordev = hal_device_store_find (hald_get_gdl (), slave_volume_stordev_udi);
+ if (slave_volume_stordev == NULL) {
+ HAL_WARNING (("No storage device for slave"));
+ g_free (target);
+ g_free (link);
+ goto error;
+ }
+
+
+ hal_device_property_strlist_add (d, "storage.linux_raid.components", hal_device_get_udi (slave_volume));
+
+ /* derive
+ *
+ * - hotpluggability (is that a word?)
+ * - array uuid
+ *
+ * Hmm.. every raid member (PV) get the array UUID. That's
+ * probably.. wrong. TODO: check with Kay.
+ *
+ * from component 0.
+ */
+ if (n == 0) {
+ const char *uuid;
+
+ hal_device_property_set_bool (
+ d, "storage.hotpluggable",
+ hal_device_property_get_bool (slave_volume_stordev, "storage.hotpluggable"));
+
+
+ uuid = hal_device_property_get_string (
+ slave_volume, "volume.uuid");
+ if (uuid != NULL) {
+ hal_device_property_set_string (
+ d, "storage.serial", uuid);
+ }
+ }
+
+ g_free (target);
+ g_free (link);
+
+ } /* for all components */
+
+ hal_device_property_set_int (d, "storage.linux_raid.num_components_active", n);
+
+ /* TODO: add more state here */
+
+ ret = TRUE;
+
+error:
+ return ret;
+}
+
+
void
hotplug_event_begin_add_blockdev (const gchar *sysfs_path, const gchar *device_file, gboolean is_partition,
HalDevice *parent, void *end_token)
@@ -647,8 +839,12 @@ hotplug_event_begin_add_blockdev (const
char *sysfs_path_real = NULL;
int floppy_num;
gboolean is_device_mapper;
+ gboolean is_md_device;
+ int md_number;
is_device_mapper = FALSE;
+ is_fakevolume = FALSE;
+ is_md_device = FALSE;
HAL_INFO (("block_add: sysfs_path=%s dev=%s is_part=%d, parent=0x%08x",
sysfs_path, device_file, is_partition, parent));
@@ -659,11 +855,18 @@ hotplug_event_begin_add_blockdev (const
}
if (strcmp (hal_util_get_last_element (sysfs_path), "fakevolume") == 0) {
+ HAL_INFO (("Handling %s as fakevolume - sysfs_path_real=%s", device_file, sysfs_path_real));
is_fakevolume = TRUE;
sysfs_path_real = hal_util_get_parent_path (sysfs_path);
- HAL_INFO (("Handling %s as fakevolume - sysfs_path_real=%s", device_file, sysfs_path_real));
+ } else if (sscanf (hal_util_get_last_element (sysfs_path), "md%d", &md_number) == 1) {
+ HAL_INFO (("Handling %s as MD device", device_file));
+ is_md_device = TRUE;
+ sysfs_path_real = g_strdup (sysfs_path);
+ /* set parent to root computer device object */
+ parent = hal_device_store_find (hald_get_gdl (), "/org/freedesktop/Hal/devices/computer");
+ if (parent == NULL)
+ d = hal_device_store_find (hald_get_tdl (), "/org/freedesktop/Hal/devices/computer");
} else {
- is_fakevolume = FALSE;
sysfs_path_real = g_strdup (sysfs_path);
}
@@ -679,13 +882,13 @@ hotplug_event_begin_add_blockdev (const
d = hal_device_new ();
/* OK, no parent... it might a device-mapper device => check slaves/ subdir in sysfs */
- if (parent == NULL && !is_partition && !is_fakevolume) {
+ if (parent == NULL && !is_partition && !is_fakevolume && !hotplug_event->reposted) {
DIR * dir;
struct dirent *dp;
char path[HAL_PATH_MAX];
g_snprintf (path, HAL_PATH_MAX, "%s/slaves", sysfs_path);
- HAL_INFO (("Looking in %s", path));
+ HAL_INFO (("Looking in %s for Device Mapper", path));
if ((dir = opendir (path)) == NULL) {
HAL_WARNING (("Unable to open %s: %s", path, strerror(errno)));
@@ -734,7 +937,7 @@ hotplug_event_begin_add_blockdev (const
closedir(dir);
HAL_INFO (("Done looking in %s", path));
}
-
+
}
if (parent == NULL) {
@@ -865,6 +1068,53 @@ hotplug_event_begin_add_blockdev (const
}
}
+ if (strcmp (udi_it, "/org/freedesktop/Hal/devices/computer") == 0) {
+ physdev = d_it;
+ physdev_udi = udi_it;
+ if (is_md_device) {
+ char *level;
+ char *model_name;
+
+ hal_device_property_set_string (d, "storage.bus", "linux_raid");
+
+ level = hal_util_get_string_from_file (sysfs_path_real, "md/level");
+ if (level == NULL)
+ goto error;
+ hal_device_property_set_string (d, "storage.linux_raid.level", level);
+
+ hal_device_property_set_string (d, "storage.linux_raid.sysfs_path", sysfs_path_real);
+
+ hal_device_property_set_string (d, "storage.vendor", "Linux");
+ if (strcmp (level, "linear") == 0) {
+ model_name = g_strdup ("Software RAID (Linear)");
+ } else if (strcmp (level, "raid0") == 0) {
+ model_name = g_strdup ("Software RAID-0 (Stripe)");
+ } else if (strcmp (level, "raid1") == 0) {
+ model_name = g_strdup ("Software RAID-1 (Mirror)");
+ } else if (strcmp (level, "raid5") == 0) {
+ model_name = g_strdup ("Software RAID-5");
+ } else {
+ model_name = g_strdup_printf ("Software RAID (%s)", level);
+ }
+ hal_device_property_set_string (d, "storage.model", model_name);
+ g_free (model_name);
+
+ hal_util_set_string_from_file (
+ d, "storage.firmware_version",
+ sysfs_path_real, "md/metadata_version");
+
+ hal_device_add_capability (d, "storage.linux_raid");
+
+ if (!refresh_md_state (d))
+ goto error;
+
+ is_hotpluggable = hal_device_property_get_bool (
+ d, "storage.hotpluggable");
+
+ }
+ break;
+ }
+
/* Check info.subsystem */
if ((bus = hal_device_property_get_string (d_it, "info.subsystem")) != NULL) {
if (strcmp (bus, "scsi") == 0) {
@@ -927,9 +1177,9 @@ hotplug_event_begin_add_blockdev (const
hal_device_property_set_string (d, "storage.originating_device", physdev_udi);
hal_device_property_set_string (d, "storage.physical_device", physdev_udi);
- if (!hal_util_get_int_from_file (sysfs_path, "removable", (gint *) &is_removable, 10)) {
+ if (!hal_util_get_int_from_file (sysfs_path_real, "removable", (gint *) &is_removable, 10)) {
HAL_WARNING (("Cannot get 'removable' file"));
- goto error;
+ is_removable = FALSE;
}
hal_device_property_set_bool (d, "storage.removable.media_available", FALSE);
@@ -937,7 +1187,7 @@ hotplug_event_begin_add_blockdev (const
/* set storage.size only if we have fixed media */
if (!is_removable) {
guint64 num_blocks;
- if (hal_util_get_uint64_from_file (sysfs_path, "size", &num_blocks, 0)) {
+ if (hal_util_get_uint64_from_file (sysfs_path_real, "size", &num_blocks, 0)) {
/* TODO: sane to assume this is always 512 for non-removable?
* I think genhd.c guarantees this... */
hal_device_property_set_uint64 (d, "storage.size", num_blocks * 512);
@@ -972,7 +1222,7 @@ hotplug_event_begin_add_blockdev (const
*
* "disk", "cdrom", "tape", "floppy", "UNKNOWN"
*/
- snprintf (buf, sizeof (buf), "%s/ide/%s", get_hal_proc_path (), hal_util_get_last_element (sysfs_path));
+ snprintf (buf, sizeof (buf), "%s/ide/%s", get_hal_proc_path (), hal_util_get_last_element (sysfs_path_real));
if ((media = hal_util_get_string_from_file (buf, "media")) != NULL) {
if (strcmp (media, "disk") == 0 ||
strcmp (media, "cdrom") == 0 ||
@@ -1161,10 +1411,12 @@ error:
if (d != NULL)
g_object_unref (d);
out:
- hotplug_event_end (end_token);
+ hotplug_event_end (end_token);
g_free (sysfs_path_real);
+ return;
}
+
static void
force_unmount_cb (HalDevice *d, guint32 exit_type,
gint return_code, gchar **error,
@@ -1412,3 +1664,218 @@ blockdev_generate_remove_hotplug_event (
return hotplug_event;
}
+
+static GSList *md_devs = NULL;
+
+static char *
+udev_get_device_file_for_sysfs_path (const char *sysfs_path)
+{
+ char *ret;
+ char *u_stdout;
+ int u_exit_status;
+ const char *argv[] = {"/usr/bin/udevinfo", "--root", "--query", "name", "--path", NULL, NULL};
+ GError *g_error;
+
+ ret = NULL;
+ argv[5] = sysfs_path;
+
+ g_error = NULL;
+
+ if (!g_spawn_sync("/",
+ (char **) argv,
+ NULL, /* envp */
+ 0, /* flags */
+ NULL, /* child_setup */
+ NULL, /* user_data */
+ &u_stdout,
+ NULL, /* stderr */
+ &u_exit_status,
+ &g_error)) {
+ HAL_ERROR (("Error spawning udevinfo: %s", g_error->message));
+ g_error_free (g_error);
+ goto out;
+ }
+
+ if (u_exit_status != 0) {
+ HAL_ERROR (("udevinfo returned exit code %d", u_exit_status));
+ g_free (u_stdout);
+ goto out;
+ }
+
+ ret = u_stdout;
+ g_strchomp (ret);
+ HAL_INFO (("Got '%s'", ret));
+
+out:
+ return ret;
+}
+
+
+void
+blockdev_process_mdstat (void)
+{
+ HotplugEvent *hotplug_event;
+ GIOChannel *channel;
+ GSList *read_md_devs;
+ GSList *i;
+ GSList *j;
+ GSList *k;
+
+ channel = get_mdstat_channel ();
+ if (channel == NULL)
+ goto error;
+
+ if (g_io_channel_seek (channel, 0, G_SEEK_SET) != G_IO_ERROR_NONE) {
+ HAL_ERROR (("Cannot seek in /proc/mdstat"));
+ goto error;
+ }
+
+ read_md_devs = NULL;
+ while (TRUE) {
+ int num;
+ char *line;
+
+ if (g_io_channel_read_line (channel, &line, NULL, NULL, NULL) != G_IO_STATUS_NORMAL)
+ break;
+
+ if (sscanf (line, "md%d : ", &num) == 1) {
+ char *sysfs_path;
+ sysfs_path = g_strdup_printf ("%s/block/md%d", get_hal_sysfs_path (), num);
+ read_md_devs = g_slist_prepend (read_md_devs, sysfs_path);
+ }
+
+ g_free (line);
+ }
+
+ /* now compute the delta */
+
+ /* add devices */
+ for (i = read_md_devs; i != NULL; i = i->next) {
+ gboolean should_add = TRUE;
+
+ for (j = md_devs; j != NULL && should_add; j = j->next) {
+ if (strcmp (i->data, j->data) == 0) {
+ should_add = FALSE;
+ }
+ }
+
+ if (should_add) {
+ char *sysfs_path = i->data;
+ char *device_file;
+ int num_tries;
+
+ num_tries = 0;
+ retry_add:
+ device_file = udev_get_device_file_for_sysfs_path (sysfs_path);
+ if (device_file == NULL) {
+ if (num_tries <= 6) {
+ int num_ms;
+ num_ms = 10 * (1<<num_tries);
+ HAL_INFO (("spinning %d ms waiting for device file for sysfs path %s",
+ num_ms, sysfs_path));
+ usleep (1000 * num_ms);
+ num_tries++;
+ goto retry_add;
+ } else {
+ HAL_ERROR (("Cannot get device file for sysfs path %s", sysfs_path));
+ }
+ } else {
+ HAL_INFO (("Adding md device at '%s' ('%s')", sysfs_path, device_file));
+
+ hotplug_event = g_new0 (HotplugEvent, 1);
+ hotplug_event->action = HOTPLUG_ACTION_ADD;
+ hotplug_event->type = HOTPLUG_EVENT_SYSFS_BLOCK;
+ g_strlcpy (hotplug_event->sysfs.subsystem, "block", sizeof (hotplug_event->sysfs.subsystem));
+ g_strlcpy (hotplug_event->sysfs.sysfs_path, sysfs_path, sizeof (hotplug_event->sysfs.sysfs_path));
+ g_strlcpy (hotplug_event->sysfs.device_file, device_file, sizeof (hotplug_event->sysfs.device_file));
+ hotplug_event->sysfs.net_ifindex = -1;
+ hotplug_event_enqueue (hotplug_event);
+
+ md_devs = g_slist_prepend (md_devs, g_strdup (sysfs_path));
+
+ g_free (device_file);
+ }
+
+ }
+ }
+
+ /* remove devices */
+ for (i = md_devs; i != NULL; i = k) {
+ gboolean should_remove = TRUE;
+
+ k = i->next;
+
+ for (j = read_md_devs; j != NULL && should_remove; j = j->next) {
+ if (strcmp (i->data, j->data) == 0) {
+ should_remove = FALSE;
+ }
+ }
+
+ if (should_remove) {
+ char *sysfs_path = i->data;
+ char *device_file;
+ int num_tries;
+
+ num_tries = 0;
+ retry_rem:
+ device_file = udev_get_device_file_for_sysfs_path (sysfs_path);
+ if (device_file == NULL) {
+ if (num_tries <= 6) {
+ int num_ms;
+ num_ms = 10 * (1<<num_tries);
+ HAL_INFO (("spinning %d ms waiting for device file for sysfs path %s",
+ num_ms, sysfs_path));
+ usleep (1000 * num_ms);
+ num_tries++;
+ goto retry_rem;
+ } else {
+ HAL_ERROR (("Cannot get device file for sysfs path %s", sysfs_path));
+ }
+ } else {
+
+ HAL_INFO (("Removing md device at '%s' ('%s')", sysfs_path, device_file));
+
+ hotplug_event = g_new0 (HotplugEvent, 1);
+ hotplug_event->action = HOTPLUG_ACTION_REMOVE;
+ hotplug_event->type = HOTPLUG_EVENT_SYSFS_BLOCK;
+ g_strlcpy (hotplug_event->sysfs.subsystem, "block", sizeof (hotplug_event->sysfs.subsystem));
+ g_strlcpy (hotplug_event->sysfs.sysfs_path, sysfs_path, sizeof (hotplug_event->sysfs.sysfs_path));
+ g_strlcpy (hotplug_event->sysfs.device_file, device_file, sizeof (hotplug_event->sysfs.device_file));
+ hotplug_event->sysfs.net_ifindex = -1;
+ hotplug_event_enqueue (hotplug_event);
+
+ md_devs = g_slist_remove_link (md_devs, i);
+ g_free (i->data);
+ g_slist_free (i);
+
+ g_free (device_file);
+ }
+
+ }
+ }
+
+ g_slist_foreach (read_md_devs, (GFunc) g_free, NULL);
+ g_slist_free (read_md_devs);
+
+ /* finally, refresh all md devices */
+ for (i = md_devs; i != NULL; i = i->next) {
+ char *sysfs_path = i->data;
+ HalDevice *d;
+
+ d = hal_device_store_match_key_value_string (hald_get_gdl (),
+ "storage.linux_raid.sysfs_path",
+ sysfs_path);
+ if (d == NULL)
+ d = hal_device_store_match_key_value_string (hald_get_tdl (),
+ "storage.linux_raid.sysfs_path",
+ sysfs_path);
+ if (d != NULL)
+ refresh_md_state (d);
+ }
+
+
+ hotplug_event_process_queue ();
+
+error:
+ ;
+}
diff --git a/hald/linux/blockdev.h b/hald/linux/blockdev.h
index 9095d8c..0d28298 100644
--- a/hald/linux/blockdev.h
+++ b/hald/linux/blockdev.h
@@ -40,4 +40,6 @@ HotplugEvent *blockdev_generate_remove_h
void blockdev_refresh_mount_state (HalDevice *d);
+void blockdev_process_mdstat (void);
+
#endif /* BLOCKDEV_H */
diff --git a/hald/linux/coldplug.c b/hald/linux/coldplug.c
index d5771b6..934d4a4 100644
--- a/hald/linux/coldplug.c
+++ b/hald/linux/coldplug.c
@@ -42,6 +42,7 @@
#include "osspec_linux.h"
#include "hotplug.h"
#include "coldplug.h"
+#include "blockdev.h"
#define DMPREFIX "dm-"
@@ -428,6 +429,12 @@ static void scan_block(void)
if (dent->d_name[0] == '.')
continue;
+ /* md devices are handled via looking at /proc/mdstat */
+ if (g_str_has_prefix (dent->d_name, "md")) {
+ HAL_INFO (("skipping md event for %s", dent->d_name));
+ continue;
+ }
+
g_strlcpy(dirname, base, sizeof(dirname));
g_strlcat(dirname, "/", sizeof(dirname));
g_strlcat(dirname, dent->d_name, sizeof(dirname));
@@ -574,6 +581,9 @@ coldplug_synthesize_events (void)
device_list = g_slist_sort (device_list, _device_order);
queue_events ();
}
+
+ /* add events from reading /proc/mdstat */
+ blockdev_process_mdstat ();
}
g_hash_table_destroy (sysfs_to_udev_map);
diff --git a/hald/linux/hotplug.c b/hald/linux/hotplug.c
index 96c8540..e836fd9 100644
--- a/hald/linux/hotplug.c
+++ b/hald/linux/hotplug.c
@@ -184,10 +184,11 @@ hotplug_event_begin_sysfs (HotplugEvent
* from within HAL for partitions on the main block device
*/
if ((strstr (hotplug_event->sysfs.sysfs_path, "/fakevolume") != NULL) ||
- hal_util_get_int_from_file (hotplug_event->sysfs.sysfs_path, "range", &range, 0))
+ hal_util_get_int_from_file (hotplug_event->sysfs.sysfs_path, "range", &range, 0)) {
is_partition = FALSE;
- else
+ } else {
is_partition = TRUE;
+ }
hal_util_find_known_parent (hotplug_event->sysfs.sysfs_path, &parent, NULL);
hotplug_event_begin_add_blockdev (hotplug_event->sysfs.sysfs_path,
diff --git a/hald/linux/osspec.c b/hald/linux/osspec.c
index 67e1be9..afecfeb 100644
--- a/hald/linux/osspec.c
+++ b/hald/linux/osspec.c
@@ -149,10 +149,17 @@ hald_udev_data (GIOChannel *source, GIOC
if (strncmp(key, "ACTION=", 7) == 0)
action = &key[7];
- else if (strncmp(key, "DEVPATH=", 8) == 0)
+ else if (strncmp(key, "DEVPATH=", 8) == 0) {
+
+ /* md devices are handled via looking at /proc/mdstat */
+ if (g_str_has_prefix (key + 8, "/block/md")) {
+ HAL_INFO (("skipping md event for %s", key + 8));
+ goto invalid;
+ }
+
g_snprintf (hotplug_event->sysfs.sysfs_path, sizeof (hotplug_event->sysfs.sysfs_path),
"%s%s", hal_sysfs_path, &key[8]);
- else if (strncmp(key, "SUBSYSTEM=", 10) == 0)
+ } else if (strncmp(key, "SUBSYSTEM=", 10) == 0)
g_strlcpy (hotplug_event->sysfs.subsystem, &key[10], sizeof (hotplug_event->sysfs.subsystem));
else if (strncmp(key, "DEVNAME=", 8) == 0)
g_strlcpy (hotplug_event->sysfs.device_file, &key[8], sizeof (hotplug_event->sysfs.device_file));
@@ -247,8 +254,7 @@ out:
}
static gboolean
-mount_tree_changed_event (GIOChannel *channel, GIOCondition cond,
- gpointer user_data)
+mount_tree_changed_event (GIOChannel *channel, GIOCondition cond, gpointer user_data)
{
if (cond & ~G_IO_ERR)
return TRUE;
@@ -259,6 +265,19 @@ mount_tree_changed_event (GIOChannel *ch
return TRUE;
}
+static gboolean
+mdstat_changed_event (GIOChannel *channel, GIOCondition cond, gpointer user_data)
+{
+ if (cond & ~G_IO_PRI)
+ return TRUE;
+
+ HAL_INFO (("/proc/mdstat changed"));
+
+ blockdev_process_mdstat ();
+
+ return TRUE;
+}
+
static HalFileMonitor *file_monitor = NULL;
HalFileMonitor *
@@ -267,6 +286,14 @@ osspec_get_file_monitor (void)
return file_monitor;
}
+static GIOChannel *mdstat_channel = NULL;
+
+GIOChannel *get_mdstat_channel (void)
+{
+ return mdstat_channel;
+}
+
+
void
osspec_privileged_init (void)
{
@@ -274,6 +301,14 @@ osspec_privileged_init (void)
if (file_monitor == NULL) {
DIE (("Cannot initialize file monitor"));
}
+
+ /* watch /proc/mdstat for md changes
+ * kernel 2.6.19 throws a POLLPRI event for every change
+ */
+ mdstat_channel = g_io_channel_new_file ("/proc/mdstat", "r", NULL);
+ if (mdstat_channel == NULL)
+ DIE (("Unable to read /proc/mdstat"));
+ g_io_add_watch (mdstat_channel, G_IO_PRI, mdstat_changed_event, NULL);
}
void
@@ -323,8 +358,7 @@ osspec_init (void)
if (hal_proc_path == NULL)
hal_proc_path = "/proc";
- /*
- * watch /proc/mounts for mount tree changes
+ /* watch /proc/mounts for mount tree changes
* kernel 2.6.15 vfs throws a POLLERR event for every change
*/
g_snprintf (path, sizeof (path), "%s/mounts", get_hal_proc_path ());
diff --git a/hald/linux/osspec_linux.h b/hald/linux/osspec_linux.h
index 8ecda30..41851c5 100644
--- a/hald/linux/osspec_linux.h
+++ b/hald/linux/osspec_linux.h
@@ -39,5 +39,7 @@ gboolean hal_util_set_driver (HalDevice
gboolean hal_util_find_known_parent (const gchar *sysfs_path, HalDevice **parent, gchar **parent_path);
+GIOChannel *get_mdstat_channel (void);
+
#endif /* OSSPEC_LINUX_H */
More information about the hal-commit
mailing list