\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];
}
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;
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");
}
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;
\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))
}
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;
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
}
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;
}
#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;
{
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)
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)
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++)
{
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;
}
\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);
}
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");
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
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;
}
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)
{
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
{
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",
}
/* 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)
{
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
\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;
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;
}
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;
}
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;
}
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;
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;
}
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);
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)
}
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;
}
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;
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
{
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);
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. */