GDBusObjectManagerServer *object_manager)
{
UDisksBlock *iface = UDISKS_BLOCK (block);
- const gchar *md_uuid;
+ const gchar *uuid;
const gchar *objpath_mdraid = "/";
const gchar *objpath_mdraid_member = "/";
UDisksLinuxMDRaidObject *object = NULL;
- md_uuid = g_udev_device_get_property (device, "MD_UUID");
- if (md_uuid == NULL || strlen (md_uuid) == 0)
- goto out;
-
- object = find_mdraid (object_manager, md_uuid);
- if (object == NULL)
- goto out;
+ uuid = g_udev_device_get_property (device, "MD_UUID");
+ if (uuid != NULL && strlen (uuid) > 0)
+ {
+ object = find_mdraid (object_manager, uuid);
+ if (object != NULL)
+ {
+ objpath_mdraid = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
+ g_clear_object (&object);
+ }
+ }
- /* TODO: find a better way to distinguish member vs array ? */
- if (g_str_has_prefix (g_udev_device_get_device_file (device), "/dev/md"))
- objpath_mdraid = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
- else
- objpath_mdraid_member = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
+ uuid = g_udev_device_get_property (device, "MD_MEMBER_UUID");
+ if (uuid != NULL && strlen (uuid) > 0)
+ {
+ object = find_mdraid (object_manager, uuid);
+ if (object != NULL)
+ {
+ objpath_mdraid_member = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
+ g_clear_object (&object);
+ }
+ }
- out:
udisks_block_set_mdraid (iface, objpath_mdraid);
udisks_block_set_mdraid_member (iface, objpath_mdraid_member);
- g_clear_object (&object);
}
/* ---------------------------------------------------------------------------------------------------- */
{
UDisksLinuxMDRaid *mdraid = UDISKS_LINUX_MDRAID (user_data);
UDisksLinuxMDRaidObject *object = NULL;
+ GUdevDevice *raid_device;
udisks_debug ("polling timeout");
goto out;
/* synthesize uevent */
- udisks_linux_mdraid_object_uevent (object, "change", NULL);
+ raid_device = udisks_linux_mdraid_object_get_device (object);
+ if (raid_device != NULL)
+ {
+ udisks_linux_mdraid_object_uevent (object, "change", raid_device, FALSE);
+ g_object_unref (raid_device);
+ }
out:
g_clear_object (&object);
GList *member_devices = NULL;
GUdevDevice *device = NULL;
const gchar *level = NULL;
+ const gchar *uuid = NULL;
+ const gchar *name = NULL;
gchar *sync_action = NULL;
gchar *sync_completed = NULL;
gchar *bitmap_location = NULL;
* former, if available
*/
if (member_devices != NULL)
- device = G_UDEV_DEVICE (member_devices->data);
+ {
+ device = G_UDEV_DEVICE (member_devices->data);
+ num_devices = g_udev_device_get_property_as_int (device, "MD_MEMBER_DEVICES");
+ level = g_udev_device_get_property (device, "MD_MEMBER_LEVEL");
+ uuid = g_udev_device_get_property (device, "MD_MEMBER_UUID");
+ name = g_udev_device_get_property (device, "MD_MEMBER_NAME");
+ }
else
- device = G_UDEV_DEVICE (raid_device);
-
- num_devices = g_udev_device_get_property_as_int (device, "MD_DEVICES");
- level = g_udev_device_get_property (device, "MD_LEVEL");
+ {
+ device = G_UDEV_DEVICE (raid_device);
+ num_devices = g_udev_device_get_property_as_int (device, "MD_DEVICES");
+ level = g_udev_device_get_property (device, "MD_LEVEL");
+ uuid = g_udev_device_get_property (device, "MD_UUID");
+ name = g_udev_device_get_property (device, "MD_NAME");
+ }
/* figure out size */
if (raid_device != NULL)
/* TODO: need MD_ARRAY_SIZE, see https://bugs.freedesktop.org/show_bug.cgi?id=53239#c5 */
}
- udisks_mdraid_set_uuid (iface, g_udev_device_get_property (device, "MD_UUID"));
- udisks_mdraid_set_name (iface, g_udev_device_get_property (device, "MD_NAME"));
+ udisks_mdraid_set_uuid (iface, uuid);
+ udisks_mdraid_set_name (iface, name);
udisks_mdraid_set_level (iface, level);
udisks_mdraid_set_num_devices (iface, num_devices);
udisks_mdraid_set_size (iface, size);
*/
if (num_members >= num_devices)
can_start = TRUE;
+
if (g_strcmp0 (level, "raid1") == 0 ||
g_strcmp0 (level, "raid4") == 0 ||
g_strcmp0 (level, "raid5") == 0 ||
if (raid_device != NULL)
{
- /* Can't use GUdevDevice methods as they cache the result and these variables vary */
- degraded = read_sysfs_attr_as_int (raid_device, "md/degraded");
- sync_action = read_sysfs_attr (raid_device, "md/sync_action");
- if (sync_action != NULL)
- g_strstrip (sync_action);
- sync_completed = read_sysfs_attr (raid_device, "md/sync_completed");
- if (sync_completed != NULL)
- g_strstrip (sync_completed);
- bitmap_location = read_sysfs_attr (raid_device, "md/bitmap/location");
- if (bitmap_location != NULL)
- g_strstrip (bitmap_location);
- chunk_size = read_sysfs_attr_as_uint64 (raid_device, "md/chunk_size");
+ if (g_strcmp0 (level, "raid1") == 0 ||
+ g_strcmp0 (level, "raid4") == 0 ||
+ g_strcmp0 (level, "raid5") == 0 ||
+ g_strcmp0 (level, "raid6") == 0 ||
+ g_strcmp0 (level, "raid10") == 0)
+ {
+ /* Can't use GUdevDevice methods as they cache the result and these variables vary */
+ degraded = read_sysfs_attr_as_int (raid_device, "md/degraded");
+ sync_action = read_sysfs_attr (raid_device, "md/sync_action");
+ if (sync_action != NULL)
+ g_strstrip (sync_action);
+ sync_completed = read_sysfs_attr (raid_device, "md/sync_completed");
+ if (sync_completed != NULL)
+ g_strstrip (sync_completed);
+ bitmap_location = read_sysfs_attr (raid_device, "md/bitmap/location");
+ if (bitmap_location != NULL)
+ g_strstrip (bitmap_location);
+ chunk_size = read_sysfs_attr_as_uint64 (raid_device, "md/chunk_size");
+ }
+ else
+ {
+ /* no redundancy, e.g. raid0 or linear */
+ }
}
udisks_mdraid_set_degraded (iface, degraded);
udisks_mdraid_set_sync_action (iface, sync_action);
if (md_dir != NULL)
{
gchar buf[256];
- const gchar *name;
- while ((name = g_dir_read_name (md_dir)) != NULL)
+ const gchar *file_name;
+ while ((file_name = g_dir_read_name (md_dir)) != NULL)
{
gchar *block_sysfs_path = NULL;
UDisksObject *member_object = NULL;
gint member_slot_as_int = -1;
guint64 member_errors = 0;
- if (!g_str_has_prefix (name, "dev-"))
+ if (!g_str_has_prefix (file_name, "dev-"))
goto member_done;
- snprintf (buf, sizeof (buf), "%s/block", name);
+ snprintf (buf, sizeof (buf), "%s/block", file_name);
block_sysfs_path = udisks_daemon_util_resolve_link (md_dir_name, buf);
if (block_sysfs_path == NULL)
{
goto member_done;
}
- snprintf (buf, sizeof (buf), "md/%s/state", name);
+ snprintf (buf, sizeof (buf), "md/%s/state", file_name);
member_state = read_sysfs_attr (raid_device, buf);
if (member_state != NULL)
{
member_state_elements = g_strsplit (member_state, ",", 0);
}
- snprintf (buf, sizeof (buf), "md/%s/slot", name);
+ snprintf (buf, sizeof (buf), "md/%s/slot", file_name);
member_slot = read_sysfs_attr (raid_device, buf);
if (member_slot != NULL)
{
member_slot_as_int = atoi (member_slot);
}
- snprintf (buf, sizeof (buf), "md/%s/errors", name);
+ snprintf (buf, sizeof (buf), "md/%s/errors", file_name);
member_errors = read_sysfs_attr_as_uint64 (raid_device, buf);
g_ptr_array_add (p,
}
udisks_mdraid_set_active_devices (iface, g_variant_builder_end (&builder));
- /* TODO: set other stuff */
-
out:
g_free (sync_completed);
g_free (sync_action);
UDisksDaemon *daemon;
+ /* The UUID for the object */
+ gchar *uuid;
+
+ /* The GUdevDevice for the RAID device (e.g. /dev/md0), if any */
+ GUdevDevice *raid_device;
+
/* list of GUdevDevice objects for detected member devices */
- GList *devices;
+ GList *member_devices;
/* interfaces */
UDisksMDRaid *iface_mdraid;
enum
{
PROP_0,
+ PROP_UUID,
PROP_DAEMON,
- PROP_DEVICE
};
static void
remove_watches (object);
- g_list_foreach (object->devices, (GFunc) g_object_unref, NULL);
- g_list_free (object->devices);
-
if (object->iface_mdraid != NULL)
g_object_unref (object->iface_mdraid);
+ g_clear_object (&object->raid_device);
+
+ g_list_foreach (object->member_devices, (GFunc) g_object_unref, NULL);
+ g_list_free (object->member_devices);
+
+ g_free (object->uuid);
+
if (G_OBJECT_CLASS (udisks_linux_mdraid_object_parent_class)->finalize != NULL)
G_OBJECT_CLASS (udisks_linux_mdraid_object_parent_class)->finalize (_object);
}
object->daemon = g_value_get_object (value);
break;
- case PROP_DEVICE:
- /* initial coldplug */
- {
- GUdevDevice *device;
- g_assert (object->devices == NULL);
- device = G_UDEV_DEVICE (g_value_get_object (value));
- udisks_linux_mdraid_object_uevent (object, "add", device);
- }
+ case PROP_UUID:
+ object->uuid = g_value_dup_string (value);
break;
default:
gchar *s;
/* compute the object path */
- uuid = udisks_mdraid_dup_uuid (object->iface_mdraid);
+ uuid = g_strdup (object->uuid);
strip_and_replace_with_uscore (uuid);
s = g_strdup_printf ("/org/freedesktop/UDisks2/mdraid/%s", uuid);
g_free (uuid);
G_PARAM_STATIC_STRINGS));
/**
- * UDisksLinuxMDRaidObject:device:
+ * UDisksLinuxMDRaidObject:uuid:
*
- * The #GUdevDevice for the object. Connect to the #GObject::notify
- * signal to get notified whenever this is updated.
+ * The UUID for the array.
*/
g_object_class_install_property (gobject_class,
- PROP_DEVICE,
- g_param_spec_object ("device",
- "Device",
- "The device for the object",
- G_UDEV_TYPE_DEVICE,
+ PROP_UUID,
+ g_param_spec_string ("uuid",
+ "UUID",
+ "The UUID for the array",
+ NULL,
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
-
}
/**
* udisks_linux_mdraid_object_new:
* @daemon: A #UDisksDaemon.
- * @device: The #GUdevDevice for the sysfs block device.
+ * @uuid: The UUID for the array.
*
- * Create a new mdraid object.
+ * Create a new MDRaid object.
*
* Returns: A #UDisksLinuxMDRaidObject object. Free with g_object_unref().
*/
UDisksLinuxMDRaidObject *
udisks_linux_mdraid_object_new (UDisksDaemon *daemon,
- GUdevDevice *device)
+ const gchar *uuid)
{
g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
- g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (uuid != NULL, NULL);
return UDISKS_LINUX_MDRAID_OBJECT (g_object_new (UDISKS_TYPE_LINUX_MDRAID_OBJECT,
"daemon", daemon,
- "device", device,
+ "uuid", uuid,
NULL));
}
udisks_linux_mdraid_object_get_members (UDisksLinuxMDRaidObject *object)
{
GList *ret = NULL;
- GList *l;
g_return_val_if_fail (UDISKS_IS_LINUX_MDRAID_OBJECT (object), NULL);
- for (l = object->devices; l != NULL; l = l->next)
- {
- GUdevDevice *device = G_UDEV_DEVICE (l->data);
- /* TODO: find a better way to distinguish member vs array ? */
- if (!g_str_has_prefix (g_udev_device_get_device_file (device), "/dev/md"))
- {
- ret = g_list_prepend (ret, g_object_ref (device));
- }
- }
+ ret = g_list_copy (object->member_devices);
+ g_list_foreach (ret, (GFunc) g_object_ref, NULL);
+
return ret;
}
udisks_linux_mdraid_object_get_device (UDisksLinuxMDRaidObject *object)
{
GUdevDevice *ret = NULL;
- GList *l;
g_return_val_if_fail (UDISKS_IS_LINUX_MDRAID_OBJECT (object), NULL);
- for (l = object->devices; l != NULL; l = l->next)
- {
- GUdevDevice *device = G_UDEV_DEVICE (l->data);
- /* TODO: find a better way to distinguish member vs array ? */
- if (g_str_has_prefix (g_udev_device_get_device_file (device), "/dev/md"))
- {
- ret = g_object_ref (device);
- goto out;
- }
- }
- out:
+ ret = object->raid_device != NULL ? g_object_ref (object->raid_device) : NULL;
+
return ret;
}
/* ---------------------------------------------------------------------------------------------------- */
static GList *
-find_link_for_sysfs_path (UDisksLinuxMDRaidObject *object,
- const gchar *sysfs_path)
+find_link_for_sysfs_path_for_member (UDisksLinuxMDRaidObject *object,
+ const gchar *sysfs_path)
{
GList *l;
GList *ret;
ret = NULL;
- for (l = object->devices; l != NULL; l = l->next)
+
+ for (l = object->member_devices; l != NULL; l = l->next)
{
GUdevDevice *device = G_UDEV_DEVICE (l->data);
if (g_strcmp0 (g_udev_device_get_sysfs_path (device), sysfs_path) == 0)
gpointer user_data)
{
UDisksLinuxMDRaidObject *object = UDISKS_LINUX_MDRAID_OBJECT (user_data);
+ gboolean bail = TRUE;
GError *error = NULL;
gchar *str = NULL;
gsize len = 0;
if (g_io_channel_seek_position (channel, 0, G_SEEK_SET, &error) != G_IO_STATUS_NORMAL)
{
- udisks_warning ("Error seeking in channel: %s (%s, %d)",
- error->message, g_quark_to_string (error->domain), error->code);
+ udisks_warning ("Error seeking in channel (uuid %s): %s (%s, %d)",
+ object->uuid, error->message, g_quark_to_string (error->domain), error->code);
g_clear_error (&error);
+ bail = TRUE;
goto out;
}
if (g_io_channel_read_to_end (channel, &str, &len, &error) != G_IO_STATUS_NORMAL)
{
- udisks_warning ("Error reading: %s (%s, %d)",
- error->message, g_quark_to_string (error->domain), error->code);
+ udisks_warning ("Error reading (uuid %s): %s (%s, %d)",
+ object->uuid, error->message, g_quark_to_string (error->domain), error->code);
g_clear_error (&error);
+ bail = TRUE;
goto out;
}
g_free (str);
/* synthesize uevent */
- udisks_linux_mdraid_object_uevent (object, "change", NULL);
+ if (object->raid_device != NULL)
+ udisks_linux_mdraid_object_uevent (object, "change", object->raid_device, FALSE);
out:
+ if (bail)
+ remove_watches (object);
return TRUE; /* keep event source around */
}
*/
static void
-md_device_added (UDisksLinuxMDRaidObject *object,
- GUdevDevice *device)
+raid_device_added (UDisksLinuxMDRaidObject *object,
+ GUdevDevice *device)
{
g_assert (object->sync_action_source == NULL);
g_assert (object->degraded_source == NULL);
}
static void
-md_device_removed (UDisksLinuxMDRaidObject *object,
- GUdevDevice *device)
+raid_device_removed (UDisksLinuxMDRaidObject *object,
+ GUdevDevice *device)
{
/* udisks_debug ("stop watching %s", g_udev_device_get_sysfs_path (device)); */
remove_watches (object);
* @object: A #UDisksLinuxMDRaidObject.
* @action: Uevent action or %NULL
* @device: A #GUdevDevice device object or %NULL if the device hasn't changed.
+ * @is_member: %TRUE if @device is a member, %FALSE if it's the raid device.
*
* Updates all information on interfaces on @mdraid.
*/
void
udisks_linux_mdraid_object_uevent (UDisksLinuxMDRaidObject *object,
const gchar *action,
- GUdevDevice *device)
+ GUdevDevice *device,
+ gboolean is_member)
{
- GList *link;
gboolean conf_changed = FALSE;
- gboolean is_md_device = FALSE;
g_return_if_fail (UDISKS_IS_LINUX_MDRAID_OBJECT (object));
- g_return_if_fail (device == NULL || G_UDEV_IS_DEVICE (device));
-
- if (device != NULL &&
- g_str_has_prefix (g_udev_device_get_name (device), "md")) /* TODO: better heuristic */
- is_md_device = TRUE;
-
- /* Skip partitions of md devices */
- if (is_md_device && device != NULL &&
- g_strcmp0 (g_udev_device_get_devtype (device), "disk") != 0)
- goto out;
+ g_return_if_fail (G_UDEV_IS_DEVICE (device));
+ udisks_debug ("is_member=%d for uuid %s and device %s", is_member, object->uuid, g_udev_device_get_device_file (device));
- link = NULL;
- if (device != NULL)
- link = find_link_for_sysfs_path (object, g_udev_device_get_sysfs_path (device));
- if (g_strcmp0 (action, "remove") == 0)
+ if (is_member)
{
- if (link != NULL)
+ GList *link = NULL;
+ link = NULL;
+ if (device != NULL)
+ link = find_link_for_sysfs_path_for_member (object, g_udev_device_get_sysfs_path (device));
+
+ if (g_strcmp0 (action, "remove") == 0)
{
- if (is_md_device)
- md_device_removed (object, device);
- g_object_unref (G_UDEV_DEVICE (link->data));
- object->devices = g_list_delete_link (object->devices, link);
+ if (link != NULL)
+ {
+ g_object_unref (G_UDEV_DEVICE (link->data));
+ object->member_devices = g_list_delete_link (object->member_devices, link);
+ }
+ else
+ {
+ udisks_warning ("MDRaid with UUID %s doesn't have member device with sysfs path %s on remove event",
+ object->uuid,
+ g_udev_device_get_sysfs_path (device));
+ }
}
else
{
- udisks_warning ("MDRaid doesn't have device with sysfs path %s on remove event",
- g_udev_device_get_sysfs_path (device));
+ if (link != NULL)
+ {
+ if (device != link->data)
+ {
+ g_object_unref (G_UDEV_DEVICE (link->data));
+ link->data = g_object_ref (device);
+ }
+ }
+ else
+ {
+ if (device != NULL)
+ {
+ object->member_devices = g_list_append (object->member_devices, g_object_ref (device));
+ }
+ }
}
}
else
{
- if (link != NULL)
+ /* Skip partitions of raid devices */
+ if (g_strcmp0 (g_udev_device_get_devtype (device), "disk") != 0)
+ goto out;
+
+ if (g_strcmp0 (action, "remove") == 0)
{
- g_object_unref (G_UDEV_DEVICE (link->data));
- link->data = g_object_ref (device);
+ if (object->raid_device != NULL)
+ if (g_strcmp0 (g_udev_device_get_sysfs_path (object->raid_device),
+ g_udev_device_get_sysfs_path (device)) == 0)
+ {
+ g_clear_object (&object->raid_device);
+ raid_device_removed (object, object->raid_device);
+ }
+ else
+ {
+ udisks_warning ("MDRaid with UUID %s doesn't have raid device with sysfs path %s on remove event (it has %s)",
+ object->uuid,
+ g_udev_device_get_sysfs_path (device),
+ g_udev_device_get_sysfs_path (object->raid_device));
+ }
+ else
+ {
+ udisks_warning ("MDRaid with UUID %s doesn't have raid device with sysfs path %s on remove event",
+ object->uuid,
+ g_udev_device_get_sysfs_path (device));
+ }
}
else
{
- if (device != NULL)
+ if (object->raid_device == NULL)
+ {
+ object->raid_device = g_object_ref (device);
+ raid_device_added (object, object->raid_device);
+ }
+ else
{
- object->devices = g_list_append (object->devices, g_object_ref (device));
- if (is_md_device)
- md_device_added (object, device);
+ if (device != object->raid_device)
+ {
+ g_clear_object (&object->raid_device);
+ object->raid_device = g_object_ref (device);
+ }
}
}
}
- conf_changed = FALSE;
- conf_changed |= update_iface (object, action, mdraid_check, mdraid_connect, mdraid_update,
- UDISKS_TYPE_LINUX_MDRAID, &object->iface_mdraid);
+ /* if we don't have any devices, no point in updating (we should get nuked soon anyway) */
+ if (udisks_linux_mdraid_object_have_devices (object))
+ {
+ conf_changed = FALSE;
+ conf_changed |= update_iface (object, action, mdraid_check, mdraid_connect, mdraid_update,
+ UDISKS_TYPE_LINUX_MDRAID, &object->iface_mdraid);
+ }
out:
;
}
/* ---------------------------------------------------------------------------------------------------- */
+/**
+ * udisks_linux_mdraid_object_have_devices:
+ * @object: A #UDisksLinuxMDRaidObject.
+ *
+ * Checks if there are any devices associated with @object at
+ * all. This includes both member devices and the raid device.
+ *
+ * Returns: %TRUE if at least one device is associated with @object, %FALSE otherwise.
+ */
+gboolean
+udisks_linux_mdraid_object_have_devices (UDisksLinuxMDRaidObject *object)
+{
+ g_return_val_if_fail (UDISKS_IS_LINUX_MDRAID_OBJECT (object), FALSE);
+
+ return g_list_length (object->member_devices) > 0 || object->raid_device != NULL;
+}
+
+/**
+ * udisks_linux_mdraid_object_get_uuid:
+ * @object: A #UDisksLinuxMDRaidObject.
+ *
+ * Gets the UUID for @object.
+ *
+ * Returns: (transfer none): The UUID for object. Do not free, the string belongs to @object.
+ */
+const gchar *
+udisks_linux_mdraid_object_get_uuid (UDisksLinuxMDRaidObject *object)
+{
+ g_return_val_if_fail (UDISKS_IS_LINUX_MDRAID_OBJECT (object), NULL);
+ return object->uuid;
+}
+
+
GType udisks_linux_mdraid_object_get_type (void) G_GNUC_CONST;
UDisksLinuxMDRaidObject *udisks_linux_mdraid_object_new (UDisksDaemon *daemon,
- GUdevDevice *device);
+ const gchar *uuid);
void udisks_linux_mdraid_object_uevent (UDisksLinuxMDRaidObject *object,
const gchar *action,
- GUdevDevice *device);
+ GUdevDevice *device,
+ gboolean is_member);
+const gchar *udisks_linux_mdraid_object_get_uuid (UDisksLinuxMDRaidObject *object);
UDisksDaemon *udisks_linux_mdraid_object_get_daemon (UDisksLinuxMDRaidObject *object);
GList *udisks_linux_mdraid_object_get_members (UDisksLinuxMDRaidObject *object);
GUdevDevice *udisks_linux_mdraid_object_get_device (UDisksLinuxMDRaidObject *object);
+gboolean udisks_linux_mdraid_object_have_devices (UDisksLinuxMDRaidObject *object);
+
G_END_DECLS
#endif /* __UDISKS_LINUX_MDRAID_OBJECT_H__ */
/* maps from array UUID and sysfs_path to UDisksLinuxMDRaidObject instances */
GHashTable *uuid_to_mdraid;
GHashTable *sysfs_path_to_mdraid;
+ GHashTable *sysfs_path_to_mdraid_members;
GFileMonitor *etc_udisks2_dir_monitor;
g_hash_table_unref (provider->sysfs_path_to_drive);
g_hash_table_unref (provider->uuid_to_mdraid);
g_hash_table_unref (provider->sysfs_path_to_mdraid);
+ g_hash_table_unref (provider->sysfs_path_to_mdraid_members);
g_object_unref (provider->gudev_client);
udisks_object_skeleton_set_manager (provider->manager_object, NULL);
g_str_equal,
g_free,
NULL);
+ provider->sysfs_path_to_mdraid_members = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ NULL);
devices = g_udev_client_query_by_subsystem (provider->gudev_client, "block");
/* make sure we process sda before sdz and sdz before sdaa */
/* ---------------------------------------------------------------------------------------------------- */
/* called with lock held */
+
static void
-handle_block_uevent_for_mdraid (UDisksLinuxProvider *provider,
- const gchar *action,
- GUdevDevice *device)
+maybe_remove_mdraid_object (UDisksLinuxProvider *provider,
+ UDisksLinuxMDRaidObject *object)
+{
+ gchar *object_uuid = NULL;
+ UDisksDaemon *daemon = NULL;
+
+ /* remove the object only if there are no devices left */
+ if (udisks_linux_mdraid_object_have_devices (object))
+ goto out;
+
+ daemon = udisks_provider_get_daemon (UDISKS_PROVIDER (provider));
+
+ object_uuid = g_strdup (udisks_linux_mdraid_object_get_uuid (object));
+ g_dbus_object_manager_server_unexport (udisks_daemon_get_object_manager (daemon),
+ g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
+ g_warn_if_fail (g_hash_table_remove (provider->uuid_to_mdraid, object_uuid));
+
+ out:
+ g_free (object_uuid);
+}
+
+static void
+handle_block_uevent_for_mdraid_with_uuid (UDisksLinuxProvider *provider,
+ const gchar *action,
+ GUdevDevice *device,
+ const gchar *uuid,
+ gboolean is_member)
{
UDisksLinuxMDRaidObject *object;
UDisksDaemon *daemon;
const gchar *sysfs_path;
- const gchar *uuid;
daemon = udisks_provider_get_daemon (UDISKS_PROVIDER (provider));
sysfs_path = g_udev_device_get_sysfs_path (device);
- uuid = g_udev_device_get_property (device, "MD_UUID");
- /* if there's no UUID, treat as remove event */
+ /* if uuid is NULL, consider it a remove event */
if (uuid == NULL)
action = "remove";
if (g_strcmp0 (action, "remove") == 0)
{
- object = g_hash_table_lookup (provider->sysfs_path_to_mdraid, sysfs_path);
+ /* first check if this device was a member */
+ object = g_hash_table_lookup (provider->sysfs_path_to_mdraid_members, sysfs_path);
if (object != NULL)
{
- GList *devices;
-
- udisks_linux_mdraid_object_uevent (object, action, device);
+ udisks_linux_mdraid_object_uevent (object, action, device, TRUE /* is_member */);
+ g_warn_if_fail (g_hash_table_remove (provider->sysfs_path_to_mdraid_members, sysfs_path));
+ maybe_remove_mdraid_object (provider, object);
+ udisks_debug ("removed member for %s", sysfs_path);
+ }
+ /* then check if the device was the raid device */
+ object = g_hash_table_lookup (provider->sysfs_path_to_mdraid, sysfs_path);
+ if (object != NULL)
+ {
+ udisks_linux_mdraid_object_uevent (object, action, device, FALSE /* is_member */);
g_warn_if_fail (g_hash_table_remove (provider->sysfs_path_to_mdraid, sysfs_path));
-
- devices = udisks_linux_mdraid_object_get_members (object);
- if (devices == NULL)
- {
- const gchar *existing_uuid;
- existing_uuid = g_object_get_data (G_OBJECT (object), "x-uuid");
- g_dbus_object_manager_server_unexport (udisks_daemon_get_object_manager (daemon),
- g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
- g_warn_if_fail (g_hash_table_remove (provider->uuid_to_mdraid, existing_uuid));
- }
- g_list_foreach (devices, (GFunc) g_object_unref, NULL);
- g_list_free (devices);
+ maybe_remove_mdraid_object (provider, object);
+ udisks_debug ("removed object for %s", sysfs_path);
}
}
else
object = g_hash_table_lookup (provider->uuid_to_mdraid, uuid);
if (object != NULL)
{
- if (g_hash_table_lookup (provider->sysfs_path_to_mdraid, sysfs_path) == NULL)
- g_hash_table_insert (provider->sysfs_path_to_mdraid, g_strdup (sysfs_path), object);
- udisks_linux_mdraid_object_uevent (object, action, device);
+ if (is_member)
+ {
+ if (g_hash_table_lookup (provider->sysfs_path_to_mdraid_members, sysfs_path) == NULL)
+ g_hash_table_insert (provider->sysfs_path_to_mdraid_members, g_strdup (sysfs_path), object);
+ }
+ else
+ {
+ if (g_hash_table_lookup (provider->sysfs_path_to_mdraid, sysfs_path) == NULL)
+ g_hash_table_insert (provider->sysfs_path_to_mdraid, g_strdup (sysfs_path), object);
+ }
+ udisks_linux_mdraid_object_uevent (object, action, device, is_member);
}
else
{
- object = udisks_linux_mdraid_object_new (daemon, device);
- if (object != NULL)
- {
- g_object_set_data_full (G_OBJECT (object), "x-uuid", g_strdup (uuid), g_free);
- g_dbus_object_manager_server_export_uniquely (udisks_daemon_get_object_manager (daemon),
- G_DBUS_OBJECT_SKELETON (object));
- g_hash_table_insert (provider->uuid_to_mdraid, g_strdup (uuid), object);
- g_hash_table_insert (provider->sysfs_path_to_mdraid, g_strdup (sysfs_path), object);
- }
+ object = udisks_linux_mdraid_object_new (daemon, uuid);
+ udisks_linux_mdraid_object_uevent (object, action, device, is_member);
+ g_dbus_object_manager_server_export_uniquely (udisks_daemon_get_object_manager (daemon),
+ G_DBUS_OBJECT_SKELETON (object));
+ g_hash_table_insert (provider->uuid_to_mdraid, g_strdup (uuid), object);
+ if (is_member)
+ g_hash_table_insert (provider->sysfs_path_to_mdraid_members, g_strdup (sysfs_path), object);
+ else
+ g_hash_table_insert (provider->sysfs_path_to_mdraid, g_strdup (sysfs_path), object);
}
}
;
}
+static void
+handle_block_uevent_for_mdraid (UDisksLinuxProvider *provider,
+ const gchar *action,
+ GUdevDevice *device)
+{
+ const gchar *uuid;
+ const gchar *member_uuid;
+
+ /* For nested RAID levels, a device can be both a member of one
+ * array and the RAID device for another. Therefore we need to
+ * consider both UUIDs.
+ *
+ * For removal, we also need to consider the case where there is no
+ * UUID.
+ */
+ uuid = g_udev_device_get_property (device, "MD_UUID");
+ member_uuid = g_udev_device_get_property (device, "MD_MEMBER_UUID");
+
+ if (uuid != NULL)
+ handle_block_uevent_for_mdraid_with_uuid (provider, action, device, uuid, FALSE);
+
+ if (member_uuid != NULL)
+ handle_block_uevent_for_mdraid_with_uuid (provider, action, device, member_uuid, TRUE);
+
+ if (uuid == NULL && member_uuid == NULL)
+ handle_block_uevent_for_mdraid_with_uuid (provider, action, device, NULL, FALSE);
+}
+
/* ---------------------------------------------------------------------------------------------------- */
/* called with lock held */