]> git.proxmox.com Git - grub2.git/commitdiff
Lazy LVM and RAID assembly
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Thu, 21 Apr 2011 22:09:07 +0000 (00:09 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Thu, 21 Apr 2011 22:09:07 +0000 (00:09 +0200)
13 files changed:
grub-core/disk/ata.c
grub-core/disk/host.c
grub-core/disk/i386/pc/biosdisk.c
grub-core/disk/loopback.c
grub-core/disk/lvm.c
grub-core/disk/memdisk.c
grub-core/disk/raid.c
grub-core/disk/scsi.c
grub-core/fs/i386/pc/pxe.c
grub-core/kern/disk.c
grub-core/kern/emu/hostdisk.c
include/grub/disk.h
include/grub/raid.h

index 7f261560d579fd106c482287a05d8c03c5992854..3a43a8caeb126fb2fd01f9cf7f42b06d875323b8 100644 (file)
@@ -666,10 +666,14 @@ grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector,
 \f
 
 static int
-grub_ata_iterate (int (*hook) (const char *name))
+grub_ata_iterate (int (*hook) (const char *name),
+                 grub_disk_pull_t pull)
 {
   struct grub_ata_device *dev;
 
+  if (pull != GRUB_DISK_PULL_NONE)
+    return 0;
+
   for (dev = grub_ata_devices; dev; dev = dev->next)
     {
       char devname[10];
@@ -696,7 +700,8 @@ grub_ata_iterate (int (*hook) (const char *name))
 }
 
 static grub_err_t
-grub_ata_open (const char *name, grub_disk_t disk)
+grub_ata_open (const char *name, grub_disk_t disk,
+              grub_disk_pull_t pull __attribute__ ((unused)))
 {
   struct grub_ata_device *dev;
   grub_err_t err;
index c5196629336e13d89bf0a909f114618b008f5d00..5376cc6ceeb683ee2a601fb54ab939248326f0c7 100644 (file)
 int grub_disk_host_i_want_a_reference;
 
 static int
-grub_host_iterate (int (*hook) (const char *name))
+grub_host_iterate (int (*hook) (const char *name),
+                  grub_disk_pull_t pull)
 {
+  if (pull != GRUB_DISK_PULL_NONE)
+    return 0;
+
   if (hook ("host"))
     return 1;
   return 0;
 }
 
 static grub_err_t
-grub_host_open (const char *name, grub_disk_t disk)
+grub_host_open (const char *name, grub_disk_t disk,
+               grub_disk_pull_t pull __attribute__ ((unused)))
 {
   if (grub_strcmp (name, "host"))
       return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a host disk");
index 1d47dc727c96816f722c8e10a535a1ecbe0d79a2..e75ab184bdf1dabc6f339c464c4b02123f29f79a 100644 (file)
@@ -284,42 +284,52 @@ grub_biosdisk_call_hook (int (*hook) (const char *name), int drive)
 }
 
 static int
-grub_biosdisk_iterate (int (*hook) (const char *name))
+grub_biosdisk_iterate (int (*hook) (const char *name),
+                      grub_disk_pull_t pull __attribute__ ((unused)))
 {
-  int drive;
   int num_floppies;
+  int drive;
 
   /* For hard disks, attempt to read the MBR.  */
-  for (drive = 0x80; drive < 0x90; drive++)
+  switch (pull)
     {
-      if (grub_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1,
-                                    GRUB_MEMORY_MACHINE_SCRATCH_SEG) != 0)
+    case GRUB_DISK_PULL_NONE:
+      for (drive = 0x80; drive < 0x90; drive++)
        {
-         grub_dprintf ("disk", "Read error when probing drive 0x%2x\n", drive);
-         break;
+         if (grub_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1,
+                                        GRUB_MEMORY_MACHINE_SCRATCH_SEG) != 0)
+           {
+             grub_dprintf ("disk", "Read error when probing drive 0x%2x\n", drive);
+             break;
+           }
+
+         if (grub_biosdisk_call_hook (hook, drive))
+           return 1;
        }
+      return 0;
 
-      if (grub_biosdisk_call_hook (hook, drive))
-       return 1;
-    }
+    case GRUB_DISK_PULL_REMOVABLE:
+      if (cd_drive)
+       {
+         if (grub_biosdisk_call_hook (hook, cd_drive))
+           return 1;
+       }
 
-  if (cd_drive)
-    {
-      if (grub_biosdisk_call_hook (hook, cd_drive))
-      return 1;
+      /* For floppy disks, we can get the number safely.  */
+      num_floppies = grub_biosdisk_get_num_floppies ();
+      for (drive = 0; drive < num_floppies; drive++)
+       if (grub_biosdisk_call_hook (hook, drive))
+         return 1;
+      return 0;
+    default:
+      return 0;
     }
-
-  /* For floppy disks, we can get the number safely.  */
-  num_floppies = grub_biosdisk_get_num_floppies ();
-  for (drive = 0; drive < num_floppies; drive++)
-    if (grub_biosdisk_call_hook (hook, drive))
-      return 1;
-
   return 0;
 }
 
 static grub_err_t
-grub_biosdisk_open (const char *name, grub_disk_t disk)
+grub_biosdisk_open (const char *name, grub_disk_t disk,
+                   grub_disk_pull_t pull __attribute__ ((unused)))
 {
   grub_uint64_t total_sectors = 0;
   int drive;
index d50f353b150cea8e6bb6b031063264ef50853a1c..21345af57c8819d5fc6ab6ef620816b50d5cd50a 100644 (file)
@@ -133,9 +133,12 @@ fail:
 
 \f
 static int
-grub_loopback_iterate (int (*hook) (const char *name))
+grub_loopback_iterate (int (*hook) (const char *name),
+                   grub_disk_pull_t pull)
 {
   struct grub_loopback *d;
+  if (pull != GRUB_DISK_PULL_NONE)
+    return 0;
   for (d = loopback_list; d; d = d->next)
     {
       if (hook (d->devname))
@@ -145,7 +148,8 @@ grub_loopback_iterate (int (*hook) (const char *name))
 }
 
 static grub_err_t
-grub_loopback_open (const char *name, grub_disk_t disk)
+grub_loopback_open (const char *name, grub_disk_t disk,
+                   grub_disk_pull_t pull __attribute__ ((unused)))
 {
   struct grub_loopback *dev;
 
index 206e3e22095a6db816566fc1d9ff684c5feac39e..72f493540d461e4d13e87c05af1f4beeca59b886 100644 (file)
@@ -32,7 +32,12 @@ GRUB_MOD_LICENSE ("GPLv3+");
 
 static struct grub_lvm_vg *vg_list;
 static int lv_count;
+static int scan_depth = 0;
 
+static int is_lv_readable (struct grub_lvm_lv *lv);
+
+static int
+grub_lvm_scan_device (const char *name);
 \f
 /* Go the string STR and return the number after STR.  *P will point
    at the number.  In case STR is not found, *P will be NULL and the
@@ -96,16 +101,39 @@ grub_lvm_check_flag (char *p, char *str, char *flag)
 }
 
 static int
-grub_lvm_iterate (int (*hook) (const char *name))
+grub_lvm_iterate (int (*hook) (const char *name),
+                 grub_disk_pull_t pull)
 {
   struct grub_lvm_vg *vg;
+  unsigned old_count = 0;
+  if (pull == GRUB_DISK_PULL_RESCAN && scan_depth)
+    return 0;
+
+  if (pull == GRUB_DISK_PULL_RESCAN)
+    {
+      old_count = lv_count;
+      if (!scan_depth)
+       {
+         scan_depth++;
+         grub_device_iterate (&grub_lvm_scan_device);
+         scan_depth--;
+       }
+    }
+  if (pull != GRUB_DISK_PULL_RESCAN && pull != GRUB_DISK_PULL_NONE)
+    return GRUB_ERR_NONE;
   for (vg = vg_list; vg; vg = vg->next)
     {
       struct grub_lvm_lv *lv;
       if (vg->lvs)
        for (lv = vg->lvs; lv; lv = lv->next)
-         if (lv->visible && hook (lv->name))
-           return 1;
+         if (lv->visible && lv->number >= old_count)
+           {
+             char lvname[sizeof ("lvm/") + grub_strlen (lv->name)];
+             grub_memcpy (lvname, "lvm/", sizeof ("lvm/") - 1);
+             grub_strcpy (lvname + sizeof ("lvm/") - 1, lv->name);
+             if (hook (lvname))
+               return 1;
+           }
     }
 
   return 0;
@@ -135,8 +163,8 @@ grub_lvm_memberlist (grub_disk_t disk)
 }
 #endif
 
-static grub_err_t
-grub_lvm_open (const char *name, grub_disk_t disk)
+static struct grub_lvm_lv *
+find_lv (const char *name)
 {
   struct grub_lvm_vg *vg;
   struct grub_lvm_lv *lv = NULL;
@@ -144,11 +172,43 @@ grub_lvm_open (const char *name, grub_disk_t disk)
     {
       if (vg->lvs)
        for (lv = vg->lvs; lv; lv = lv->next)
-         if (! grub_strcmp (lv->name, name))
-           break;
+         if (! grub_strcmp (lv->name, name) && is_lv_readable (lv))
+           return lv;
+    }
+  return NULL;
+}
 
-      if (lv)
-       break;
+static const char *scan_for = NULL;
+
+static grub_err_t
+grub_lvm_open (const char *name, grub_disk_t disk,
+              grub_disk_pull_t pull)
+{
+  struct grub_lvm_lv *lv = NULL;
+  int explicit = 0;
+
+  if (grub_memcmp (name, "lvm/", sizeof ("lvm/") - 1) == 0)
+    {
+      name += sizeof ("lvm/") - 1;
+      explicit = 1;
+    }
+
+  lv = find_lv (name);
+
+  if (! lv && !scan_depth &&
+      pull == (explicit ? GRUB_DISK_PULL_RESCAN : GRUB_DISK_PULL_RESCAN_UNTYPED))
+    {
+      scan_for = name;
+      scan_depth++;
+      grub_device_iterate (&grub_lvm_scan_device);
+      scan_depth--;
+      scan_for = NULL;
+      if (grub_errno)
+       {
+         grub_print_error ();
+         grub_errno = GRUB_ERR_NONE;
+       }
+      lv = find_lv (name);
     }
 
   if (! lv)
@@ -285,6 +345,49 @@ read_lv (struct grub_lvm_lv *lv, grub_disk_addr_t sector,
   return grub_error (GRUB_ERR_IO, "unknown LVM segment");
 }
 
+static grub_err_t
+is_node_readable (const struct grub_lvm_node *node)
+{
+  /* Check whether we actually know the physical volume we want to
+     read from.  */
+  if (node->pv)
+    return !!(node->pv->disk);
+  if (node->lv)
+    return is_lv_readable (node->lv);
+  return 0;
+}
+
+static int
+is_lv_readable (struct grub_lvm_lv *lv)
+{
+  unsigned int i, j;
+
+  if (!lv)
+    return 0;
+
+  /* Find the right segment.  */
+  for (i = 0; i < lv->segment_count; i++)
+    switch (lv->segments[i].type)
+      {
+      case GRUB_LVM_STRIPED:
+       for (j = 0; j < lv->segments[i].node_count; j++)
+         if (!is_node_readable (lv->segments[i].nodes + j))
+           return 0;
+       break;
+      case GRUB_LVM_MIRROR:
+       for (j = 0; j < lv->segments[i].node_count; j++)
+         if (is_node_readable (lv->segments[i].nodes + j))
+           break;
+       if (j == lv->segments[i].node_count)
+         return 0;
+      default:
+       return 0;
+      }
+
+  return 1;
+}
+
+
 static grub_err_t
 grub_lvm_read (grub_disk_t disk, grub_disk_addr_t sector,
                grub_size_t size, char *buf)
@@ -332,6 +435,15 @@ grub_lvm_scan_device (const char *name)
       return 0;
     }
 
+  for (vg = vg_list; vg; vg = vg->next)
+    for (pv = vg->pvs; pv; pv = pv->next)
+      if (pv->disk && pv->disk->id == disk->id
+         && pv->disk->dev->id == disk->dev->id)
+       {
+         grub_disk_close (disk);
+         return 0;
+       }
+
   /* Search for label. */
   for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++)
     {
@@ -857,6 +969,8 @@ grub_lvm_scan_device (const char *name)
   if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
     grub_errno = GRUB_ERR_NONE;
   grub_print_error ();
+  if (scan_for && find_lv (scan_for))
+    return 1;
   return 0;
 }
 
@@ -878,13 +992,6 @@ static struct grub_disk_dev grub_lvm_dev =
 \f
 GRUB_MOD_INIT(lvm)
 {
-  grub_device_iterate (&grub_lvm_scan_device);
-  if (grub_errno)
-    {
-      grub_print_error ();
-      grub_errno = GRUB_ERR_NONE;
-    }
-
   grub_disk_dev_register (&grub_lvm_dev);
 }
 
index 114ac0d9edad27522c0c0ebc747b54fcf0dad7e4..77523405574e31c253cc03ae31bfade5159cf4b1 100644 (file)
@@ -30,13 +30,18 @@ static char *memdisk_addr;
 static grub_off_t memdisk_size = 0;
 
 static int
-grub_memdisk_iterate (int (*hook) (const char *name))
+grub_memdisk_iterate (int (*hook) (const char *name),
+                     grub_disk_pull_t pull)
 {
+  if (pull != GRUB_DISK_PULL_NONE)
+    return 0;
+
   return hook ("memdisk");
 }
 
 static grub_err_t
-grub_memdisk_open (const char *name, grub_disk_t disk)
+grub_memdisk_open (const char *name, grub_disk_t disk,
+                  grub_disk_pull_t pull __attribute__ ((unused)))
 {
   if (grub_strcmp (name, "memdisk"))
       return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a memdisk");
index 946e6d2c2a1510aa6d96a3691c047f79e9217933..78453ac88c99476450f1dd44e26f4ab70d8596cf 100644 (file)
@@ -33,6 +33,11 @@ GRUB_MOD_LICENSE ("GPLv3+");
 static struct grub_raid_array *array_list;
 grub_raid5_recover_func_t grub_raid5_recover_func;
 grub_raid6_recover_func_t grub_raid6_recover_func;
+static grub_raid_t grub_raid_list;
+static int inscnt = 0;
+
+static struct grub_raid_array *
+find_array (const char *name);
 
 \f
 static char
@@ -78,14 +83,98 @@ grub_is_array_readable (struct grub_raid_array *array)
   return 0;
 }
 
+static grub_err_t
+insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
+              grub_disk_addr_t start_sector, const char *scanner_name,
+             grub_raid_t raid __attribute__ ((unused)));
+
+static int scan_depth = 0;
+
+static void
+scan_devices (const char *arname)
+{
+  grub_raid_t raid;
+
+  auto int hook (const char *name);
+  int hook (const char *name)
+    {
+      grub_disk_t disk;
+      struct grub_raid_array array;
+      struct grub_raid_array *arr;
+      grub_disk_addr_t start_sector;
+
+      grub_dprintf ("raid", "Scanning for %s RAID devices on disk %s\n",
+                   raid->name, name);
+#ifdef GRUB_UTIL
+      grub_util_info ("Scanning for %s RAID devices on disk %s",
+                     raid->name, name);
+#endif
+
+      disk = grub_disk_open (name);
+      if (!disk)
+        return 0;
+      
+      for (arr = array_list; arr != NULL; arr = arr->next)
+       {
+         struct grub_raid_member *m;
+         for (m = arr->members; m < arr->members + arr->nr_devs; m++)
+           if (m->device && m->device->id == disk->id
+               && m->device->dev->id == m->device->dev->id)
+             {
+               grub_disk_close (disk);
+               return 0;
+             }
+       }
+
+      if ((disk->total_sectors != GRUB_ULONG_MAX) &&
+         (! raid->detect (disk, &array, &start_sector)) &&
+         (! insert_array (disk, &array, start_sector, raid->name,
+                          raid)))
+       return 0;
+
+      /* This error usually means it's not raid, no need to display
+        it.  */
+      if (grub_errno != GRUB_ERR_OUT_OF_RANGE)
+       grub_print_error ();
+
+      grub_errno = GRUB_ERR_NONE;
+
+      grub_disk_close (disk);
+
+      if (arname && find_array (arname))
+       return 1;
+
+      return 0;
+    }
+
+  if (scan_depth)
+    return;
+
+  scan_depth++;
+  for (raid = grub_raid_list; raid; raid = raid->next)
+    grub_device_iterate (&hook);
+  scan_depth--;
+}
+
 static int
-grub_raid_iterate (int (*hook) (const char *name))
+grub_raid_iterate (int (*hook) (const char *name),
+                  grub_disk_pull_t pull)
 {
   struct grub_raid_array *array;
+  int islcnt = 0;
+
+  if (pull == GRUB_DISK_PULL_RESCAN)
+    {
+      islcnt = inscnt;
+      scan_devices (NULL);
+    }
+
+  if (pull != GRUB_DISK_PULL_NONE && pull != GRUB_DISK_PULL_RESCAN)
+    return 0;
 
   for (array = array_list; array != NULL; array = array->next)
     {
-      if (grub_is_array_readable (array))
+      if (grub_is_array_readable (array) && array->became_readable_at >= islcnt)
        if (hook (array->name))
          return 1;
     }
@@ -134,11 +223,10 @@ ascii2hex (char c)
   return 0;
 }
 
-static grub_err_t
-grub_raid_open (const char *name, grub_disk_t disk)
+static struct grub_raid_array *
+find_array (const char *name)
 {
   struct grub_raid_array *array;
-  unsigned n;
 
   if (grub_memcmp (name, "mduuid/", sizeof ("mduuid/") - 1) == 0)
     {
@@ -155,7 +243,7 @@ grub_raid_open (const char *name, grub_disk_t disk)
          if (uuid_len == (unsigned) array->uuid_len
              && grub_memcmp (uuidbin, array->uuid, uuid_len) == 0)
            if (grub_is_array_readable (array))
-             break;
+             return array;
        }
     }
   else
@@ -163,8 +251,33 @@ grub_raid_open (const char *name, grub_disk_t disk)
       {
        if (!grub_strcmp (array->name, name))
          if (grub_is_array_readable (array))
-           break;
+           return array;
       }
+  return NULL;
+}
+
+static grub_err_t
+grub_raid_open (const char *name, grub_disk_t disk, grub_disk_pull_t pull)
+{
+  struct grub_raid_array *array;
+  unsigned n;
+
+  if (grub_memcmp (name, "md", sizeof ("md") - 1) != 0)
+     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
+                       name);
+
+  array = find_array (name);
+
+  if (! array && pull == GRUB_DISK_PULL_RESCAN)
+    {
+      scan_devices (name);
+      if (grub_errno)
+       {
+         grub_print_error ();
+         grub_errno = GRUB_ERR_NONE;
+       }
+      array = find_array (name);
+    }
 
   if (!array)
     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
@@ -690,15 +803,19 @@ insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
     }
 
   /* Add the device to the array. */
-  array->members[new_array->index].device = disk;
-  array->members[new_array->index].start_sector = start_sector;
-  array->nr_devs++;
+  {
+    int was_readable = grub_is_array_readable (array);
+
+    array->members[new_array->index].device = disk;
+    array->members[new_array->index].start_sector = start_sector;
+    array->nr_devs++;
+    if (!was_readable && grub_is_array_readable (array))
+      array->became_readable_at = inscnt++;
+  }
 
   return 0;
 }
 
-static grub_raid_t grub_raid_list;
-
 static void
 free_array (void)
 {
@@ -729,45 +846,8 @@ free_array (void)
 void
 grub_raid_register (grub_raid_t raid)
 {
-  auto int hook (const char *name);
-  int hook (const char *name)
-    {
-      grub_disk_t disk;
-      struct grub_raid_array array;
-      grub_disk_addr_t start_sector;
-
-      grub_dprintf ("raid", "Scanning for %s RAID devices on disk %s\n",
-                   grub_raid_list->name, name);
-#ifdef GRUB_UTIL
-      grub_util_info ("Scanning for %s RAID devices on disk %s",
-                     grub_raid_list->name, name);
-#endif
-
-      disk = grub_disk_open (name);
-      if (!disk)
-        return 0;
-
-      if ((disk->total_sectors != GRUB_ULONG_MAX) &&
-         (! grub_raid_list->detect (disk, &array, &start_sector)) &&
-         (! insert_array (disk, &array, start_sector, grub_raid_list->name,
-                          grub_raid_list)))
-       return 0;
-
-      /* This error usually means it's not raid, no need to display
-        it.  */
-      if (grub_errno != GRUB_ERR_OUT_OF_RANGE)
-       grub_print_error ();
-
-      grub_errno = GRUB_ERR_NONE;
-
-      grub_disk_close (disk);
-
-      return 0;
-    }
-
   raid->next = grub_raid_list;
   grub_raid_list = raid;
-  grub_device_iterate (&hook);
 }
 
 void
index 25f0e3aea25a6b9a1c428b3e225ba5f9a8a9ebf2..e85036860b8208b77f320a916905e0ee74f3079f 100644 (file)
@@ -316,7 +316,8 @@ grub_scsi_write12 (grub_disk_t disk, grub_disk_addr_t sector,
 
 \f
 static int
-grub_scsi_iterate (int (*hook) (const char *name))
+grub_scsi_iterate (int (*hook) (const char *name),
+                  grub_disk_pull_t pull)
 {
   grub_scsi_dev_t p;
 
@@ -356,6 +357,9 @@ grub_scsi_iterate (int (*hook) (const char *name))
       return 0;
     }
 
+  if (pull != GRUB_DISK_PULL_NONE)
+    return 0;
+
   for (p = grub_scsi_dev_list; p; p = p->next)
     if (p->iterate && (p->iterate) (scsi_iterate))
       return 1;
@@ -364,7 +368,8 @@ grub_scsi_iterate (int (*hook) (const char *name))
 }
 
 static grub_err_t
-grub_scsi_open (const char *name, grub_disk_t disk)
+grub_scsi_open (const char *name, grub_disk_t disk,
+               grub_disk_pull_t pull __attribute__ ((unused)))
 {
   grub_scsi_dev_t p;
   grub_scsi_t scsi;
index d6dc2c22d6a1c89223189e364dea74a157083c28..929f44587f3c774e0ec4c5d41f58c2008e5be9af 100644 (file)
@@ -104,8 +104,12 @@ grub_pxe_scan (void)
 }
 
 static int
-grub_pxe_iterate (int (*hook) (const char *name))
+grub_pxe_iterate (int (*hook) (const char *name),
+                 grub_disk_pull_t pull)
 {
+  if (pull != GRUB_DISK_PULL_NONE)
+    return 0;
+
   if (hook ("pxe"))
     return 1;
   return 0;
@@ -139,7 +143,8 @@ parse_ip (const char *val, grub_uint32_t *ip, const char **rest)
 }
 
 static grub_err_t
-grub_pxe_open (const char *name, grub_disk_t disk)
+grub_pxe_open (const char *name, grub_disk_t disk,
+              grub_disk_pull_t pull __attribute__ ((unused)))
 {
   struct grub_pxe_disk_data *data;
 
index 807ee4277b1048b4901f5b6fb76d9f46230ad9c4..9c2c70b80c1a43be5c62150863e30314e7800c95 100644 (file)
@@ -207,10 +207,16 @@ int
 grub_disk_dev_iterate (int (*hook) (const char *name))
 {
   grub_disk_dev_t p;
+  grub_disk_pull_t pull;
 
-  for (p = grub_disk_dev_list; p; p = p->next)
-    if (p->iterate && (p->iterate) (hook))
-      return 1;
+  for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
+    {
+      if (pull == GRUB_DISK_PULL_RESCAN_UNTYPED)
+       continue;
+      for (p = grub_disk_dev_list; p; p = p->next)
+       if (p->iterate && (p->iterate) (hook, pull))
+         return 1;
+    }
 
   return 0;
 }
@@ -241,6 +247,7 @@ grub_disk_open (const char *name)
   grub_disk_dev_t dev;
   char *raw = (char *) name;
   grub_uint64_t current_time;
+  grub_disk_pull_t pull;
 
   grub_dprintf ("disk", "Opening `%s'...\n", name);
 
@@ -266,15 +273,19 @@ grub_disk_open (const char *name)
   if (! disk->name)
     goto fail;
 
-
-  for (dev = grub_disk_dev_list; dev; dev = dev->next)
+  for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
     {
-      if ((dev->open) (raw, disk) == GRUB_ERR_NONE)
+      for (dev = grub_disk_dev_list; dev; dev = dev->next)
+       {
+         if ((dev->open) (raw, disk, pull) == GRUB_ERR_NONE)
+           break;
+         else if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
+           grub_errno = GRUB_ERR_NONE;
+         else
+           goto fail;
+       }
+      if (dev)
        break;
-      else if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
-       grub_errno = GRUB_ERR_NONE;
-      else
-       goto fail;
     }
 
   if (! dev)
index 63bca37ee76f84a638ccf40576c97e00a05e3473..3ee6174d04304ba7a8e1173d9df8714defffb9ef 100644 (file)
@@ -212,7 +212,8 @@ find_free_slot (void)
 }
 
 static int
-grub_util_biosdisk_iterate (int (*hook) (const char *name))
+grub_util_biosdisk_iterate (int (*hook) (const char *name),
+                           grub_disk_pull_t pull)
 {
   unsigned i;
 
@@ -224,7 +225,8 @@ grub_util_biosdisk_iterate (int (*hook) (const char *name))
 }
 
 static grub_err_t
-grub_util_biosdisk_open (const char *name, grub_disk_t disk)
+grub_util_biosdisk_open (const char *name, grub_disk_t disk,
+                        grub_disk_pull_t pull __attribute__ ((unused)))
 {
   int drive;
   struct stat st;
index 66db1149a4394810d29ebce9c35cbfb5169a2341..2678ad5eb6e7629011db63ba5b2d23a77cb74256 100644 (file)
@@ -50,6 +50,15 @@ struct grub_disk;
 struct grub_disk_memberlist;
 #endif
 
+typedef enum
+  { 
+    GRUB_DISK_PULL_NONE,
+    GRUB_DISK_PULL_REMOVABLE,
+    GRUB_DISK_PULL_RESCAN,
+    GRUB_DISK_PULL_RESCAN_UNTYPED,
+    GRUB_DISK_PULL_MAX
+  } grub_disk_pull_t;
+
 /* Disk device.  */
 struct grub_disk_dev
 {
@@ -60,10 +69,12 @@ struct grub_disk_dev
   enum grub_disk_dev_id id;
 
   /* Call HOOK with each device name, until HOOK returns non-zero.  */
-  int (*iterate) (int (*hook) (const char *name));
+  int (*iterate) (int (*hook) (const char *name),
+                 grub_disk_pull_t pull);
 
   /* Open the device named NAME, and set up DISK.  */
-  grub_err_t (*open) (const char *name, struct grub_disk *disk);
+  grub_err_t (*open) (const char *name, struct grub_disk *disk,
+                     grub_disk_pull_t pull);
 
   /* Close the disk DISK.  */
   void (*close) (struct grub_disk *disk);
index d5853639d53edda619f8829fe5ac8b0afa727335..1eb43721af948c016c85bfb8320a08c75989a1a5 100644 (file)
@@ -42,6 +42,7 @@ struct grub_raid_array
   int number;              /* The device number, taken from md_minor so we
                              are consistent with the device name in
                              Linux. */
+  int became_readable_at;
   int level;               /* RAID levels, only 0, 1 or 5 at the moment. */
   int layout;              /* Layout for RAID 5/6.  */
   unsigned int total_devs; /* Total number of devices in the array. */