[gnome-disk-utility] handle inactive and partitioned md devices



commit 816e1b3f0af2b52a0a2c19f6092d836da7944ffe
Author: David Zeuthen <davidz redhat com>
Date:   Sun Mar 15 16:57:43 2009 -0400

    handle inactive and partitioned md devices
    
    See
    
     http://cgit.freedesktop.org/DeviceKit/DeviceKit-disks/commit/?id=1c6e690dcdc5f31d69d39fc89a9db035802febcc
    
    for the 'inactive' bits. Basically we need this to cope with the current way
    autoassembly is handled by Fedora. E.g. if you put in half a mirror and then
    remove it again, there's an inactive array with a dangling symlink in sysfs.
    
    For partitioned md devices, this was introduced in the kernel with
    this commit
    
    http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=92850bbd71228730c80efd491e7427650188d359
    
    Note that there's a bug in current udev (version 140ish) that prevents
    probing the partions of a md device. This will get fixed soon.
    
    To make it possible to partition an md device, we have moved the
    "Create partition table" section so it's only visible for a completely
    unrecognized device (e.g. when we only see a top-level block device
    with no partitions or no recognizable signature).
    
    The move of "Create partition table" makes the UI look a bit empty for
    disks that don't report SMART status; there's no sections at all. It
    also makes it a bit harder to completely format a disk. The former
    should be fixed by having some graphical representation of the
    partitions/content, the latter by having a File->New menu that
    launches a wizard to prepare formatting the disk.
---
 src/gdu/gdu-linux-md-drive.c                       |  148 +++++++------------
 src/gdu/gdu-pool.c                                 |   33 +++--
 src/gdu/gdu-private.h                              |    3 +-
 src/gdu/gdu-volume-hole.c                          |    8 +-
 .../gdu-section-create-partition-table.c           |    4 +-
 src/palimpsest/gdu-section-linux-md-drive.c        |   26 +++-
 src/palimpsest/gdu-shell.c                         |   22 +++-
 7 files changed, 131 insertions(+), 113 deletions(-)

diff --git a/src/gdu/gdu-linux-md-drive.c b/src/gdu/gdu-linux-md-drive.c
index 0e0bb33..ae14dc2 100644
--- a/src/gdu/gdu-linux-md-drive.c
+++ b/src/gdu/gdu-linux-md-drive.c
@@ -58,6 +58,8 @@ struct _GduLinuxMdDrivePrivate
 
         gchar *uuid;
 
+        gchar *device_file;
+
         gchar *id;
 };
 
@@ -93,13 +95,15 @@ gdu_linux_md_drive_finalize (GObject *object)
 
         //g_debug ("##### finalized linux-md drive '%s' %p", drive->priv->id, drive);
 
-        if (drive->priv->pool != NULL) {
+        if (drive->priv->uuid != NULL) {
                 g_signal_handlers_disconnect_by_func (drive->priv->pool, device_added, drive);
                 g_signal_handlers_disconnect_by_func (drive->priv->pool, device_removed, drive);
                 g_signal_handlers_disconnect_by_func (drive->priv->pool, device_changed, drive);
-                g_object_unref (drive->priv->pool);
         }
 
+        if (drive->priv->pool != NULL)
+                g_object_unref (drive->priv->pool);
+
         if (drive->priv->device != NULL) {
                 g_object_unref (drive->priv->device);
         }
@@ -109,6 +113,9 @@ gdu_linux_md_drive_finalize (GObject *object)
 
         g_free (drive->priv->id);
 
+        g_free (drive->priv->uuid);
+        g_free (drive->priv->device_file);
+
         if (G_OBJECT_CLASS (parent_class)->finalize)
                 (* G_OBJECT_CLASS (parent_class)->finalize) (G_OBJECT (drive));
 }
@@ -266,22 +273,37 @@ device_changed (GduPool *pool, GduDevice *device, gpointer user_data)
         }
 }
 
+/**
+ * _gdu_linux_md_drive_new:
+ * @pool: A #GduPool.
+ * @uuid: The UUID for the array.
+ * @device_file: The device file for the array.
+ *
+ * Creates a new #GduLinuxMdDrive. Note that only one of @uuid and
+ * @device_file may be %NULL.
+ */
 GduLinuxMdDrive *
 _gdu_linux_md_drive_new (GduPool      *pool,
-                         const gchar  *uuid)
+                         const gchar  *uuid,
+                         const gchar  *device_file)
 {
         GduLinuxMdDrive *drive;
 
         drive = GDU_LINUX_MD_DRIVE (g_object_new (GDU_TYPE_LINUX_MD_DRIVE, NULL));
         drive->priv->pool = g_object_ref (pool);
         drive->priv->uuid = g_strdup (uuid);
-        drive->priv->id = g_strdup_printf ("linux_md_%s", uuid);
-
-        g_signal_connect (drive->priv->pool, "device-added", G_CALLBACK (device_added), drive);
-        g_signal_connect (drive->priv->pool, "device-removed", G_CALLBACK (device_removed), drive);
-        g_signal_connect (drive->priv->pool, "device-changed", G_CALLBACK (device_changed), drive);
-
-        prime_devices (drive);
+        drive->priv->device_file = g_strdup (device_file);
+
+        if (uuid != NULL) {
+                drive->priv->id = g_strdup_printf ("linux_md_%s", uuid);
+                g_signal_connect (drive->priv->pool, "device-added", G_CALLBACK (device_added), drive);
+                g_signal_connect (drive->priv->pool, "device-removed", G_CALLBACK (device_removed), drive);
+                g_signal_connect (drive->priv->pool, "device-changed", G_CALLBACK (device_changed), drive);
+                prime_devices (drive);
+        } else {
+                drive->priv->id = g_strdup_printf ("linux_md_%s", device_file);
+                drive->priv->device = gdu_pool_get_by_device_file (pool, device_file);
+        }
 
         return drive;
 }
@@ -412,28 +434,36 @@ gdu_linux_md_drive_get_name (GduPresentable *presentable)
 
         ret = NULL;
 
-        if (drive->priv->slaves == NULL)
-                goto out;
+        if (drive->priv->slaves != NULL) {
+                device = GDU_DEVICE (drive->priv->slaves->data);
 
-        device = GDU_DEVICE (drive->priv->slaves->data);
+                level = gdu_device_linux_md_component_get_level (device);
+                name = gdu_device_linux_md_component_get_name (device);
+                num_raid_devices = gdu_device_linux_md_component_get_num_raid_devices (device);
+                num_slaves = g_list_length (drive->priv->slaves);
+                component_size = gdu_device_get_size (device);
 
-        level = gdu_device_linux_md_component_get_level (device);
-        name = gdu_device_linux_md_component_get_name (device);
-        num_raid_devices = gdu_device_linux_md_component_get_num_raid_devices (device);
-        num_slaves = g_list_length (drive->priv->slaves);
-        component_size = gdu_device_get_size (device);
+                level_str = gdu_linux_md_get_raid_level_for_display (level);
 
-        level_str = gdu_linux_md_get_raid_level_for_display (level);
+                if (name == NULL || strlen (name) == 0) {
+                        ret = g_strdup_printf (_("%s Drive"), level_str);
+                } else {
+                        ret = g_strdup_printf (_("%s (%s)"), name, level_str);
+                }
+
+                g_free (level_str);
+
+        } else if (drive->priv->device != NULL) {
+                ret = g_strdup_printf (_("RAID device %s (%s)"),
+                                       gdu_device_get_device_file (drive->priv->device),
+                                       gdu_device_linux_md_get_state (drive->priv->device));
 
-        if (name == NULL || strlen (name) == 0) {
-                ret = g_strdup_printf (_("%s Drive"), level_str);
         } else {
-                ret = g_strdup_printf (_("%s (%s)"), name, level_str);
-        }
+                g_warn_if_fail (drive->priv->device_file != NULL);
 
-        g_free (level_str);
+                ret = g_strdup_printf (_("RAID device %s"), drive->priv->device_file);
+        }
 
-out:
         return ret;
 }
 
@@ -677,74 +707,6 @@ out:
         return ret;
 }
 
-#if 0
-static gboolean
-gdu_linux_md_drive_can_activate_degraded (GduDrive *_drive)
-{
-        GduLinuxMdDrive *drive = GDU_LINUX_MD_DRIVE (_drive);
-        GduDevice *device;
-        gboolean can_activate_degraded;
-        int num_ready_slaves;
-        int num_raid_devices;
-        const char *raid_level;
-
-        device = NULL;
-
-        can_activate_degraded = FALSE;
-
-        /* can't activated what's already activated */
-        if (drive->priv->device != NULL)
-                goto out;
-
-        /* we might even be able to activate in non-degraded mode */
-        if (gdu_linux_md_drive_can_activate (_drive))
-                goto out;
-
-        device = gdu_linux_md_drive_get_first_slave (drive);
-        if (device == NULL)
-                goto out;
-
-        num_ready_slaves = gdu_linux_md_drive_get_num_ready_slaves (drive);
-        num_raid_devices = gdu_device_linux_md_component_get_num_raid_devices (device);
-        raid_level = gdu_device_linux_md_component_get_level (device);
-
-        /* this depends on the raid level... */
-        if (strcmp (raid_level, "raid1") == 0) {
-                if (num_ready_slaves >= 1) {
-                        can_activate_degraded = TRUE;
-                }
-        } else if (strcmp (raid_level, "raid4") == 0) {
-                if (num_ready_slaves >= num_raid_devices - 1) {
-                        can_activate_degraded = TRUE;
-                }
-        } else if (strcmp (raid_level, "raid5") == 0) {
-                if (num_ready_slaves >= num_raid_devices - 1) {
-                        can_activate_degraded = TRUE;
-                }
-        } else if (strcmp (raid_level, "raid6") == 0) {
-                if (num_ready_slaves >= num_raid_devices - 2) {
-                        can_activate_degraded = TRUE;
-                }
-        } else if (strcmp (raid_level, "raid10") == 0) {
-                /* TODO: This is not necessarily correct; it depends on which
-                 *       slaves have failed... Right now we err on the side
-                 *       of saying the array can be activated even when sometimes
-                 *       it can't
-                 */
-                if (num_ready_slaves >= num_raid_devices / 2) {
-                        can_activate_degraded = TRUE;
-                }
-        }
-
-
-out:
-        if (device != NULL)
-                g_object_unref (device);
-        return can_activate_degraded;
-        return FALSE;
-}
-#endif
-
 typedef struct
 {
         GduLinuxMdDrive *drive;
diff --git a/src/gdu/gdu-pool.c b/src/gdu/gdu-pool.c
index 00aa228..c1cfd2b 100644
--- a/src/gdu/gdu-pool.c
+++ b/src/gdu/gdu-pool.c
@@ -554,7 +554,7 @@ recompute_presentables (GduPool *pool)
          *
          * The reason for this brute-force approach is that the GduPresentable entities are
          * somewhat complicated since the whole process involves synthesizing GduVolumeHole and
-         * GduActivatableDrive objects.
+         * GduLinuxMdDrive objects.
          */
 
         new_presentables = NULL;
@@ -595,16 +595,29 @@ recompute_presentables (GduPool *pool)
                                 const gchar *uuid;
 
                                 uuid = gdu_device_linux_md_get_uuid (device);
-                                drive = GDU_DRIVE (_gdu_linux_md_drive_new (pool, uuid));
 
-                                /* Due to the topological sorting of devices, we are guaranteed that
-                                 * that running Linux MD arrays come before the slaves.
-                                 */
-                                g_warn_if_fail (g_hash_table_lookup (hash_map_from_linux_md_uuid_to_drive, uuid) == NULL);
+                                /* 'clear' and 'inactive' devices may not have an uuid */
+                                if (uuid != NULL && strlen (uuid) == 0)
+                                        uuid = NULL;
+
+                                if (uuid != NULL) {
+                                        drive = GDU_DRIVE (_gdu_linux_md_drive_new (pool, uuid, NULL));
+
+                                        /* Due to the topological sorting of devices, we are guaranteed that
+                                         * that running Linux MD arrays come before the slaves.
+                                         */
+                                        g_warn_if_fail (g_hash_table_lookup (hash_map_from_linux_md_uuid_to_drive, uuid) == NULL);
+
+                                        g_hash_table_insert (hash_map_from_linux_md_uuid_to_drive,
+                                                             (gpointer) uuid,
+                                                             drive);
+                                } else {
+                                        drive = GDU_DRIVE (_gdu_linux_md_drive_new (pool,
+                                                                                    NULL,
+                                                                                    gdu_device_get_device_file (device)));
+                                }
+
 
-                                g_hash_table_insert (hash_map_from_linux_md_uuid_to_drive,
-                                                     (gpointer) uuid,
-                                                     drive);
                         } else {
                                 drive = _gdu_drive_new_from_device (pool, device);
                         }
@@ -709,7 +722,7 @@ recompute_presentables (GduPool *pool)
                         if (g_hash_table_lookup (hash_map_from_linux_md_uuid_to_drive, uuid) == NULL) {
                                 GduDrive *drive;
 
-                                drive = GDU_DRIVE (_gdu_linux_md_drive_new (pool, uuid));
+                                drive = GDU_DRIVE (_gdu_linux_md_drive_new (pool, uuid, NULL));
                                 new_presentables = g_list_prepend (new_presentables, drive);
 
                                 g_hash_table_insert (hash_map_from_linux_md_uuid_to_drive,
diff --git a/src/gdu/gdu-private.h b/src/gdu/gdu-private.h
index 96e7510..2beaa9f 100644
--- a/src/gdu/gdu-private.h
+++ b/src/gdu/gdu-private.h
@@ -94,7 +94,8 @@ GduVolumeHole   *_gdu_volume_hole_new       (GduPool *pool, guint64 offset, guin
 
 
 GduLinuxMdDrive   *_gdu_linux_md_drive_new             (GduPool              *pool,
-                                                        const gchar          *uuid);
+                                                        const gchar          *uuid,
+                                                        const gchar          *device_file);
 
 gboolean _gdu_linux_md_drive_has_uuid (GduLinuxMdDrive  *drive,
                                        const gchar      *uuid);
diff --git a/src/gdu/gdu-volume-hole.c b/src/gdu/gdu-volume-hole.c
index af8141e..6d77fca 100644
--- a/src/gdu/gdu-volume-hole.c
+++ b/src/gdu/gdu-volume-hole.c
@@ -31,6 +31,7 @@
 #include "gdu-device.h"
 #include "gdu-volume-hole.h"
 #include "gdu-presentable.h"
+#include "gdu-linux-md-drive.h"
 
 /**
  * SECTION:gdu-volume-hole
@@ -183,8 +184,13 @@ gdu_volume_hole_get_icon (GduPresentable *presentable)
 
         drive_media = gdu_device_drive_get_media (d);
 
+        /* Linux MD devices can be partitioned */
+        if (GDU_IS_LINUX_MD_DRIVE (p)) {
+                name = "gdu-raid-array";
+        }
+
         /* first try the media */
-        if (drive_media != NULL) {
+        if (name == NULL && drive_media != NULL) {
                 if (strcmp (drive_media, "flash_cf") == 0) {
                         name = "media-flash-cf";
                 } else if (strcmp (drive_media, "flash_ms") == 0) {
diff --git a/src/palimpsest/gdu-section-create-partition-table.c b/src/palimpsest/gdu-section-create-partition-table.c
index 4bd3f87..bbabc7f 100644
--- a/src/palimpsest/gdu-section-create-partition-table.c
+++ b/src/palimpsest/gdu-section-create-partition-table.c
@@ -205,7 +205,7 @@ gdu_section_create_partition_table_init (GduSectionCreatePartitionTable *section
         section->priv->create_part_table_action = polkit_gnome_action_new_default (
                 "create-part-table",
                 section->priv->pk_change_action,
-                _("_Create"),
+                _("C_reate"),
                 _("Create"));
         g_object_set (section->priv->create_part_table_action,
                       "auth-label", _("_Create..."),
@@ -244,7 +244,7 @@ gdu_section_create_partition_table_init (GduSectionCreatePartitionTable *section
         /* partition table type */
         label = gtk_label_new (NULL);
         gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
-        gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("_Type:"));
+        gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), _("Ty_pe:"));
         gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1,
                           GTK_FILL, GTK_EXPAND | GTK_FILL, 2, 2);
         combo_box = gdu_util_part_table_type_combo_box_create ();
diff --git a/src/palimpsest/gdu-section-linux-md-drive.c b/src/palimpsest/gdu-section-linux-md-drive.c
index a1195b9..90a6fd5 100644
--- a/src/palimpsest/gdu-section-linux-md-drive.c
+++ b/src/palimpsest/gdu-section-linux-md-drive.c
@@ -571,13 +571,33 @@ update (GduSectionLinuxMdDrive *section)
 
         slaves = gdu_linux_md_drive_get_slaves (linux_md_drive);
         num_slaves = g_list_length (slaves);
+
         if (num_slaves == 0) {
-                /* this fine; happens when the last component is yanked
-                 * since remove_slave() emits "changed".
+                /* This happens for 'clear' arrays or for arrays with stale symlinks
+                 * to devices that has been yanked.
+                 *
+                 * - Ideally Linux MD / mdadm wouldn't have stale symlinks in sysfs but
+                 *   that is not how things currently work (2.6.29).
+                 *
+                 * - Also sometimes when stopping an array the md device is still around
+                 *
+                 * So we only offer to stop such arrays since the software beneath us
+                 * is unstable. In an ideal world we wouldn't show them.
                  */
-                /*g_warning ("%s: no slaves for linux_md drive", __FUNCTION__);*/
+
+                gtk_label_set_text (GTK_LABEL (section->priv->linux_md_name_label), _("-"));
+                gtk_label_set_text (GTK_LABEL (section->priv->linux_md_home_host_label), _("-"));
+                gtk_label_set_text (GTK_LABEL (section->priv->linux_md_type_label), _("-"));
+                gtk_label_set_text (GTK_LABEL (section->priv->linux_md_size_label), _("-"));
+                gtk_label_set_text (GTK_LABEL (section->priv->linux_md_components_label), _("-"));
+                gtk_label_set_markup (GTK_LABEL (section->priv->linux_md_state_label), _("-"));
+
+                gtk_widget_set_sensitive (GTK_WIDGET (section), FALSE);
                 goto out;
         }
+
+        gtk_widget_set_sensitive (GTK_WIDGET (section), TRUE);
+
         component = GDU_DEVICE (slaves->data);
 
         if (!gdu_device_is_linux_md_component (component)) {
diff --git a/src/palimpsest/gdu-shell.c b/src/palimpsest/gdu-shell.c
index 8a0da93..324f57c 100644
--- a/src/palimpsest/gdu-shell.c
+++ b/src/palimpsest/gdu-shell.c
@@ -522,9 +522,6 @@ compute_sections_to_show (GduShell *shell, gboolean showing_job)
                                                                                   (gpointer) GDU_TYPE_SECTION_HEALTH);
                                 }
 
-                                sections_to_show = g_list_append (sections_to_show,
-                                                                  (gpointer) GDU_TYPE_SECTION_CREATE_PARTITION_TABLE);
-
                         }
 
                 } else if (GDU_IS_VOLUME (shell->priv->presentable_now_showing) && device != NULL) {
@@ -551,11 +548,30 @@ compute_sections_to_show (GduShell *shell, gboolean showing_job)
                                                 sections_to_show, (gpointer) GDU_TYPE_SECTION_SWAPSPACE);
                                 }
                         } else {
+                                GduPresentable *toplevel_presentable;
+                                GduDevice *toplevel_device;
+
                                 sections_to_show = g_list_append (
                                         sections_to_show, (gpointer) GDU_TYPE_SECTION_UNRECOGNIZED);
+
+                                /* Also show a "Create partition table" section for a volume if the drive isn't partitioned */
+                                toplevel_presentable = gdu_presentable_get_toplevel (shell->priv->presentable_now_showing);
+                                if (toplevel_presentable != NULL) {
+                                        toplevel_device = gdu_presentable_get_device (toplevel_presentable);
+
+                                        if (toplevel_device != NULL) {
+                                                if (!gdu_device_is_partition_table (toplevel_device)) {
+                                                        sections_to_show = g_list_append (
+                                                                sections_to_show, (gpointer) GDU_TYPE_SECTION_CREATE_PARTITION_TABLE);
+                                                }
+                                                g_object_unref (toplevel_device);
+                                        }
+                                        g_object_unref (toplevel_presentable);
+                                }
                         }
 
                 } else if (GDU_IS_VOLUME_HOLE (shell->priv->presentable_now_showing)) {
+
                         sections_to_show = g_list_append (sections_to_show,
                                                           (gpointer) GDU_TYPE_SECTION_UNALLOCATED);
                 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]