merge lazy into luks

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-04-22 15:13:12 +02:00
commit 0aaa85f1a0
23 changed files with 542 additions and 193 deletions

View file

@ -10,6 +10,7 @@ library = {
common = grub-core/kern/device.c; common = grub-core/kern/device.c;
common = grub-core/kern/disk.c; common = grub-core/kern/disk.c;
common = grub-core/kern/emu/getroot.c; common = grub-core/kern/emu/getroot.c;
common = grub-core/kern/emu/raid.c;
common = grub-core/kern/emu/hostdisk.c; common = grub-core/kern/emu/hostdisk.c;
common = grub-core/kern/emu/misc.c; common = grub-core/kern/emu/misc.c;
common = grub-core/kern/emu/mm.c; common = grub-core/kern/emu/mm.c;
@ -265,7 +266,6 @@ program = {
installdir = sbin; installdir = sbin;
mansection = 8; mansection = 8;
common = util/grub-setup.c; common = util/grub-setup.c;
common = util/raid.c;
common = util/lvm.c; common = util/lvm.c;
common = grub-core/lib/reed_solomon.c; common = grub-core/lib/reed_solomon.c;

View file

@ -165,6 +165,7 @@ kernel = {
emu = kern/emu/cache.S; emu = kern/emu/cache.S;
emu = kern/emu/console.c; emu = kern/emu/console.c;
emu = kern/emu/getroot.c; emu = kern/emu/getroot.c;
emu = kern/emu/raid.c;
emu = kern/emu/hostdisk.c; emu = kern/emu/hostdisk.c;
emu = kern/emu/hostfs.c; emu = kern/emu/hostfs.c;
emu = kern/emu/main.c; emu = kern/emu/main.c;

View file

@ -666,10 +666,14 @@ grub_ata_readwrite (grub_disk_t disk, grub_disk_addr_t sector,
static int 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; struct grub_ata_device *dev;
if (pull != GRUB_DISK_PULL_NONE)
return 0;
for (dev = grub_ata_devices; dev; dev = dev->next) for (dev = grub_ata_devices; dev; dev = dev->next)
{ {
char devname[10]; char devname[10];
@ -696,7 +700,8 @@ grub_ata_iterate (int (*hook) (const char *name))
} }
static grub_err_t 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; struct grub_ata_device *dev;
grub_err_t err; grub_err_t err;

View file

@ -27,15 +27,20 @@
int grub_disk_host_i_want_a_reference; int grub_disk_host_i_want_a_reference;
static int 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")) if (hook ("host"))
return 1; return 1;
return 0; return 0;
} }
static grub_err_t 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")) if (grub_strcmp (name, "host"))
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a host disk"); return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a host disk");

View file

@ -284,42 +284,52 @@ grub_biosdisk_call_hook (int (*hook) (const char *name), int drive)
} }
static int 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 num_floppies;
int drive;
/* For hard disks, attempt to read the MBR. */ /* 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, case GRUB_DISK_PULL_NONE:
GRUB_MEMORY_MACHINE_SCRATCH_SEG) != 0) for (drive = 0x80; drive < 0x90; drive++)
{ {
grub_dprintf ("disk", "Read error when probing drive 0x%2x\n", drive); if (grub_biosdisk_rw_standard (0x02, drive, 0, 0, 1, 1,
break; 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;
case GRUB_DISK_PULL_REMOVABLE:
if (cd_drive)
{
if (grub_biosdisk_call_hook (hook, cd_drive))
return 1;
} }
if (grub_biosdisk_call_hook (hook, drive)) /* For floppy disks, we can get the number safely. */
return 1; 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;
} }
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; return 0;
} }
static grub_err_t 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; grub_uint64_t total_sectors = 0;
int drive; int drive;

View file

@ -133,9 +133,12 @@ fail:
static int 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; struct grub_loopback *d;
if (pull != GRUB_DISK_PULL_NONE)
return 0;
for (d = loopback_list; d; d = d->next) for (d = loopback_list; d; d = d->next)
{ {
if (hook (d->devname)) if (hook (d->devname))
@ -145,7 +148,8 @@ grub_loopback_iterate (int (*hook) (const char *name))
} }
static grub_err_t 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; struct grub_loopback *dev;

View file

@ -498,10 +498,14 @@ grub_luks_scan_device (const char *name)
} }
static int static int
grub_luks_iterate (int (*hook) (const char *name)) grub_luks_iterate (int (*hook) (const char *name),
grub_disk_pull_t pull)
{ {
grub_luks_t i; grub_luks_t i;
if (pull != GRUB_DISK_PULL_NONE)
return 0;
for (i = luks_list; i != NULL; i = i->next) for (i = luks_list; i != NULL; i = i->next)
{ {
char buf[30]; char buf[30];
@ -514,7 +518,8 @@ grub_luks_iterate (int (*hook) (const char *name))
} }
static grub_err_t static grub_err_t
grub_luks_open (const char *name, grub_disk_t disk) grub_luks_open (const char *name, grub_disk_t disk,
grub_disk_pull_t pull __attribute__ ((unused)))
{ {
grub_luks_t dev; grub_luks_t dev;

View file

@ -26,13 +26,19 @@
#ifdef GRUB_UTIL #ifdef GRUB_UTIL
#include <grub/emu/misc.h> #include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
#endif #endif
GRUB_MOD_LICENSE ("GPLv3+"); GRUB_MOD_LICENSE ("GPLv3+");
static struct grub_lvm_vg *vg_list; static struct grub_lvm_vg *vg_list;
static int lv_count; 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);
/* Go the string STR and return the number after STR. *P will point /* 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 at the number. In case STR is not found, *P will be NULL and the
@ -96,16 +102,36 @@ grub_lvm_check_flag (char *p, char *str, char *flag)
} }
static int 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; 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) for (vg = vg_list; vg; vg = vg->next)
{ {
struct grub_lvm_lv *lv; struct grub_lvm_lv *lv;
if (vg->lvs) if (vg->lvs)
for (lv = vg->lvs; lv; lv = lv->next) for (lv = vg->lvs; lv; lv = lv->next)
if (lv->visible && hook (lv->name)) if (lv->visible && lv->number >= old_count)
return 1; {
if (hook (lv->fullname))
return 1;
}
} }
return 0; return 0;
@ -135,8 +161,8 @@ grub_lvm_memberlist (grub_disk_t disk)
} }
#endif #endif
static grub_err_t static struct grub_lvm_lv *
grub_lvm_open (const char *name, grub_disk_t disk) find_lv (const char *name)
{ {
struct grub_lvm_vg *vg; struct grub_lvm_vg *vg;
struct grub_lvm_lv *lv = NULL; struct grub_lvm_lv *lv = NULL;
@ -144,11 +170,42 @@ grub_lvm_open (const char *name, grub_disk_t disk)
{ {
if (vg->lvs) if (vg->lvs)
for (lv = vg->lvs; lv; lv = lv->next) for (lv = vg->lvs; lv; lv = lv->next)
if (! grub_strcmp (lv->name, name)) if ((grub_strcmp (lv->fullname, name) == 0
break; || grub_strcmp (lv->compatname, name) == 0)
&& is_lv_readable (lv))
return lv;
}
return NULL;
}
if (lv) static const char *scan_for = NULL;
break;
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)
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) if (! lv)
@ -285,6 +342,49 @@ read_lv (struct grub_lvm_lv *lv, grub_disk_addr_t sector,
return grub_error (GRUB_ERR_IO, "unknown LVM segment"); 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 static grub_err_t
grub_lvm_read (grub_disk_t disk, grub_disk_addr_t sector, grub_lvm_read (grub_disk_t disk, grub_disk_addr_t sector,
grub_size_t size, char *buf) grub_size_t size, char *buf)
@ -332,6 +432,15 @@ grub_lvm_scan_device (const char *name)
return 0; 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. */ /* Search for label. */
for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++) for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++)
{ {
@ -573,11 +682,43 @@ grub_lvm_scan_device (const char *name)
q++; q++;
s = q - p; s = q - p;
lv->name = grub_malloc (vgname_len + 1 + s + 1); lv->name = grub_strndup (p, s);
grub_memcpy (lv->name, vgname, vgname_len); if (!lv->name)
lv->name[vgname_len] = '-'; goto lvs_fail;
grub_memcpy (lv->name + vgname_len + 1, p, s); lv->compatname = grub_malloc (vgname_len + 1 + s + 1);
lv->name[vgname_len + 1 + s] = '\0'; if (!lv->compatname)
goto lvs_fail;
grub_memcpy (lv->compatname, vgname, vgname_len);
lv->compatname[vgname_len] = '-';
grub_memcpy (lv->compatname + vgname_len + 1, p, s);
lv->compatname[vgname_len + 1 + s] = '\0';
{
const char *iptr;
char *optr;
lv->fullname = grub_malloc (sizeof("lvm/") + 2 * vgname_len
+ 1 + 2 * s + 1);
if (!lv->fullname)
goto lvs_fail;
optr = lv->fullname;
grub_memcpy (optr, "lvm/", sizeof ("lvm/") - 1);
optr += sizeof ("lvm/") - 1;
for (iptr = vgname; iptr < vgname + vgname_len; iptr++)
{
*optr++ = *iptr;
if (*iptr == '-')
*optr++ = '-';
}
*optr++ = '-';
for (iptr = p; iptr < p + s; iptr++)
{
*optr++ = *iptr;
if (*iptr == '-')
*optr++ = '-';
}
*optr++ = 0;
}
lv->size = 0; lv->size = 0;
@ -857,6 +998,8 @@ grub_lvm_scan_device (const char *name)
if (grub_errno == GRUB_ERR_OUT_OF_RANGE) if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
grub_errno = GRUB_ERR_NONE; grub_errno = GRUB_ERR_NONE;
grub_print_error (); grub_print_error ();
if (scan_for && find_lv (scan_for))
return 1;
return 0; return 0;
} }
@ -878,13 +1021,6 @@ static struct grub_disk_dev grub_lvm_dev =
GRUB_MOD_INIT(lvm) 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); grub_disk_dev_register (&grub_lvm_dev);
} }

View file

@ -30,13 +30,18 @@ static char *memdisk_addr;
static grub_off_t memdisk_size = 0; static grub_off_t memdisk_size = 0;
static int 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"); return hook ("memdisk");
} }
static grub_err_t 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")) if (grub_strcmp (name, "memdisk"))
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a memdisk"); return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a memdisk");

View file

@ -33,6 +33,11 @@ GRUB_MOD_LICENSE ("GPLv3+");
static struct grub_raid_array *array_list; static struct grub_raid_array *array_list;
grub_raid5_recover_func_t grub_raid5_recover_func; grub_raid5_recover_func_t grub_raid5_recover_func;
grub_raid6_recover_func_t grub_raid6_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);
static char static char
@ -78,14 +83,98 @@ grub_is_array_readable (struct grub_raid_array *array)
return 0; 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 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; 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) 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)) if (hook (array->name))
return 1; return 1;
} }
@ -134,11 +223,10 @@ ascii2hex (char c)
return 0; return 0;
} }
static grub_err_t static struct grub_raid_array *
grub_raid_open (const char *name, grub_disk_t disk) find_array (const char *name)
{ {
struct grub_raid_array *array; struct grub_raid_array *array;
unsigned n;
if (grub_memcmp (name, "mduuid/", sizeof ("mduuid/") - 1) == 0) 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 if (uuid_len == (unsigned) array->uuid_len
&& grub_memcmp (uuidbin, array->uuid, uuid_len) == 0) && grub_memcmp (uuidbin, array->uuid, uuid_len) == 0)
if (grub_is_array_readable (array)) if (grub_is_array_readable (array))
break; return array;
} }
} }
else else
@ -163,8 +251,33 @@ grub_raid_open (const char *name, grub_disk_t disk)
{ {
if (!grub_strcmp (array->name, name)) if (!grub_strcmp (array->name, name))
if (grub_is_array_readable (array)) 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) if (!array)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s", 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. */ /* Add the device to the array. */
array->members[new_array->index].device = disk; {
array->members[new_array->index].start_sector = start_sector; int was_readable = grub_is_array_readable (array);
array->nr_devs++;
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; return 0;
} }
static grub_raid_t grub_raid_list;
static void static void
free_array (void) free_array (void)
{ {
@ -729,45 +846,8 @@ free_array (void)
void void
grub_raid_register (grub_raid_t raid) 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; raid->next = grub_raid_list;
grub_raid_list = raid; grub_raid_list = raid;
grub_device_iterate (&hook);
} }
void void

View file

@ -316,7 +316,8 @@ grub_scsi_write12 (grub_disk_t disk, grub_disk_addr_t sector,
static int 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; grub_scsi_dev_t p;
@ -356,6 +357,9 @@ grub_scsi_iterate (int (*hook) (const char *name))
return 0; return 0;
} }
if (pull != GRUB_DISK_PULL_NONE)
return 0;
for (p = grub_scsi_dev_list; p; p = p->next) for (p = grub_scsi_dev_list; p; p = p->next)
if (p->iterate && (p->iterate) (scsi_iterate)) if (p->iterate && (p->iterate) (scsi_iterate))
return 1; return 1;
@ -364,7 +368,8 @@ grub_scsi_iterate (int (*hook) (const char *name))
} }
static grub_err_t 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_dev_t p;
grub_scsi_t scsi; grub_scsi_t scsi;

View file

@ -104,8 +104,12 @@ grub_pxe_scan (void)
} }
static int 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")) if (hook ("pxe"))
return 1; return 1;
return 0; return 0;
@ -139,7 +143,8 @@ parse_ip (const char *val, grub_uint32_t *ip, const char **rest)
} }
static grub_err_t 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; struct grub_pxe_disk_data *data;

View file

@ -207,10 +207,16 @@ int
grub_disk_dev_iterate (int (*hook) (const char *name)) grub_disk_dev_iterate (int (*hook) (const char *name))
{ {
grub_disk_dev_t p; grub_disk_dev_t p;
grub_disk_pull_t pull;
for (p = grub_disk_dev_list; p; p = p->next) for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
if (p->iterate && (p->iterate) (hook)) {
return 1; 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; return 0;
} }
@ -241,6 +247,7 @@ grub_disk_open (const char *name)
grub_disk_dev_t dev; grub_disk_dev_t dev;
char *raw = (char *) name; char *raw = (char *) name;
grub_uint64_t current_time; grub_uint64_t current_time;
grub_disk_pull_t pull;
grub_dprintf ("disk", "Opening `%s'...\n", name); grub_dprintf ("disk", "Opening `%s'...\n", name);
@ -266,15 +273,19 @@ grub_disk_open (const char *name)
if (! disk->name) if (! disk->name)
goto fail; goto fail;
for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
for (dev = grub_disk_dev_list; dev; dev = dev->next)
{ {
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; break;
else if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
grub_errno = GRUB_ERR_NONE;
else
goto fail;
} }
if (! dev) if (! dev)

View file

@ -640,6 +640,56 @@ grub_guess_root_device (const char *dir)
return os_dev; return os_dev;
} }
#ifdef HAVE_DEVICE_MAPPER
static int
grub_util_open_dm (const char *os_dev, struct dm_tree **tree,
struct dm_tree_node **node)
{
uint32_t maj, min;
struct stat st;
*node = NULL;
*tree = NULL;
if ((strncmp ("/dev/mapper/", os_dev, 12) != 0))
return 0;
if (stat (os_dev, &st) < 0)
return 0;
*tree = dm_tree_create ();
if (! *tree)
{
grub_printf ("Failed to create tree\n");
grub_dprintf ("hostdisk", "dm_tree_create failed\n");
return 0;
}
maj = major (st.st_rdev);
min = minor (st.st_rdev);
if (! dm_tree_add_dev (*tree, maj, min))
{
grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n");
dm_tree_free (*tree);
*tree = NULL;
return 0;
}
*node = dm_tree_find_node (*tree, maj, min);
if (! *node)
{
grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
dm_tree_free (*tree);
*tree = NULL;
return 0;
}
return 1;
}
#endif
static char * static char *
get_dm_uuid (const char *os_dev) get_dm_uuid (const char *os_dev)
{ {
@ -649,40 +699,13 @@ get_dm_uuid (const char *os_dev)
#ifdef HAVE_DEVICE_MAPPER #ifdef HAVE_DEVICE_MAPPER
{ {
struct dm_tree *tree; struct dm_tree *tree;
uint32_t maj, min; struct dm_tree_node *node;
struct dm_tree_node *node = NULL;
const char *node_uuid; const char *node_uuid;
char *ret; char *ret;
struct stat st;
if (stat (os_dev, &st) < 0) if (!grub_util_open_dm (os_dev, &tree, &node))
return NULL; return NULL;
tree = dm_tree_create ();
if (! tree)
{
grub_printf ("Failed to create tree\n");
grub_dprintf ("hostdisk", "dm_tree_create failed\n");
return NULL;
}
maj = major (st.st_rdev);
min = minor (st.st_rdev);
if (! dm_tree_add_dev (tree, maj, min))
{
grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n");
dm_tree_free (tree);
return NULL;
}
node = dm_tree_find_node (tree, maj, min);
if (! node)
{
grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
dm_tree_free (tree);
return NULL;
}
node_uuid = dm_tree_node_get_uuid (node); node_uuid = dm_tree_node_get_uuid (node);
if (! node_uuid) if (! node_uuid)
{ {
@ -692,18 +715,22 @@ get_dm_uuid (const char *os_dev)
} }
ret = grub_strdup (node_uuid); ret = grub_strdup (node_uuid);
dm_tree_free (tree); dm_tree_free (tree);
return ret; return ret;
} }
#else #endif
return NULL; return NULL;
#endif /* HAVE_DEVICE_MAPPER */
} }
static enum grub_dev_abstraction_types static enum grub_dev_abstraction_types
grub_util_get_dm_abstraction (const char *os_dev) grub_util_get_dm_abstraction (const char *os_dev)
{ {
#ifdef HAVE_DEVICE_MAPPER
char *uuid; char *uuid;
uuid = get_dm_uuid (os_dev); uuid = get_dm_uuid (os_dev);
if (uuid == NULL) if (uuid == NULL)
@ -722,6 +749,11 @@ grub_util_get_dm_abstraction (const char *os_dev)
grub_free (uuid); grub_free (uuid);
return GRUB_DEV_ABSTRACTION_NONE; return GRUB_DEV_ABSTRACTION_NONE;
#else
if ((strncmp ("/dev/mapper/", os_dev, 12) != 0))
return GRUB_DEV_ABSTRACTION_NONE;
return GRUB_DEV_ABSTRACTION_LVM;
#endif
} }
int int
@ -830,11 +862,62 @@ out:
} }
#endif /* __linux__ */ #endif /* __linux__ */
void
grub_util_pull_device (const char *os_dev)
{
switch (grub_util_get_dev_abstraction (os_dev))
{
case GRUB_DEV_ABSTRACTION_LVM:
case GRUB_DEV_ABSTRACTION_LUKS:
#ifdef HAVE_DEVICE_MAPPER
{
struct dm_tree *tree;
struct dm_tree_node *node;
struct dm_tree_node *child;
void *handle = NULL;
if (!grub_util_open_dm (os_dev, &tree, &node))
return;
while ((child = dm_tree_next_child (&handle, node, 0)))
{
const struct dm_info *dm = dm_tree_node_get_info (child);
char *subdev;
if (!dm)
continue;
subdev = grub_find_device ("/dev", makedev (dm->major, dm->minor));
if (subdev)
grub_util_pull_device (subdev);
}
dm_tree_free (tree);
}
#endif
return;
case GRUB_DEV_ABSTRACTION_RAID:
#ifdef __linux__
{
char **devicelist = grub_util_raid_getmembers (os_dev, 0);
int i;
for (i = 0; devicelist[i];i++)
grub_util_pull_device (devicelist[i]);
free (devicelist);
}
#endif
return;
default: /* GRUB_DEV_ABSTRACTION_NONE */
grub_util_biosdisk_get_grub_dev (os_dev);
return;
}
}
char * char *
grub_util_get_grub_dev (const char *os_dev) grub_util_get_grub_dev (const char *os_dev)
{ {
char *grub_dev = NULL; char *grub_dev = NULL;
grub_util_pull_device (os_dev);
switch (grub_util_get_dev_abstraction (os_dev)) switch (grub_util_get_dev_abstraction (os_dev))
{ {
case GRUB_DEV_ABSTRACTION_LVM: case GRUB_DEV_ABSTRACTION_LVM:
@ -844,14 +927,10 @@ grub_util_get_grub_dev (const char *os_dev)
grub_size_t offset = sizeof ("/dev/mapper/") - 1; grub_size_t offset = sizeof ("/dev/mapper/") - 1;
len = strlen (os_dev) - offset + 1; len = strlen (os_dev) - offset + 1;
grub_dev = xmalloc (len); grub_dev = xmalloc (len + sizeof ("lvm/"));
for (i = 0; i < len; i++, offset++) grub_memcpy (grub_dev, "lvm/", sizeof ("lvm/") - 1);
{ grub_memcpy (grub_dev + sizeof ("lvm/") - 1, os_dev + offset, len);
grub_dev[i] = os_dev[offset];
if (os_dev[offset] == '-' && os_dev[offset + 1] == '-')
offset++;
}
} }
break; break;

View file

@ -213,7 +213,8 @@ find_free_slot (void)
} }
static int 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; unsigned i;
@ -225,7 +226,8 @@ grub_util_biosdisk_iterate (int (*hook) (const char *name))
} }
static grub_err_t 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; int drive;
struct stat st; struct stat st;

View file

@ -21,7 +21,6 @@
#ifdef __linux__ #ifdef __linux__
#include <grub/emu/misc.h> #include <grub/emu/misc.h>
#include <grub/util/misc.h> #include <grub/util/misc.h>
#include <grub/util/raid.h>
#include <grub/emu/getroot.h> #include <grub/emu/getroot.h>
#include <string.h> #include <string.h>
@ -36,7 +35,7 @@
#include <linux/raid/md_u.h> #include <linux/raid/md_u.h>
char ** char **
grub_util_raid_getmembers (const char *name) grub_util_raid_getmembers (const char *name, int bootable)
{ {
int fd, ret, i, j; int fd, ret, i, j;
char **devicelist; char **devicelist;
@ -53,7 +52,14 @@ grub_util_raid_getmembers (const char *name)
if (ret != 0) if (ret != 0)
grub_util_error ("ioctl RAID_VERSION error: %s", strerror (errno)); grub_util_error ("ioctl RAID_VERSION error: %s", strerror (errno));
if (version.major != 0 || version.minor != 90) if ((version.major != 0 || version.minor != 90)
&& (version.major != 1 || version.minor != 0)
&& (version.major != 1 || version.minor != 1)
&& (version.major != 1 || version.minor != 2))
grub_util_error ("unsupported RAID version: %d.%d",
version.major, version.minor);
if (bootable && (version.major != 0 || version.minor != 90))
grub_util_error ("unsupported RAID version: %d.%d", grub_util_error ("unsupported RAID version: %d.%d",
version.major, version.minor); version.major, version.minor);

View file

@ -50,6 +50,15 @@ struct grub_disk;
struct grub_disk_memberlist; struct grub_disk_memberlist;
#endif #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. */ /* Disk device. */
struct grub_disk_dev struct grub_disk_dev
{ {
@ -60,10 +69,12 @@ struct grub_disk_dev
enum grub_disk_dev_id id; enum grub_disk_dev_id id;
/* Call HOOK with each device name, until HOOK returns non-zero. */ /* 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. */ /* 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. */ /* Close the disk DISK. */
void (*close) (struct grub_disk *disk); void (*close) (struct grub_disk *disk);

View file

@ -35,5 +35,8 @@ char *grub_util_get_grub_dev (const char *os_dev);
char *grub_make_system_path_relative_to_its_root (const char *path); char *grub_make_system_path_relative_to_its_root (const char *path);
const char *grub_util_check_block_device (const char *blk_dev); const char *grub_util_check_block_device (const char *blk_dev);
const char *grub_util_check_char_device (const char *blk_dev); const char *grub_util_check_char_device (const char *blk_dev);
#ifdef __linux__
char **grub_util_raid_getmembers (const char *name, int bootable);
#endif
#endif /* ! GRUB_UTIL_GETROOT_HEADER */ #endif /* ! GRUB_UTIL_GETROOT_HEADER */

View file

@ -29,5 +29,6 @@ const char *grub_util_biosdisk_get_osdev (grub_disk_t disk);
int grub_util_biosdisk_is_present (const char *name); int grub_util_biosdisk_is_present (const char *name);
int grub_util_biosdisk_is_floppy (grub_disk_t disk); int grub_util_biosdisk_is_floppy (grub_disk_t disk);
grub_err_t grub_util_biosdisk_flush (struct grub_disk *disk); grub_err_t grub_util_biosdisk_flush (struct grub_disk *disk);
void grub_util_pull_device (const char *osname);
#endif /* ! GRUB_BIOSDISK_MACHINE_UTIL_HEADER */ #endif /* ! GRUB_BIOSDISK_MACHINE_UTIL_HEADER */

View file

@ -44,6 +44,8 @@ struct grub_lvm_pv {
struct grub_lvm_lv { struct grub_lvm_lv {
char *name; char *name;
char *fullname;
char *compatname;
unsigned int number; unsigned int number;
unsigned int segment_count; unsigned int segment_count;
grub_uint64_t size; grub_uint64_t size;

View file

@ -42,6 +42,7 @@ struct grub_raid_array
int number; /* The device number, taken from md_minor so we int number; /* The device number, taken from md_minor so we
are consistent with the device name in are consistent with the device name in
Linux. */ Linux. */
int became_readable_at;
int level; /* RAID levels, only 0, 1 or 5 at the moment. */ int level; /* RAID levels, only 0, 1 or 5 at the moment. */
int layout; /* Layout for RAID 5/6. */ int layout; /* Layout for RAID 5/6. */
unsigned int total_devs; /* Total number of devices in the array. */ unsigned int total_devs; /* Total number of devices in the array. */

View file

@ -1,27 +0,0 @@
/* raid.h - RAID support for GRUB utils. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2006,2007 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GRUB_RAID_UTIL_HEADER
#define GRUB_RAID_UTIL_HEADER 1
#ifdef __linux__
char** grub_util_raid_getmembers (const char *name);
#endif
#endif /* ! GRUB_RAID_UTIL_HEADER */

View file

@ -32,7 +32,6 @@
#include <grub/machine/kernel.h> #include <grub/machine/kernel.h>
#include <grub/term.h> #include <grub/term.h>
#include <grub/i18n.h> #include <grub/i18n.h>
#include <grub/util/raid.h>
#include <grub/util/lvm.h> #include <grub/util/lvm.h>
#ifdef GRUB_MACHINE_IEEE1275 #ifdef GRUB_MACHINE_IEEE1275
#include <grub/util/ofpath.h> #include <grub/util/ofpath.h>
@ -972,12 +971,12 @@ main (int argc, char *argv[])
int i; int i;
if (arguments.device[0] == '/') if (arguments.device[0] == '/')
devicelist = grub_util_raid_getmembers (arguments.device); devicelist = grub_util_raid_getmembers (arguments.device, 1);
else else
{ {
char *devname; char *devname;
devname = xasprintf ("/dev/%s", dest_dev); devname = xasprintf ("/dev/%s", dest_dev);
devicelist = grub_util_raid_getmembers (dest_dev); devicelist = grub_util_raid_getmembers (dest_dev, 1);
free (devname); free (devname);
} }