Lazy LVM and RAID assembly
This commit is contained in:
parent
9b710a888e
commit
24b905a11c
13 changed files with 365 additions and 114 deletions
|
@ -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);
|
||||
|
||||
/* 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 =
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue