From: "Vladimir 'φ-coder/phcoder' Serbinenko" <phcoder@gmail.com>
To: The development of GRUB 2 <grub-devel@gnu.org>
Subject: Unify raid and lvm handling
Date: Sat, 28 Jan 2012 15:36:51 +0100 [thread overview]
Message-ID: <4F240803.70202@gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 137 bytes --]
Unify RAID and LVM into one unifomr "diskfilter" similar to
device-mapper or geom.
--
Regards
Vladimir 'φ-coder/phcoder' Serbinenko
[-- Attachment #2: diskfilter.diff --]
[-- Type: text/x-diff, Size: 199290 bytes --]
=== modified file 'Makefile.util.def'
--- Makefile.util.def 2012-01-24 12:17:36 +0000
+++ Makefile.util.def 2012-01-28 13:51:46 +0000
@@ -29,6 +29,9 @@
common = grub-core/lib/pbkdf2.c;
common = grub-core/commands/extcmd.c;
common = grub-core/lib/arg.c;
+ common = grub-core/disk/ldm.c;
+ common = grub-core/disk/diskfilter.c;
+ common = grub-core/partmap/gpt.c;
};
library = {
@@ -53,7 +56,6 @@
common = grub-core/disk/mdraid1x_linux.c;
common = grub-core/disk/raid5_recover.c;
common = grub-core/disk/raid6_recover.c;
- common = grub-core/disk/raid.c;
common = grub-core/fs/affs.c;
common = grub-core/fs/afs.c;
common = grub-core/fs/bfs.c;
@@ -103,7 +105,6 @@
common = grub-core/partmap/acorn.c;
common = grub-core/partmap/amiga.c;
common = grub-core/partmap/apple.c;
- common = grub-core/partmap/gpt.c;
common = grub-core/partmap/msdos.c;
common = grub-core/partmap/sun.c;
common = grub-core/partmap/plan.c;
=== modified file 'grub-core/Makefile.core.def'
--- grub-core/Makefile.core.def 2012-01-27 12:52:48 +0000
+++ grub-core/Makefile.core.def 2012-01-28 13:51:46 +0000
@@ -875,6 +875,11 @@
};
module = {
+ name = ldm;
+ common = disk/ldm.c;
+};
+
+module = {
name = mdraid09;
common = disk/mdraid_linux.c;
};
@@ -885,8 +890,8 @@
};
module = {
- name = raid;
- common = disk/raid.c;
+ name = diskfilter;
+ common = disk/diskfilter.c;
};
module = {
=== renamed file 'grub-core/disk/raid.c' => 'grub-core/disk/diskfilter.c'
--- grub-core/disk/raid.c 2012-01-14 10:37:34 +0000
+++ grub-core/disk/diskfilter.c 2012-01-28 14:32:25 +0000
@@ -1,4 +1,4 @@
-/* raid.c - module to read RAID arrays. */
+/* diskfilter.c - module to read RAID arrays. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc.
@@ -22,149 +22,196 @@
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
-#include <grub/raid.h>
+#include <grub/diskfilter.h>
#include <grub/partition.h>
#ifdef GRUB_UTIL
+#include <grub/i18n.h>
#include <grub/util/misc.h>
#endif
GRUB_MOD_LICENSE ("GPLv3+");
-/* Linked list of RAID arrays. */
-static struct grub_raid_array *array_list;
+/* Linked list of DISKFILTER arrays. */
+static struct grub_diskfilter_vg *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;
+grub_diskfilter_t grub_diskfilter_list;
static int inscnt = 0;
+static int lv_num = 0;
-static struct grub_raid_array *
-find_array (const char *name);
+static struct grub_diskfilter_lv *
+find_lv (const char *name);
+static int is_lv_readable (struct grub_diskfilter_lv *lv);
\f
-static char
-grub_is_array_readable (struct grub_raid_array *array)
-{
- switch (array->level)
+
+static grub_err_t
+is_node_readable (const struct grub_diskfilter_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_diskfilter_lv *lv)
+{
+ unsigned i, j;
+ if (!lv)
+ return 0;
+ for (i = 0; i < lv->segment_count; i++)
{
- case 0:
- if (array->nr_devs == array->total_devs)
- return 1;
- break;
-
- case 1:
- if (array->nr_devs >= 1)
- return 1;
- break;
-
- case 4:
- case 5:
- case 6:
- case 10:
- {
- unsigned int n;
-
- if (array->level == 10)
- {
- n = array->layout & 0xFF;
- if (n == 1)
- n = (array->layout >> 8) & 0xFF;
-
- n--;
- }
- else
- n = array->level / 3;
-
- if (array->nr_devs >= array->total_devs - n)
- return 1;
-
- break;
- }
+ int need = lv->segments[i].node_count, have = 0;
+ switch (lv->segments[i].type)
+ {
+ case GRUB_DISKFILTER_RAID6:
+ need--;
+ case GRUB_DISKFILTER_RAID4:
+ case GRUB_DISKFILTER_RAID5:
+ need--;
+ case GRUB_DISKFILTER_STRIPED:
+ break;
+
+ case GRUB_DISKFILTER_MIRROR:
+ need = 1;
+ break;
+
+ case GRUB_DISKFILTER_RAID10:
+ {
+ unsigned int n;
+ n = lv->segments[i].layout & 0xFF;
+ if (n == 1)
+ n = (lv->segments[i].layout >> 8) & 0xFF;
+ need = lv->segments[i].node_count - n + 1;
+ }
+ break;
+ }
+ for (j = 0; j < lv->segments[i].node_count; j++)
+ {
+ if (is_node_readable (lv->segments[i].nodes + j))
+ have++;
+ if (have >= need)
+ break;
+ }
+ if (have < need)
+ return 0;
}
- return 0;
+ return 1;
}
static grub_err_t
-insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
+insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id,
+ struct grub_diskfilter_vg *array,
grub_disk_addr_t start_sector, const char *scanner_name,
- grub_raid_t raid __attribute__ ((unused)));
+ grub_diskfilter_t diskfilter __attribute__ ((unused)));
static int scan_depth = 0;
-static void
-scan_devices (const char *arname)
+static int
+scan_disk (const char *name)
{
- grub_raid_t raid;
-
- auto int hook (const char *name);
- int hook (const char *name)
+ auto int hook (grub_disk_t disk, grub_partition_t p);
+ int hook (grub_disk_t disk, grub_partition_t p)
{
- grub_disk_t disk;
- struct grub_raid_array array;
- struct grub_raid_array *arr;
+ struct grub_diskfilter_vg *arr;
grub_disk_addr_t start_sector;
+ struct grub_diskfilter_pv_id id;
+ grub_diskfilter_t diskfilter;
- grub_dprintf ("raid", "Scanning for %s RAID devices on disk %s\n",
- raid->name, name);
+ grub_dprintf ("diskfilter", "Scanning for DISKFILTER devices on disk %s\n",
+ name);
#ifdef GRUB_UTIL
- grub_util_info ("Scanning for %s RAID devices on disk %s",
- raid->name, name);
+ grub_util_info ("Scanning for DISKFILTER devices on disk %s", name);
#endif
- disk = grub_disk_open (name);
- if (!disk)
- return 0;
+ disk->partition = p;
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 == disk->dev->id
- && grub_partition_get_start (m->device->partition)
- == grub_partition_get_start (disk->partition)
- && grub_disk_get_size (m->device)
- == grub_disk_get_size (disk))
- {
- grub_disk_close (disk);
- return 0;
- }
- }
-
- if ((! 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 ();
-
+ struct grub_diskfilter_pv *m;
+ for (m = arr->pvs; m; m = m->next)
+ if (m->disk && m->disk->id == disk->id
+ && m->disk->dev->id == disk->dev->id
+ && m->part_start == grub_partition_get_start (disk->partition)
+ && m->part_size == grub_disk_get_size (disk))
+ return 0;
+ }
+
+ for (diskfilter = grub_diskfilter_list; diskfilter; diskfilter = diskfilter->next)
+ {
+ id.uuid = 0;
+ id.uuidlen = 0;
+ arr = diskfilter->detect (disk, &id, &start_sector);
+ if (arr &&
+ (! insert_array (disk, &id, arr, start_sector, diskfilter->name,
+ diskfilter)))
+ {
+ if (id.uuidlen)
+ grub_free (id.uuid);
+ return 0;
+ }
+ if (arr && id.uuidlen)
+ grub_free (id.uuid);
+
+ /* This error usually means it's not diskfilter, no need to display
+ it. */
+ if (grub_errno != GRUB_ERR_OUT_OF_RANGE)
+ grub_print_error ();
+
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ return 0;
+ }
+ grub_disk_t disk;
+
+ if (scan_depth)
+ return 0;
+
+ disk = grub_disk_open (name);
+ if (!disk)
+ {
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);
+ if (hook (disk, 0))
+ return 1;
+ if (grub_partition_iterate (disk, hook))
+ return 1;
scan_depth--;
+ grub_disk_close (disk);
+ return 0;
+}
+
+static void
+scan_devices (const char *arname)
+{
+ grub_disk_dev_t p;
+ grub_disk_pull_t pull;
+
+ for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
+ for (p = grub_disk_dev_list; p; p = p->next)
+ if (p->id != GRUB_DISK_DEVICE_DISKFILTER_ID
+ && p->iterate)
+ {
+ if ((p->iterate) (scan_disk, pull))
+ return;
+ if (arname && is_lv_readable (find_lv (arname)))
+ return;
+ }
}
static int
-grub_raid_iterate (int (*hook) (const char *name),
+grub_diskfilter_iterate (int (*hook) (const char *name),
grub_disk_pull_t pull)
{
- struct grub_raid_array *array;
+ struct grub_diskfilter_vg *array;
int islcnt = 0;
if (pull == GRUB_DISK_PULL_RESCAN)
@@ -176,11 +223,16 @@
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; array = array->next)
{
- if (grub_is_array_readable (array) && array->became_readable_at >= islcnt)
- if (hook (array->name))
- return 1;
+ struct grub_diskfilter_lv *lv;
+ if (array->lvs)
+ for (lv = array->lvs; lv; lv = lv->next)
+ if (lv->visible && lv->fullname && lv->became_readable_at >= islcnt)
+ {
+ if (hook (lv->fullname))
+ return 1;
+ }
}
return 0;
@@ -188,30 +240,33 @@
#ifdef GRUB_UTIL
static grub_disk_memberlist_t
-grub_raid_memberlist (grub_disk_t disk)
+grub_diskfilter_memberlist (grub_disk_t disk)
{
- struct grub_raid_array *array = disk->data;
+ struct grub_diskfilter_lv *lv = disk->data;
grub_disk_memberlist_t list = NULL, tmp;
- unsigned int i;
+ struct grub_diskfilter_pv *pv;
- for (i = 0; i < array->total_devs; i++)
- if (array->members[i].device)
+ if (lv->vg->pvs)
+ for (pv = lv->vg->pvs; pv; pv = pv->next)
{
- tmp = grub_malloc (sizeof (*tmp));
- tmp->disk = array->members[i].device;
- tmp->next = list;
- list = tmp;
+ if (!pv->disk)
+ grub_util_error (_("Couldn't find PV %s. Check your device.map"),
+ pv->name);
+ tmp = grub_malloc (sizeof (*tmp));
+ tmp->disk = pv->disk;
+ tmp->next = list;
+ list = tmp;
}
return list;
}
static const char *
-grub_raid_getname (struct grub_disk *disk)
+grub_diskfilter_getname (struct grub_disk *disk)
{
- struct grub_raid_array *array = disk->data;
+ struct grub_diskfilter_lv *array = disk->data;
- return array->driver->name;
+ return array->vg->driver->name;
}
#endif
@@ -227,10 +282,11 @@
return 0;
}
-static struct grub_raid_array *
-find_array (const char *name)
+static struct grub_diskfilter_lv *
+find_lv (const char *name)
{
- struct grub_raid_array *array;
+ struct grub_diskfilter_vg *vg;
+ struct grub_diskfilter_lv *lv = NULL;
if (grub_memcmp (name, "mduuid/", sizeof ("mduuid/") - 1) == 0)
{
@@ -241,38 +297,41 @@
for (i = 0; i < uuid_len; i++)
uuidbin[i] = ascii2hex (uuidstr[2 * i + 1])
| (ascii2hex (uuidstr[2 * i]) << 4);
-
- for (array = array_list; array != NULL; array = array->next)
+
+ for (vg = array_list; vg; vg = vg->next)
{
- if (uuid_len == (unsigned) array->uuid_len
- && grub_memcmp (uuidbin, array->uuid, uuid_len) == 0)
- if (grub_is_array_readable (array))
- return array;
+ if (uuid_len == vg->uuid_len
+ && grub_memcmp (uuidbin, vg->uuid, uuid_len) == 0)
+ if (is_lv_readable (vg->lvs))
+ return vg->lvs;
}
}
- else
- for (array = array_list; array != NULL; array = array->next)
- {
- if (!grub_strcmp (array->name, name))
- if (grub_is_array_readable (array))
- return array;
- }
+
+ for (vg = array_list; vg; vg = vg->next)
+ {
+ if (vg->lvs)
+ for (lv = vg->lvs; lv; lv = lv->next)
+ if (lv->fullname && grub_strcmp (lv->fullname, name) == 0
+ && is_lv_readable (lv))
+ return lv;
+ }
return NULL;
}
static grub_err_t
-grub_raid_open (const char *name, grub_disk_t disk)
+grub_diskfilter_open (const char *name, grub_disk_t disk)
{
- struct grub_raid_array *array;
- unsigned n;
+ struct grub_diskfilter_lv *lv;
- if (grub_memcmp (name, "md", sizeof ("md") - 1) != 0)
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
+ if (grub_memcmp (name, "md", sizeof ("md") - 1) != 0
+ && grub_memcmp (name, "lvm/", sizeof ("lvm/") - 1) != 0
+ && grub_memcmp (name, "ldm/", sizeof ("ldm/") - 1) != 0)
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown DISKFILTER device %s",
name);
- array = find_array (name);
+ lv = find_lv (name);
- if (! array)
+ if (! lv)
{
scan_devices (name);
if (grub_errno)
@@ -280,337 +339,385 @@
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
}
- array = find_array (name);
+ lv = find_lv (name);
}
- if (!array)
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
+ if (!lv)
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown DISKFILTER device %s",
name);
- disk->id = array->number;
- disk->data = array;
-
- grub_dprintf ("raid", "%s: total_devs=%d, disk_size=%lld\n", name,
- array->total_devs, (unsigned long long) array->disk_size);
-
- switch (array->level)
- {
- case 1:
- disk->total_sectors = array->disk_size;
- break;
-
- case 10:
- n = array->layout & 0xFF;
- if (n == 1)
- n = (array->layout >> 8) & 0xFF;
-
- disk->total_sectors = grub_divmod64 (array->total_devs *
- array->disk_size,
- n, 0);
- break;
-
- case 0:
- case 4:
- case 5:
- case 6:
- n = array->level / 3;
-
- disk->total_sectors = (array->total_devs - n) * array->disk_size;
- break;
- }
-
- grub_dprintf ("raid", "%s: level=%d, total_sectors=%lld\n", name,
- array->level, (unsigned long long) disk->total_sectors);
+ disk->id = lv->number;
+ disk->data = lv;
+
+ grub_dprintf ("diskfilter", "%s: total_devs=%d, total_size=%lld\n", name,
+ lv->segments ? lv->segments->node_count : 0,
+ (unsigned long long) lv->size);
+ disk->total_sectors = lv->size;
+ grub_dprintf ("diskfilter", "%s: level=%d, total_sectors=%lld\n", name,
+ lv->segments ? lv->segments->type : 0,
+ (unsigned long long) disk->total_sectors);
return 0;
}
static void
-grub_raid_close (grub_disk_t disk __attribute ((unused)))
+grub_diskfilter_close (grub_disk_t disk __attribute ((unused)))
{
return;
}
static grub_err_t
-grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector,
- grub_size_t size, char *buf)
-{
- struct grub_raid_array *array = disk->data;
- grub_err_t err = 0;
-
- switch (array->level)
- {
- case 0:
- case 1:
- case 10:
+read_lv (struct grub_diskfilter_lv *lv, grub_disk_addr_t sector,
+ grub_size_t size, char *buf);
+
+grub_err_t
+grub_diskfilter_read_node (const struct grub_diskfilter_node *node,
+ grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+{
+ /* Check whether we actually know the physical volume we want to
+ read from. */
+ if (node->pv)
+ {
+ if (node->pv->disk)
+ return grub_disk_read (node->pv->disk, sector + node->start
+ + node->pv->start_sector,
+ 0, size << GRUB_DISK_SECTOR_BITS, buf);
+ else
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+ "physical volume %s not found", node->pv->name);
+
+ }
+ if (node->lv)
+ return read_lv (node->lv, sector + node->start, size, buf);
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown node '%s'", node->name);
+}
+
+static grub_err_t
+read_segment (struct grub_diskfilter_segment *seg, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+{
+ grub_err_t err;
+ switch (seg->type)
+ {
+ case GRUB_DISKFILTER_STRIPED:
+ if (seg->node_count == 1)
+ return grub_diskfilter_read_node (&seg->nodes[0],
+ sector, size, buf);
+ case GRUB_DISKFILTER_MIRROR:
+ case GRUB_DISKFILTER_RAID10:
{
- grub_disk_addr_t read_sector, far_ofs;
+ grub_disk_addr_t read_sector, far_ofs;
grub_uint64_t disknr, b, near, far, ofs;
-
- read_sector = grub_divmod64 (sector, array->chunk_size, &b);
- far = ofs = near = 1;
- far_ofs = 0;
-
- if (array->level == 1)
- near = array->total_devs;
- else if (array->level == 10)
- {
- near = array->layout & 0xFF;
- far = (array->layout >> 8) & 0xFF;
- if (array->layout >> 16)
- {
- ofs = far;
- far_ofs = 1;
- }
- else
- far_ofs = grub_divmod64 (array->disk_size,
- far * array->chunk_size, 0);
-
- far_ofs *= array->chunk_size;
- }
-
- read_sector = grub_divmod64 (read_sector * near, array->total_devs,
- &disknr);
-
- ofs *= array->chunk_size;
- read_sector *= ofs;
-
- while (1)
- {
- grub_size_t read_size;
- unsigned int i, j;
-
- read_size = array->chunk_size - b;
- if (read_size > size)
- read_size = size;
-
- for (i = 0; i < near; i++)
- {
- unsigned int k;
-
- k = disknr;
- for (j = 0; j < far; j++)
- {
- if (array->members[k].device)
- {
- if (grub_errno == GRUB_ERR_READ_ERROR)
- grub_errno = GRUB_ERR_NONE;
-
- err = grub_disk_read (array->members[k].device,
- array->members[k].start_sector +
- read_sector + j * far_ofs + b,
- 0,
- read_size << GRUB_DISK_SECTOR_BITS,
- buf);
- if (! err)
- break;
- else if (err != GRUB_ERR_READ_ERROR)
- return err;
- }
- else
- err = grub_error (GRUB_ERR_READ_ERROR,
- "disk missing");
-
- k++;
- if (k == array->total_devs)
- k = 0;
- }
-
- if (! err)
- break;
-
- disknr++;
- if (disknr == array->total_devs)
- {
- disknr = 0;
- read_sector += ofs;
- }
- }
-
- if (err)
- return err;
-
- buf += read_size << GRUB_DISK_SECTOR_BITS;
+ unsigned int i, j;
+
+ read_sector = grub_divmod64 (sector, seg->stripe_size, &b);
+ far = ofs = near = 1;
+ far_ofs = 0;
+
+ if (seg->type == 1)
+ near = seg->node_count;
+ else if (seg->type == 10)
+ {
+ near = seg->layout & 0xFF;
+ far = (seg->layout >> 8) & 0xFF;
+ if (seg->layout >> 16)
+ {
+ ofs = far;
+ far_ofs = 1;
+ }
+ else
+ far_ofs = grub_divmod64 (seg->raid_member_size,
+ far * seg->stripe_size, 0);
+
+ far_ofs *= seg->stripe_size;
+ }
+
+ read_sector = grub_divmod64 (read_sector * near,
+ seg->node_count,
+ &disknr);
+
+ ofs *= seg->stripe_size;
+ read_sector *= ofs;
+
+ while (1)
+ {
+ grub_size_t read_size;
+
+ read_size = seg->stripe_size - b;
+ if (read_size > size)
+ read_size = size;
+
+ for (i = 0; i < near; i++)
+ {
+ unsigned int k;
+
+ k = disknr;
+ for (j = 0; j < far; j++)
+ {
+ if (grub_errno == GRUB_ERR_READ_ERROR
+ || grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
+ grub_errno = GRUB_ERR_NONE;
+
+ err = grub_diskfilter_read_node (&seg->nodes[k],
+ read_sector
+ + j * far_ofs + b,
+ read_size,
+ buf);
+ if (! err)
+ break;
+ else if (err != GRUB_ERR_READ_ERROR
+ && err != GRUB_ERR_UNKNOWN_DEVICE)
+ return err;
+ k++;
+ if (k == seg->node_count)
+ k = 0;
+ }
+
+ if (! err)
+ break;
+
+ disknr++;
+ if (disknr == seg->node_count)
+ {
+ disknr = 0;
+ read_sector += ofs;
+ }
+ }
+
+ if (err)
+ return err;
+
+ buf += read_size << GRUB_DISK_SECTOR_BITS;
size -= read_size;
if (! size)
- break;
-
- b = 0;
- disknr += (near - i);
- while (disknr >= array->total_devs)
- {
- disknr -= array->total_devs;
- read_sector += ofs;
- }
- }
- break;
+ return GRUB_ERR_NONE;
+
+ b = 0;
+ disknr += (near - i);
+ while (disknr >= seg->node_count)
+ {
+ disknr -= seg->node_count;
+ read_sector += ofs;
+ }
+ }
}
+ return GRUB_ERR_NONE;
- case 4:
- case 5:
- case 6:
+ case GRUB_DISKFILTER_RAID4:
+ case GRUB_DISKFILTER_RAID5:
+ case GRUB_DISKFILTER_RAID6:
{
grub_disk_addr_t read_sector;
grub_uint64_t b, p, n, disknr, e;
- /* n = 1 for level 4 and 5, 2 for level 6. */
- n = array->level / 3;
+ /* n = 1 for level 4 and 5, 2 for level 6. */
+ n = seg->type / 3;
/* Find the first sector to read. */
- read_sector = grub_divmod64 (sector, array->chunk_size, &b);
- read_sector = grub_divmod64 (read_sector, array->total_devs - n,
- &disknr);
- if (array->level >= 5)
- {
- grub_divmod64 (read_sector, array->total_devs, &p);
-
- if (! (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK))
- p = array->total_devs - 1 - p;
-
- if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
- {
- disknr += p + n;
- }
- else
- {
- grub_uint32_t q;
-
- q = p + (n - 1);
- if (q >= array->total_devs)
- q -= array->total_devs;
-
- if (disknr >= p)
- disknr += n;
- else if (disknr >= q)
- disknr += q + 1;
- }
-
- if (disknr >= array->total_devs)
- disknr -= array->total_devs;
- }
- else
- p = array->total_devs - n;
-
- read_sector *= array->chunk_size;
+ read_sector = grub_divmod64 (sector, seg->stripe_size, &b);
+ read_sector = grub_divmod64 (read_sector, seg->node_count - n,
+ &disknr);
+ if (seg->type >= 5)
+ {
+ grub_divmod64 (read_sector, seg->node_count, &p);
+
+ if (! (seg->layout & GRUB_RAID_LAYOUT_RIGHT_MASK))
+ p = seg->node_count - 1 - p;
+
+ if (seg->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
+ {
+ disknr += p + n;
+ }
+ else
+ {
+ grub_uint32_t q;
+
+ q = p + (n - 1);
+ if (q >= seg->node_count)
+ q -= seg->node_count;
+
+ if (disknr >= p)
+ disknr += n;
+ else if (disknr >= q)
+ disknr += q + 1;
+ }
+
+ if (disknr >= seg->node_count)
+ disknr -= seg->node_count;
+ }
+ else
+ p = seg->node_count - n;
+
+ read_sector *= seg->stripe_size;
while (1)
{
- grub_size_t read_size;
- int next_level;
-
- read_size = array->chunk_size - b;
- if (read_size > size)
- read_size = size;
-
- e = 0;
- if (array->members[disknr].device)
- {
- /* Reset read error. */
- if (grub_errno == GRUB_ERR_READ_ERROR)
- grub_errno = GRUB_ERR_NONE;
-
- err = grub_disk_read (array->members[disknr].device,
- array->members[disknr].start_sector +
- read_sector + b, 0,
- read_size << GRUB_DISK_SECTOR_BITS,
- buf);
-
- if ((err) && (err != GRUB_ERR_READ_ERROR))
- break;
- e++;
- }
- else
- err = GRUB_ERR_READ_ERROR;
+ grub_size_t read_size;
+ int next_level;
+
+ read_size = seg->stripe_size - b;
+ if (read_size > size)
+ read_size = size;
+
+ e = 0;
+ /* Reset read error. */
+ if (grub_errno == GRUB_ERR_READ_ERROR
+ || grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
+ grub_errno = GRUB_ERR_NONE;
+
+ err = grub_diskfilter_read_node (&seg->nodes[disknr],
+ read_sector + b,
+ read_size,
+ buf);
+
+ if ((err) && (err != GRUB_ERR_READ_ERROR
+ && err != GRUB_ERR_UNKNOWN_DEVICE))
+ return err;
+ e++;
if (err)
- {
- if (array->nr_devs < array->total_devs - n + e)
- break;
-
- grub_errno = GRUB_ERR_NONE;
- if (array->level == 6)
- {
- err = ((grub_raid6_recover_func) ?
- (*grub_raid6_recover_func) (array, disknr, p,
- buf, read_sector + b,
- read_size) :
- grub_error (GRUB_ERR_BAD_DEVICE,
- "raid6rec is not loaded"));
- }
- else
- {
- err = ((grub_raid5_recover_func) ?
- (*grub_raid5_recover_func) (array, disknr,
- buf, read_sector + b,
- read_size) :
- grub_error (GRUB_ERR_BAD_DEVICE,
- "raid5rec is not loaded"));
- }
-
- if (err)
- break;
- }
+ {
+ grub_errno = GRUB_ERR_NONE;
+ if (seg->type == GRUB_DISKFILTER_RAID6)
+ {
+ err = ((grub_raid6_recover_func) ?
+ (*grub_raid6_recover_func) (seg, disknr, p,
+ buf, read_sector + b,
+ read_size) :
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "raid6rec is not loaded"));
+ }
+ else
+ {
+ err = ((grub_raid5_recover_func) ?
+ (*grub_raid5_recover_func) (seg, disknr,
+ buf, read_sector + b,
+ read_size) :
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "raid5rec is not loaded"));
+ }
+
+ if (err)
+ return err;
+ }
buf += read_size << GRUB_DISK_SECTOR_BITS;
size -= read_size;
+ sector += read_size;
if (! size)
break;
- b = 0;
+ b = 0;
disknr++;
- if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
- {
- if (disknr == array->total_devs)
- disknr = 0;
-
- next_level = (disknr == p);
- }
- else
- {
- if (disknr == p)
- disknr += n;
-
- next_level = (disknr >= array->total_devs);
- }
-
- if (next_level)
- {
- read_sector += array->chunk_size;
-
- if (array->level >= 5)
- {
- if (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK)
- p = (p == array->total_devs - 1) ? 0 : p + 1;
- else
- p = (p == 0) ? array->total_devs - 1 : p - 1;
-
- if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
- {
- disknr = p + n;
- if (disknr >= array->total_devs)
- disknr -= array->total_devs;
- }
- else
- {
- disknr -= array->total_devs;
- if (disknr == p)
- disknr += n;
- }
- }
- else
- disknr = 0;
- }
- }
+ if (seg->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
+ {
+ if (disknr == seg->node_count)
+ disknr = 0;
+
+ next_level = (disknr == p);
+ }
+ else
+ {
+ if (disknr == p)
+ disknr += n;
+
+ next_level = (disknr >= seg->node_count);
+ }
+
+ if (next_level)
+ {
+ read_sector += seg->stripe_size;
+
+ if (seg->type >= 5)
+ {
+ if (seg->layout & GRUB_RAID_LAYOUT_RIGHT_MASK)
+ p = (p == seg->node_count - 1) ? 0 : p + 1;
+ else
+ p = (p == 0) ? seg->node_count - 1 : p - 1;
+
+ if (seg->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
+ {
+ disknr = p + n;
+ if (disknr >= seg->node_count)
+ disknr -= seg->node_count;
+ }
+ else
+ {
+ disknr -= seg->node_count;
+ if (disknr == p)
+ disknr += n;
+ }
+ }
+ else
+ disknr = 0;
+ }
+ }
+ }
+ return GRUB_ERR_NONE;
+ default:
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "unsupported RAID level %d", seg->type);
+ }
+}
+
+static grub_err_t
+read_lv (struct grub_diskfilter_lv *lv, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+{
+ if (!lv)
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown volume");
+
+ while (size)
+ {
+ grub_err_t err = 0;
+ struct grub_diskfilter_vg *vg = lv->vg;
+ struct grub_diskfilter_segment *seg = lv->segments;
+ grub_uint64_t extent;
+ grub_size_t to_read;
+
+ extent = grub_divmod64 (sector, vg->extent_size, NULL);
+
+ /* Find the right segment. */
+ {
+ unsigned int i;
+ for (i = 0; i < lv->segment_count; i++)
+ {
+ if ((seg->start_extent <= extent)
+ && ((seg->start_extent + seg->extent_count) > extent))
+ break;
+ seg++;
+ }
+ if (i == lv->segment_count)
+ return grub_error (GRUB_ERR_READ_ERROR, "incorrect segment");
}
- break;
+ to_read = ((seg->start_extent + seg->extent_count)
+ * vg->extent_size) - sector;
+ if (to_read > size)
+ to_read = size;
+
+ err = read_segment (seg, sector - seg->start_extent * vg->extent_size,
+ to_read, buf);
+ if (err)
+ return err;
+
+ size -= to_read;
+ sector += to_read;
+ buf += to_read << GRUB_DISK_SECTOR_BITS;
}
-
- return err;
-}
-
-static grub_err_t
-grub_raid_write (grub_disk_t disk __attribute ((unused)),
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_diskfilter_read (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+{
+ return read_lv (disk->data, sector, size, buf);
+}
+
+static grub_err_t
+grub_diskfilter_write (grub_disk_t disk __attribute ((unused)),
grub_disk_addr_t sector __attribute ((unused)),
grub_size_t size __attribute ((unused)),
const char *buf __attribute ((unused)))
@@ -618,229 +725,252 @@
return GRUB_ERR_NOT_IMPLEMENTED_YET;
}
-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)))
+struct grub_diskfilter_vg *
+grub_diskfilter_get_vg_by_uuid (grub_size_t uuidlen, char *uuid)
{
- struct grub_raid_array *array = 0, *p;
- int was_readable = 0;
+ struct grub_diskfilter_vg *p;
- /* See whether the device is part of an array we have already seen a
- device from. */
for (p = array_list; p != NULL; p = p->next)
- if ((p->uuid_len == new_array->uuid_len) &&
- (! grub_memcmp (p->uuid, new_array->uuid, p->uuid_len)))
- {
- grub_free (new_array->uuid);
- array = p;
-
- was_readable = grub_is_array_readable (array);
-
- /* Do some checks before adding the device to the array. */
-
- if (new_array->index >= array->allocated_devs)
- {
- void *tmp;
- unsigned int newnum = 2 * (new_array->index + 1);
- tmp = grub_realloc (array->members, newnum
- * sizeof (array->members[0]));
- if (!tmp)
- return grub_errno;
- array->members = tmp;
- grub_memset (array->members + array->allocated_devs,
- 0, (newnum - array->allocated_devs)
- * sizeof (array->members[0]));
- array->allocated_devs = newnum;
- }
-
- /* FIXME: Check whether the update time of the superblocks are
- the same. */
-
- if (array->total_devs == array->nr_devs)
- /* We found more members of the array than the array
- actually has according to its superblock. This shouldn't
- happen normally. */
- return grub_error (GRUB_ERR_BAD_DEVICE,
- "superfluous RAID member (%d found)",
- array->total_devs);
-
- if (array->members[new_array->index].device != NULL)
- /* We found multiple devices with the same number. Again,
- this shouldn't happen. */
- return grub_error (GRUB_ERR_BAD_DEVICE,
- "found two disks with the index %d for RAID %s",
- new_array->index, array->name);
-
- if (new_array->disk_size < array->disk_size)
- array->disk_size = new_array->disk_size;
- break;
- }
-
- /* Add an array to the list if we didn't find any. */
- if (!array)
+ if ((p->uuid_len == uuidlen) &&
+ (! grub_memcmp (p->uuid, uuid, p->uuid_len)))
+ return p;
+ return NULL;
+}
+
+grub_err_t
+grub_diskfilter_vg_register (struct grub_diskfilter_vg *vg)
+{
+ struct grub_diskfilter_lv *lv, *p;
+ struct grub_diskfilter_vg *vgp;
+ unsigned i;
+
+ grub_dprintf ("diskfilter", "Found array %s\n", vg->name);
+#ifdef GRUB_UTIL
+ grub_util_info ("Found array %s", vg->name);
+#endif
+
+ for (lv = vg->lvs; lv; lv = lv->next)
{
- array = grub_malloc (sizeof (*array));
- if (!array)
- {
- grub_free (new_array->uuid);
- return grub_errno;
- }
-
- *array = *new_array;
- array->nr_devs = 0;
-#ifdef GRUB_UTIL
- array->driver = raid;
-#endif
- array->allocated_devs = 32;
- if (new_array->index >= array->allocated_devs)
- array->allocated_devs = 2 * (new_array->index + 1);
-
- array->members = grub_zalloc (array->allocated_devs
- * sizeof (array->members[0]));
-
- if (!array->members)
- {
- grub_free (new_array->uuid);
- return grub_errno;
- }
-
- if (! array->name)
- {
- for (p = array_list; p != NULL; p = p->next)
- {
- if (p->number == array->number)
- break;
- }
- }
-
- if (array->name || p)
- {
- /* The number is already in use, so we need to find a new one.
- (Or, in the case of named arrays, the array doesn't have its
- own number, but we need one that doesn't clash for use as a key
- in the disk cache. */
- int i = array->name ? 0x40000000 : 0;
-
- while (1)
- {
- for (p = array_list; p != NULL; p = p->next)
- {
- if (p->number == i)
- break;
- }
-
- if (! p)
- {
- /* We found an unused number. */
- array->number = i;
- break;
- }
-
- i++;
- }
- }
-
- /* mdraid 1.x superblocks have only a name stored not a number.
- Use it directly as GRUB device. */
- if (! array->name)
- {
- array->name = grub_xasprintf ("md%d", array->number);
- if (! array->name)
- {
- grub_free (array->members);
- grub_free (array->uuid);
- grub_free (array);
-
- return grub_errno;
- }
- }
- else
- {
- /* Strip off the homehost if present. */
- char *colon = grub_strchr (array->name, ':');
- char *new_name = grub_xasprintf ("md/%s",
- colon ? colon + 1 : array->name);
-
- if (! new_name)
- {
- grub_free (array->members);
- grub_free (array->uuid);
- grub_free (array);
-
- return grub_errno;
- }
-
- grub_free (array->name);
- array->name = new_name;
- }
-
- grub_dprintf ("raid", "Found array %s (%s)\n", array->name,
- scanner_name);
-#ifdef GRUB_UTIL
- grub_util_info ("Found array %s (%s)", array->name,
- scanner_name);
-#endif
-
- {
- int max_used_number = 0, len, need_new_name = 0;
- int add_us = 0;
- len = grub_strlen (array->name);
- if (len && grub_isdigit (array->name[len-1]))
- add_us = 1;
- for (p = array_list; p != NULL; p = p->next)
- {
- int cur_num;
- char *num, *end;
- if (grub_strncmp (p->name, array->name, len) != 0)
- continue;
- if (p->name[len] == 0)
+ lv->number = lv_num++;
+
+ if (lv->fullname)
+ {
+ grub_size_t len;
+ int max_used_number = 0, need_new_name = 0;
+ len = grub_strlen (lv->fullname);
+ for (vgp = array_list; vgp; vgp = vgp->next)
+ for (p = vgp->lvs; p; p = p->next)
{
- need_new_name = 1;
- continue;
+ int cur_num;
+ char *num, *end;
+ if (!p->fullname)
+ continue;
+ if (grub_strncmp (p->fullname, lv->fullname, len) != 0)
+ continue;
+ if (p->fullname[len] == 0)
+ {
+ need_new_name = 1;
+ continue;
+ }
+ num = p->fullname + len + 1;
+ if (!grub_isdigit (num[0]))
+ continue;
+ cur_num = grub_strtoul (num, &end, 10);
+ if (end[0])
+ continue;
+ if (cur_num > max_used_number)
+ max_used_number = cur_num;
}
- if (add_us && p->name[len] != '_')
- continue;
- if (add_us)
- num = p->name + len + 1;
- else
- num = p->name + len;
- if (!grub_isdigit (num[0]))
- continue;
- cur_num = grub_strtoull (num, &end, 10);
- if (end[0])
- continue;
- if (cur_num > max_used_number)
- max_used_number = cur_num;
- }
- if (need_new_name)
- {
- char *tmp;
- tmp = grub_xasprintf ("%s%s%d", array->name, add_us ? "_" : "",
- max_used_number + 1);
- if (!tmp)
- return grub_errno;
- grub_free (array->name);
- array->name = tmp;
- }
- }
-
- /* Add our new array to the list. */
- array->next = array_list;
- array_list = array;
-
+ if (need_new_name)
+ {
+ char *tmp;
+ tmp = grub_xasprintf ("%s_%d", lv->fullname, max_used_number + 1);
+ if (!tmp)
+ return grub_errno;
+ grub_free (lv->fullname);
+ lv->fullname = tmp;
+ }
+ }
/* RAID 1 doesn't use a chunksize but code assumes one so set
one. */
- if (array->level == 1)
- array->chunk_size = 64;
- }
-
- /* 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++;
- if (!was_readable && grub_is_array_readable (array))
- array->became_readable_at = inscnt++;
+ for (i = 0; i < lv->segment_count; i++)
+ if (lv->segments[i].type == 1)
+ lv->segments[i].stripe_size = 64;
+ lv->vg = vg;
+ }
+ /* Add our new array to the list. */
+ vg->next = array_list;
+ array_list = vg;
+ return GRUB_ERR_NONE;
+}
+
+struct grub_diskfilter_vg *
+grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb,
+ char *name, grub_uint64_t disk_size,
+ grub_uint64_t stripe_size,
+ int layout, int level)
+{
+ struct grub_diskfilter_vg *array;
+ int i;
+ grub_uint64_t totsize;
+ struct grub_diskfilter_pv *pv;
+
+ switch (level)
+ {
+ case 1:
+ totsize = disk_size;
+ break;
+
+ case 10:
+ {
+ int n;
+ n = layout & 0xFF;
+ if (n == 1)
+ n = (layout >> 8) & 0xFF;
+
+ totsize = grub_divmod64 (nmemb * disk_size, n, 0);
+ }
+ break;
+
+ case 0:
+ case 4:
+ case 5:
+ case 6:
+ totsize = (nmemb - level / 3) * disk_size;
+ break;
+ }
+
+ array = grub_diskfilter_get_vg_by_uuid (uuidlen, uuid);
+ if (array)
+ {
+ if (array->lvs && array->lvs->size < totsize)
+ {
+ array->lvs->size = totsize;
+ if (array->lvs->segments)
+ array->lvs->segments->extent_count = totsize;
+ }
+
+ if (array->lvs->segments
+ && array->lvs->segments->raid_member_size > disk_size)
+ array->lvs->segments->raid_member_size = disk_size;
+
+ grub_free (uuid);
+ return array;
+ }
+ array = grub_zalloc (sizeof (*array));
+ if (!array)
+ return NULL;
+ array->uuid = uuid;
+ array->uuid_len = uuidlen;
+ if (name)
+ {
+ /* Strip off the homehost if present. */
+ char *colon = grub_strchr (name, ':');
+ char *new_name = grub_xasprintf ("md/%s",
+ colon ? colon + 1 : name);
+
+ if (! new_name)
+ goto fail;
+
+ array->name = new_name;
+ }
+ array->extent_size = 1;
+ array->lvs = grub_zalloc (sizeof (*array->lvs));
+ if (!array->lvs)
+ goto fail;
+ array->lvs->segment_count = 1;
+ array->lvs->visible = 1;
+ array->lvs->name = array->name;
+ array->lvs->fullname = array->name;
+
+ array->lvs->size = totsize;
+
+ array->lvs->segments = grub_zalloc (sizeof (*array->lvs->segments));
+ if (!array->lvs->segments)
+ goto fail;
+ array->lvs->segments->stripe_size = stripe_size;
+ array->lvs->segments->layout = layout;
+ array->lvs->segments->start_extent = 0;
+ array->lvs->segments->extent_count = totsize;
+ array->lvs->segments->type = level;
+ array->lvs->segments->node_count = nmemb;
+ array->lvs->segments->raid_member_size = disk_size;
+ array->lvs->segments->nodes
+ = grub_zalloc (nmemb * sizeof (array->lvs->segments->nodes[0]));
+ array->lvs->segments->stripe_size = stripe_size;
+ for (i = 0; i < nmemb; i++)
+ {
+ pv = grub_zalloc (sizeof (*pv));
+ if (!pv)
+ goto fail;
+ pv->id.uuidlen = 0;
+ pv->id.id = i;
+ array->pvs = pv;
+ array->lvs->segments->nodes[i].pv = &array->pvs[i];
+ }
+
+ return array;
+
+ fail:
+ grub_free (array->lvs);
+ while (array->pvs)
+ {
+ pv = array->pvs->next;
+ grub_free (array->pvs);
+ array->pvs = pv;
+ }
+ grub_free (array);
+ return NULL;
+}
+
+static grub_err_t
+insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id,
+ struct grub_diskfilter_vg *array,
+ grub_disk_addr_t start_sector, const char *scanner_name,
+ grub_diskfilter_t diskfilter __attribute__ ((unused)))
+{
+ struct grub_diskfilter_pv *pv;
+
+ grub_dprintf ("diskfilter", "Inserting %s into %s (%s)\n", disk->name,
+ array->name, scanner_name);
+#ifdef GRUB_UTIL
+ grub_util_info ("Inserting %s into %s (%s)\n", disk->name,
+ array->name, scanner_name);
+ array->driver = diskfilter;
+#endif
+
+ for (pv = array->pvs; pv; pv = pv->next)
+ if (id->uuidlen == pv->id.uuidlen
+ && id->uuidlen
+ ? (grub_memcmp (pv->id.uuid, id->uuid, id->uuidlen) == 0)
+ : (pv->id.id == id->id))
+ {
+ struct grub_diskfilter_lv *lv;
+ /* FIXME: Check whether the update time of the superblocks are
+ the same. */
+ /* This could happen to LVM on RAID, pv->disk points to the
+ raid device, we shouldn't change it. */
+ if (! pv->disk)
+ {
+ pv->disk = grub_disk_open (disk->name);
+ if (! pv->disk)
+ return grub_errno;
+ pv->part_start = grub_partition_get_start (disk->partition);
+ pv->part_size = grub_disk_get_size (disk);
+
+ if (start_sector != (grub_uint64_t)-1)
+ pv->start_sector = start_sector;
+ pv->start_sector += pv->part_start;
+ }
+ /* Add the device to the array. */
+ for (lv = array->lvs; lv; lv = lv->next)
+ if (!lv->became_readable_at && lv->fullname && is_lv_readable (lv))
+ {
+ lv->became_readable_at = ++inscnt;
+ scan_disk (lv->fullname);
+ }
+ break;
+ }
return 0;
}
@@ -848,74 +978,100 @@
static void
free_array (void)
{
- struct grub_raid_array *array;
-
- array = array_list;
- while (array)
+ while (array_list)
{
- struct grub_raid_array *p;
- unsigned int i;
-
- p = array;
- array = array->next;
-
- for (i = 0; i < p->allocated_devs; i++)
- if (p->members[i].device)
- grub_disk_close (p->members[i].device);
- grub_free (p->members);
-
- grub_free (p->uuid);
- grub_free (p->name);
- grub_free (p);
+ struct grub_diskfilter_vg *vg;
+ struct grub_diskfilter_pv *pv;
+ struct grub_diskfilter_lv *lv;
+
+ vg = array_list;
+ array_list = array_list->next;
+
+ while ((pv = vg->pvs))
+ {
+ vg->pvs = pv->next;
+ grub_free (pv->name);
+ if (pv->disk)
+ grub_disk_close (pv->disk);
+ if (pv->id.uuidlen)
+ grub_free (pv->id.uuid);
+ grub_free (pv->internal_id);
+ grub_free (pv);
+ }
+
+ while ((lv = vg->lvs))
+ {
+ unsigned i;
+ vg->lvs = lv->next;
+ if (lv->name != lv->fullname)
+ grub_free (lv->fullname);
+ if (lv->name != vg->name)
+ grub_free (lv->name);
+ for (i = 0; i < lv->segment_count; i++)
+ grub_free (lv->segments[i].nodes);
+ grub_free (lv->segments);
+ grub_free (lv->internal_id);
+ grub_free (lv);
+ }
+
+ grub_free (vg->uuid);
+ grub_free (vg->name);
+ grub_free (vg);
}
array_list = 0;
}
-void
-grub_raid_register (grub_raid_t raid)
-{
- raid->next = grub_raid_list;
- grub_raid_list = raid;
-}
-
-void
-grub_raid_unregister (grub_raid_t raid)
-{
- grub_raid_t *p, q;
-
- for (p = &grub_raid_list, q = *p; q; p = &(q->next), q = q->next)
- if (q == raid)
+#ifdef GRUB_UTIL
+struct grub_diskfilter_pv *
+grub_diskfilter_get_pv_from_disk (grub_disk_t disk,
+ struct grub_diskfilter_vg **vg_out)
+{
+ struct grub_diskfilter_pv *pv;
+ struct grub_diskfilter_vg *vg;
+
+ scan_disk (disk->name);
+ for (vg = array_list; vg; vg = vg->next)
+ for (pv = vg->pvs; pv; pv = pv->next)
{
- *p = q->next;
- break;
+ if (pv->disk && pv->disk->id == disk->id
+ && pv->disk->dev->id == disk->dev->id
+ && pv->part_start == grub_partition_get_start (disk->partition)
+ && pv->part_size == grub_disk_get_size (disk))
+ {
+ if (vg_out)
+ *vg_out = vg;
+ return pv;
+ }
}
+ return NULL;
}
+#endif
-static struct grub_disk_dev grub_raid_dev =
+static struct grub_disk_dev grub_diskfilter_dev =
{
- .name = "raid",
- .id = GRUB_DISK_DEVICE_RAID_ID,
- .iterate = grub_raid_iterate,
- .open = grub_raid_open,
- .close = grub_raid_close,
- .read = grub_raid_read,
- .write = grub_raid_write,
+ .name = "diskfilter",
+ .id = GRUB_DISK_DEVICE_DISKFILTER_ID,
+ .iterate = grub_diskfilter_iterate,
+ .open = grub_diskfilter_open,
+ .close = grub_diskfilter_close,
+ .read = grub_diskfilter_read,
+ .write = grub_diskfilter_write,
#ifdef GRUB_UTIL
- .memberlist = grub_raid_memberlist,
- .raidname = grub_raid_getname,
+ .memberlist = grub_diskfilter_memberlist,
+ .raidname = grub_diskfilter_getname,
#endif
.next = 0
};
\f
-GRUB_MOD_INIT(raid)
+GRUB_MOD_INIT(diskfilter)
{
- grub_disk_dev_register (&grub_raid_dev);
+ grub_disk_dev_register (&grub_diskfilter_dev);
}
-GRUB_MOD_FINI(raid)
+GRUB_MOD_FINI(diskfilter)
{
- grub_disk_dev_unregister (&grub_raid_dev);
+ grub_disk_dev_unregister (&grub_diskfilter_dev);
free_array ();
}
=== modified file 'grub-core/disk/dmraid_nvidia.c'
--- grub-core/disk/dmraid_nvidia.c 2012-01-14 10:37:34 +0000
+++ grub-core/disk/dmraid_nvidia.c 2012-01-28 13:51:46 +0000
@@ -22,7 +22,7 @@
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
-#include <grub/raid.h>
+#include <grub/diskfilter.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -90,72 +90,91 @@
struct grub_nv_array array; /* Array information */
} __attribute__ ((packed));
-static grub_err_t
-grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array,
- grub_disk_addr_t *start_sector)
+static struct grub_diskfilter_vg *
+grub_dmraid_nv_detect (grub_disk_t disk,
+ struct grub_diskfilter_pv_id *id,
+ grub_disk_addr_t *start_sector)
{
grub_disk_addr_t sector;
struct grub_nv_super sb;
+ int level;
+ int layout;
+ grub_uint64_t disk_size;
+ char *uuid;
if (disk->partition)
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "skip partition");
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "skip partition");
+ return NULL;
+ }
sector = grub_disk_get_size (disk);
if (sector == GRUB_DISK_SIZE_UNKNOWN)
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
+ return NULL;
+ }
sector -= 2;
if (grub_disk_read (disk, sector, 0, sizeof (sb), &sb))
- return grub_errno;
+ return NULL;
if (grub_memcmp (sb.vendor, NV_ID_STRING, 6))
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
+ return NULL;
+ }
if (sb.version != NV_VERSION)
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "unknown version: %d.%d", sb.version);
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "unknown version: %d.%d", sb.version);
+ return NULL;
+ }
switch (sb.array.raid_level)
{
case NV_LEVEL_0:
- array->level = 0;
- array->disk_size = sb.capacity / sb.array.total_volumes;
+ level = 0;
+ disk_size = sb.capacity / sb.array.total_volumes;
break;
case NV_LEVEL_1:
- array->level = 1;
- array->disk_size = sb.capacity;
+ level = 1;
+ disk_size = sb.capacity;
break;
case NV_LEVEL_5:
- array->level = 5;
- array->layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC;
- array->disk_size = sb.capacity / (sb.array.total_volumes - 1);
+ level = 5;
+ layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC;
+ disk_size = sb.capacity / (sb.array.total_volumes - 1);
break;
default:
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "unsupported RAID level: %d", sb.array.raid_level);
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "unsupported RAID level: %d", sb.array.raid_level);
+ return NULL;
}
- array->name = NULL;
- array->number = 0;
- array->total_devs = sb.array.total_volumes;
- array->chunk_size = sb.array.stripe_block_size;
- array->index = sb.unit_number;
- array->uuid_len = sizeof (sb.array.signature);
- array->uuid = grub_malloc (sizeof (sb.array.signature));
- if (! array->uuid)
- return grub_errno;
+ uuid = grub_malloc (sizeof (sb.array.signature));
+ if (! uuid)
+ return NULL;
- grub_memcpy (array->uuid, (char *) &sb.array.signature,
+ grub_memcpy (uuid, (char *) &sb.array.signature,
sizeof (sb.array.signature));
+ id->uuidlen = 0;
+ id->id = sb.unit_number;
+
*start_sector = 0;
- return 0;
+ return grub_diskfilter_make_raid (sizeof (sb.array.signature),
+ uuid, sb.array.total_volumes,
+ NULL, disk_size,
+ sb.array.stripe_block_size, layout,
+ level);
}
-static struct grub_raid grub_dmraid_nv_dev =
+static struct grub_diskfilter grub_dmraid_nv_dev =
{
.name = "dmraid_nv",
.detect = grub_dmraid_nv_detect,
@@ -164,10 +183,10 @@
GRUB_MOD_INIT(dm_nv)
{
- grub_raid_register (&grub_dmraid_nv_dev);
+ grub_diskfilter_register (&grub_dmraid_nv_dev);
}
GRUB_MOD_FINI(dm_nv)
{
- grub_raid_unregister (&grub_dmraid_nv_dev);
+ grub_diskfilter_unregister (&grub_dmraid_nv_dev);
}
=== added file 'grub-core/disk/ldm.c'
--- grub-core/disk/ldm.c 1970-01-01 00:00:00 +0000
+++ grub-core/disk/ldm.c 2012-01-28 13:51:46 +0000
@@ -0,0 +1,997 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2008,2009,2011 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/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/disk.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/diskfilter.h>
+#include <grub/gpt_partition.h>
+
+#ifdef GRUB_UTIL
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#endif
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define LDM_GUID_STRLEN 64
+#define LDM_NAME_STRLEN 32
+
+typedef grub_uint8_t *grub_ldm_id_t;
+
+enum { STRIPE = 1, SPANNED = 2, RAID5 = 3 };
+
+#define LDM_LABEL_SECTOR 6
+struct grub_ldm_vblk {
+ char magic[4];
+ grub_uint8_t unused1[12];
+ grub_uint16_t update_status;
+ grub_uint8_t flags;
+ grub_uint8_t type;
+ grub_uint32_t unused2;
+ grub_uint8_t dynamic[104];
+} __attribute__ ((packed));
+#define LDM_VBLK_MAGIC "VBLK"
+
+enum
+ {
+ STATUS_CONSISTENT = 0,
+ STATUS_STILL_ACTIVE = 1,
+ STATUS_NOT_ACTIVE_YET = 2
+ };
+
+enum
+ {
+ ENTRY_COMPONENT = 0x32,
+ ENTRY_PARTITION = 0x33,
+ ENTRY_DISK = 0x34,
+ ENTRY_VOLUME = 0x51,
+ };
+
+struct grub_ldm_label
+{
+ char magic[8];
+ grub_uint32_t unused1;
+ grub_uint16_t ver_major;
+ grub_uint16_t ver_minor;
+ grub_uint8_t unused2[32];
+ char disk_guid[LDM_GUID_STRLEN];
+ char host_guid[LDM_GUID_STRLEN];
+ char group_guid[LDM_GUID_STRLEN];
+ char group_name[LDM_NAME_STRLEN];
+ grub_uint8_t unused3[11];
+ grub_uint64_t pv_start;
+ grub_uint64_t pv_size;
+ grub_uint64_t config_start;
+ grub_uint64_t config_size;
+} __attribute__ ((packed));
+
+
+#define LDM_MAGIC "PRIVHEAD"
+
+\f
+
+static inline grub_uint64_t
+read_int (grub_uint8_t *in, grub_size_t s)
+{
+ grub_uint8_t *ptr2;
+ grub_uint64_t ret;
+ ret = 0;
+ for (ptr2 = in; ptr2 < in + s; ptr2++)
+ {
+ ret <<= 8;
+ ret |= *ptr2;
+ }
+ return ret;
+}
+
+static const grub_gpt_part_type_t ldm_type = GRUB_GPT_PARTITION_TYPE_LDM;
+
+static grub_disk_addr_t
+gpt_ldm_sector (grub_disk_t dsk)
+{
+ grub_disk_addr_t sector = 0;
+ grub_err_t err;
+ auto int hook (grub_disk_t disk, const grub_partition_t p);
+ int hook (grub_disk_t disk, const grub_partition_t p)
+ {
+ struct grub_gpt_partentry gptdata;
+ grub_partition_t p2;
+
+ p2 = disk->partition;
+ disk->partition = p->parent;
+ if (grub_disk_read (disk, p->offset, p->index,
+ sizeof (gptdata), &gptdata))
+ {
+ disk->partition = p2;
+ return 0;
+ }
+ disk->partition = p2;
+
+ if (! grub_memcmp (&gptdata.type, &ldm_type, 16))
+ {
+ sector = p->start + p->len - 1;
+ return 1;
+ }
+ return 0;
+ }
+ err = grub_gpt_partition_map_iterate (dsk, hook);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return 0;
+ }
+ return sector;
+}
+
+static struct grub_diskfilter_vg *
+make_vg (grub_disk_t disk,
+ const struct grub_ldm_label *label)
+{
+ grub_disk_addr_t startsec, endsec, cursec;
+ struct grub_diskfilter_vg *vg;
+ grub_err_t err;
+
+ /* First time we see this volume group. We've to create the
+ whole volume group structure. */
+ vg = grub_malloc (sizeof (*vg));
+ if (! vg)
+ return NULL;
+ vg->extent_size = 1;
+ vg->name = grub_malloc (LDM_NAME_STRLEN + 1);
+ vg->uuid = grub_malloc (LDM_GUID_STRLEN + 1);
+ if (! vg->uuid || !vg->name)
+ {
+ grub_free (vg->uuid);
+ grub_free (vg->name);
+ return NULL;
+ }
+ grub_memcpy (vg->uuid, label->group_guid, LDM_GUID_STRLEN);
+ grub_memcpy (vg->name, label->group_name, LDM_NAME_STRLEN);
+ vg->name[LDM_NAME_STRLEN] = 0;
+ vg->uuid[LDM_GUID_STRLEN] = 0;
+ vg->uuid_len = grub_strlen (vg->uuid);
+
+ vg->lvs = NULL;
+ vg->pvs = NULL;
+
+ startsec = grub_be_to_cpu64 (label->config_start);
+ endsec = startsec + grub_be_to_cpu64 (label->config_size);
+
+ /* First find disks. */
+ for (cursec = startsec + 0x12; cursec < endsec; cursec++)
+ {
+ struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
+ / sizeof (struct grub_ldm_vblk)];
+ unsigned i;
+ err = grub_disk_read (disk, cursec, 0,
+ sizeof(vblk), &vblk);
+ if (err)
+ goto fail2;
+
+ for (i = 0; i < ARRAY_SIZE (vblk); i++)
+ {
+ struct grub_diskfilter_pv *pv;
+ grub_uint8_t *ptr;
+ if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
+ sizeof (vblk[i].magic)) != 0)
+ continue;
+ if (grub_be_to_cpu16 (vblk[i].update_status)
+ != STATUS_CONSISTENT
+ && grub_be_to_cpu16 (vblk[i].update_status)
+ != STATUS_STILL_ACTIVE)
+ continue;
+ if (vblk[i].type != ENTRY_DISK)
+ continue;
+ pv = grub_zalloc (sizeof (*pv));
+ if (!pv)
+ goto fail2;
+
+ pv->disk = 0;
+ ptr = vblk[i].dynamic;
+ if (ptr + *ptr + 1 >= vblk[i].dynamic
+ + sizeof (vblk[i].dynamic))
+ {
+ grub_free (pv);
+ goto fail2;
+ }
+ pv->internal_id = grub_malloc (ptr[0] + 2);
+ if (!pv->internal_id)
+ {
+ grub_free (pv);
+ goto fail2;
+ }
+ grub_memcpy (pv->internal_id, ptr, (grub_size_t) ptr[0] + 1);
+ pv->internal_id[(grub_size_t) ptr[0] + 1] = 0;
+
+ ptr += *ptr + 1;
+ if (ptr + *ptr + 1 >= vblk[i].dynamic
+ + sizeof (vblk[i].dynamic))
+ {
+ grub_free (pv);
+ goto fail2;
+ }
+ /* ptr = name. */
+ ptr += *ptr + 1;
+ if (ptr + *ptr + 1
+ >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ grub_free (pv);
+ goto fail2;
+ }
+ pv->id.uuidlen = *ptr;
+ pv->id.uuid = grub_malloc (pv->id.uuidlen + 1);
+ grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen);
+ pv->id.uuid[pv->id.uuidlen] = 0;
+
+ pv->next = vg->pvs;
+ vg->pvs = pv;
+ }
+ }
+
+ /* Then find LVs. */
+ for (cursec = startsec + 0x12; cursec < endsec; cursec++)
+ {
+ struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
+ / sizeof (struct grub_ldm_vblk)];
+ unsigned i;
+ err = grub_disk_read (disk, cursec, 0,
+ sizeof(vblk), &vblk);
+ if (err)
+ goto fail2;
+
+ for (i = 0; i < ARRAY_SIZE (vblk); i++)
+ {
+ struct grub_diskfilter_lv *lv;
+ grub_uint8_t *ptr;
+ if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
+ sizeof (vblk[i].magic)) != 0)
+ continue;
+ if (grub_be_to_cpu16 (vblk[i].update_status)
+ != STATUS_CONSISTENT
+ && grub_be_to_cpu16 (vblk[i].update_status)
+ != STATUS_STILL_ACTIVE)
+ continue;
+ if (vblk[i].type != ENTRY_VOLUME)
+ continue;
+ lv = grub_zalloc (sizeof (*lv));
+ if (!lv)
+ goto fail2;
+
+ lv->vg = vg;
+ lv->segment_count = 1;
+ lv->segment_alloc = 1;
+ lv->visible = 1;
+ lv->segments = grub_zalloc (sizeof (*lv->segments));
+ if (!lv->segments)
+ goto fail2;
+ lv->segments->start_extent = 0;
+ lv->segments->type = GRUB_DISKFILTER_MIRROR;
+ lv->segments->node_count = 0;
+ lv->segments->node_alloc = 8;
+ lv->segments->nodes = grub_zalloc (sizeof (*lv->segments->nodes)
+ * lv->segments->node_alloc);
+ if (!lv->segments->nodes)
+ goto fail2;
+ ptr = vblk[i].dynamic;
+ if (ptr + *ptr + 1 >= vblk[i].dynamic
+ + sizeof (vblk[i].dynamic))
+ {
+ grub_free (lv);
+ goto fail2;
+ }
+ lv->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2);
+ if (!lv->internal_id)
+ {
+ grub_free (lv);
+ goto fail2;
+ }
+ grub_memcpy (lv->internal_id, ptr, ptr[0] + 1);
+ lv->internal_id[ptr[0] + 1] = 0;
+
+ ptr += *ptr + 1;
+ if (ptr + *ptr + 1 >= vblk[i].dynamic
+ + sizeof (vblk[i].dynamic))
+ {
+ grub_free (lv);
+ goto fail2;
+ }
+ lv->name = grub_malloc (*ptr + 1);
+ if (!lv->name)
+ {
+ grub_free (lv->internal_id);
+ grub_free (lv);
+ goto fail2;
+ }
+ grub_memcpy (lv->name, ptr + 1, *ptr);
+ lv->name[*ptr] = 0;
+ lv->fullname = grub_xasprintf ("ldm/%s/%s",
+ vg->uuid, lv->name);
+ if (!lv->fullname)
+ {
+ grub_free (lv->internal_id);
+ grub_free (lv->name);
+ grub_free (lv);
+ goto fail2;
+ }
+ ptr += *ptr + 1;
+ if (ptr + *ptr + 1
+ >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ grub_free (lv->internal_id);
+ grub_free (lv->name);
+ grub_free (lv);
+ goto fail2;
+ }
+ /* ptr = volume type. */
+ ptr += *ptr + 1;
+ if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ grub_free (lv->internal_id);
+ grub_free (lv->name);
+ grub_free (lv);
+ goto fail2;
+ }
+ /* ptr = flags. */
+ ptr += *ptr + 1;
+ if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ grub_free (lv->internal_id);
+ grub_free (lv->name);
+ grub_free (lv);
+ goto fail2;
+ }
+
+ /* Skip state, type, unknown, volume number, zeros, flags. */
+ ptr += 14 + 1 + 1 + 1 + 3 + 1;
+ /* ptr = number of children. */
+ if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ grub_free (lv->internal_id);
+ grub_free (lv->name);
+ grub_free (lv);
+ goto fail2;
+ }
+ ptr += *ptr + 1;
+ if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ grub_free (lv->internal_id);
+ grub_free (lv->name);
+ grub_free (lv);
+ goto fail2;
+ }
+
+ /* Skip 2 more fields. */
+ ptr += 8 + 8;
+ if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
+ || ptr + *ptr + 1>= vblk[i].dynamic
+ + sizeof (vblk[i].dynamic))
+ {
+ grub_free (lv->internal_id);
+ grub_free (lv->name);
+ grub_free (lv);
+ goto fail2;
+ }
+ lv->size = read_int (ptr + 1, *ptr);
+ lv->segments->extent_count = lv->size;
+
+ lv->next = vg->lvs;
+ vg->lvs = lv;
+ }
+ }
+
+ /* Now the components. */
+ for (cursec = startsec + 0x12; cursec < endsec; cursec++)
+ {
+ struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
+ / sizeof (struct grub_ldm_vblk)];
+ unsigned i;
+ err = grub_disk_read (disk, cursec, 0,
+ sizeof(vblk), &vblk);
+ if (err)
+ goto fail2;
+
+ for (i = 0; i < ARRAY_SIZE (vblk); i++)
+ {
+ struct grub_diskfilter_lv *comp;
+ struct grub_diskfilter_lv *lv;
+ grub_uint8_t type;
+
+ grub_uint8_t *ptr;
+ if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
+ sizeof (vblk[i].magic)) != 0)
+ continue;
+ if (grub_be_to_cpu16 (vblk[i].update_status)
+ != STATUS_CONSISTENT
+ && grub_be_to_cpu16 (vblk[i].update_status)
+ != STATUS_STILL_ACTIVE)
+ continue;
+ if (vblk[i].type != ENTRY_COMPONENT)
+ continue;
+ comp = grub_zalloc (sizeof (*comp));
+ if (!comp)
+ goto fail2;
+ comp->visible = 0;
+ comp->name = 0;
+ comp->fullname = 0;
+
+ ptr = vblk[i].dynamic;
+ if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ goto fail2;
+ }
+ comp->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2);
+ if (!comp->internal_id)
+ {
+ grub_free (comp);
+ goto fail2;
+ }
+ grub_memcpy (comp->internal_id, ptr, ptr[0] + 1);
+ comp->internal_id[ptr[0] + 1] = 0;
+
+ ptr += *ptr + 1;
+ if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ grub_free (comp->internal_id);
+ grub_free (comp);
+ goto fail2;
+ }
+ /* ptr = name. */
+ ptr += *ptr + 1;
+ if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ grub_free (comp->internal_id);
+ grub_free (comp);
+ goto fail2;
+ }
+ /* ptr = state. */
+ ptr += *ptr + 1;
+ type = *ptr++;
+ /* skip zeros. */
+ ptr += 4;
+ if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ grub_free (comp->internal_id);
+ grub_free (comp);
+ goto fail2;
+ }
+
+ /* ptr = number of children. */
+ ptr += *ptr + 1;
+ if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ grub_free (comp->internal_id);
+ grub_free (comp);
+ goto fail2;
+ }
+ ptr += 8 + 8;
+ if (ptr + *ptr + 1 >= vblk[i].dynamic
+ + sizeof (vblk[i].dynamic))
+ {
+ grub_free (comp->internal_id);
+ grub_free (comp);
+ goto fail2;
+ }
+ for (lv = vg->lvs; lv; lv = lv->next)
+ {
+ if (lv->internal_id[0] == ptr[0]
+ && grub_memcmp (lv->internal_id + 1, ptr + 1, ptr[0]) == 0)
+ break;
+ }
+ if (!lv)
+ {
+ grub_free (comp->internal_id);
+ grub_free (comp);
+ continue;
+ }
+ comp->size = lv->size;
+ if (type == SPANNED)
+ {
+ comp->segment_alloc = 8;
+ comp->segment_count = 0;
+ comp->segments = grub_malloc (sizeof (*comp->segments)
+ * comp->segment_alloc);
+ if (!comp->segments)
+ goto fail2;
+ }
+ else
+ {
+ comp->segment_alloc = 1;
+ comp->segment_count = 1;
+ comp->segments = grub_malloc (sizeof (*comp->segments));
+ if (!comp->segments)
+ goto fail2;
+ comp->segments->start_extent = 0;
+ comp->segments->extent_count = lv->size;
+ comp->segments->layout = 0;
+ if (type == STRIPE)
+ comp->segments->type = GRUB_DISKFILTER_STRIPED;
+ else if (type == RAID5)
+ {
+ comp->segments->type = GRUB_DISKFILTER_RAID5;
+ comp->segments->layout = GRUB_RAID_LAYOUT_SYMMETRIC_MASK;
+ }
+ else
+ goto fail2;
+ ptr += *ptr + 1;
+ ptr++;
+ if (!(vblk[i].flags & 0x10))
+ goto fail2;
+ if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
+ || ptr + *ptr + 1 >= vblk[i].dynamic
+ + sizeof (vblk[i].dynamic))
+ {
+ grub_free (comp->internal_id);
+ grub_free (comp);
+ goto fail2;
+ }
+ comp->segments->stripe_size = read_int (ptr + 1, *ptr);
+ ptr += *ptr + 1;
+ if (ptr + *ptr + 1 >= vblk[i].dynamic
+ + sizeof (vblk[i].dynamic))
+ {
+ grub_free (comp->internal_id);
+ grub_free (comp);
+ goto fail2;
+ }
+ comp->segments->node_count = read_int (ptr + 1, *ptr);
+ comp->segments->node_alloc = comp->segments->node_count;
+ comp->segments->nodes = grub_zalloc (sizeof (*comp->segments->nodes)
+ * comp->segments->node_alloc);
+ if (!lv->segments->nodes)
+ goto fail2;
+ }
+
+ if (lv->segments->node_alloc == lv->segments->node_count)
+ {
+ void *t;
+ lv->segments->node_alloc *= 2;
+ t = grub_realloc (lv->segments->nodes,
+ sizeof (*lv->segments->nodes)
+ * lv->segments->node_alloc);
+ if (!t)
+ goto fail2;
+ lv->segments->nodes = t;
+ }
+ lv->segments->nodes[lv->segments->node_count].pv = 0;
+ lv->segments->nodes[lv->segments->node_count].start = 0;
+ lv->segments->nodes[lv->segments->node_count++].lv = comp;
+ comp->next = vg->lvs;
+ vg->lvs = comp;
+ }
+ }
+ /* Partitions. */
+ for (cursec = startsec + 0x12; cursec < endsec; cursec++)
+ {
+ struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
+ / sizeof (struct grub_ldm_vblk)];
+ unsigned i;
+ err = grub_disk_read (disk, cursec, 0,
+ sizeof(vblk), &vblk);
+ if (err)
+ goto fail2;
+
+ for (i = 0; i < ARRAY_SIZE (vblk); i++)
+ {
+ struct grub_diskfilter_lv *comp;
+ struct grub_diskfilter_node part;
+ grub_disk_addr_t start, size;
+
+ grub_uint8_t *ptr;
+ if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
+ sizeof (vblk[i].magic)) != 0)
+ continue;
+ if (grub_be_to_cpu16 (vblk[i].update_status)
+ != STATUS_CONSISTENT
+ && grub_be_to_cpu16 (vblk[i].update_status)
+ != STATUS_STILL_ACTIVE)
+ continue;
+ if (vblk[i].type != ENTRY_PARTITION)
+ continue;
+ part.lv = 0;
+ part.pv = 0;
+
+ ptr = vblk[i].dynamic;
+ if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ goto fail2;
+ }
+ /* ID */
+ ptr += *ptr + 1;
+ if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ goto fail2;
+ }
+ /* ptr = name. */
+ ptr += *ptr + 1;
+ if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ goto fail2;
+ }
+
+ /* skip zeros and logcommit id. */
+ ptr += 4 + 8;
+ if (ptr + 16 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ goto fail2;
+ }
+ part.start = read_int (ptr, 8);
+ start = read_int (ptr + 8, 8);
+ ptr += 16;
+ if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
+ || ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ goto fail2;
+ }
+ size = read_int (ptr + 1, *ptr);
+ ptr += *ptr + 1;
+ if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
+ || ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ goto fail2;
+ }
+
+ for (comp = vg->lvs; comp; comp = comp->next)
+ if (comp->internal_id[0] == ptr[0]
+ && grub_memcmp (ptr + 1, comp->internal_id + 1,
+ comp->internal_id[0]) == 0)
+ goto out;
+ continue;
+ out:
+ if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
+ || ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
+ {
+ goto fail2;
+ }
+ ptr += *ptr + 1;
+ struct grub_diskfilter_pv *pv;
+ for (pv = vg->pvs; pv; pv = pv->next)
+ if (pv->internal_id[0] == ptr[0]
+ && grub_memcmp (pv->internal_id + 1, ptr + 1, ptr[0]) == 0)
+ part.pv = pv;
+
+ if (comp->segment_alloc == 1)
+ {
+ unsigned index;
+ ptr += *ptr + 1;
+ if (ptr + *ptr + 1 >= vblk[i].dynamic
+ + sizeof (vblk[i].dynamic))
+ {
+ goto fail2;
+ }
+ index = read_int (ptr + 1, *ptr);
+ if (index < comp->segments->node_count)
+ comp->segments->nodes[index] = part;
+ }
+ else
+ {
+ if (comp->segment_alloc == comp->segment_count)
+ {
+ void *t;
+ comp->segment_alloc *= 2;
+ t = grub_realloc (comp->segments,
+ comp->segment_alloc
+ * sizeof (*comp->segments));
+ if (!t)
+ goto fail2;
+ comp->segments = t;
+ }
+ comp->segments[comp->segment_count].start_extent = start;
+ comp->segments[comp->segment_count].extent_count = size;
+ comp->segments[comp->segment_count].type = GRUB_DISKFILTER_STRIPED;
+ comp->segments[comp->segment_count].node_count = 1;
+ comp->segments[comp->segment_count].node_alloc = 1;
+ comp->segments[comp->segment_count].nodes
+ = grub_malloc (sizeof (*comp->segments[comp->segment_count].nodes));
+ if (!comp->segments[comp->segment_count].nodes)
+ goto fail2;
+ comp->segments[comp->segment_count].nodes[0] = part;
+ comp->segment_count++;
+ }
+ }
+ }
+ if (grub_diskfilter_vg_register (vg))
+ goto fail2;
+ return vg;
+ fail2:
+ {
+ struct grub_diskfilter_lv *lv, *next_lv;
+ struct grub_diskfilter_pv *pv, *next_pv;
+ for (lv = vg->lvs; lv; lv = next_lv)
+ {
+ unsigned i;
+ for (i = 0; i < lv->segment_count; i++)
+ grub_free (lv->segments[i].nodes);
+
+ next_lv = lv->next;
+ grub_free (lv->segments);
+ grub_free (lv->internal_id);
+ grub_free (lv->name);
+ grub_free (lv->fullname);
+ grub_free (lv);
+ }
+ for (pv = vg->pvs; pv; pv = next_pv)
+ {
+ next_pv = pv->next;
+ grub_free (pv->id.uuid);
+ grub_free (pv);
+ }
+ }
+ grub_free (vg->uuid);
+ grub_free (vg);
+ return NULL;
+}
+
+static struct grub_diskfilter_vg *
+grub_ldm_detect (grub_disk_t disk,
+ struct grub_diskfilter_pv_id *id,
+ grub_disk_addr_t *start_sector)
+{
+ grub_err_t err;
+ struct grub_ldm_label label;
+ struct grub_diskfilter_vg *vg;
+
+#ifdef GRUB_UTIL
+ grub_util_info ("scanning %s for LDM", disk->name);
+#endif
+
+ {
+ int i;
+ for (i = 0; i < 3; i++)
+ {
+ grub_disk_addr_t sector;
+ switch (i)
+ {
+ case 0:
+ sector = LDM_LABEL_SECTOR;
+ break;
+ case 1:
+ /* LDM is never inside a partition. */
+ if (disk->partition)
+ continue;
+ sector = grub_disk_get_size (disk);
+ if (sector == GRUB_DISK_SIZE_UNKNOWN)
+ continue;
+ sector--;
+ break;
+ /* FIXME: try the third copy. */
+ case 2:
+ sector = gpt_ldm_sector (disk);
+ if (!sector)
+ continue;
+ break;
+ }
+ err = grub_disk_read (disk, sector, 0,
+ sizeof(label), &label);
+ if (err)
+ return NULL;
+ if (grub_memcmp (label.magic, LDM_MAGIC, sizeof (label.magic)) == 0
+ && grub_be_to_cpu16 (label.ver_major) == 0x02
+ && grub_be_to_cpu16 (label.ver_minor) >= 0x0b
+ && grub_be_to_cpu16 (label.ver_minor) <= 0x0c)
+ break;
+ }
+
+ /* Return if we didn't find a label. */
+ if (i == 3)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("no LDM signature found");
+#endif
+ return NULL;
+ }
+ }
+
+ id->uuid = grub_malloc (LDM_GUID_STRLEN + 1);
+ if (!id->uuid)
+ return NULL;
+ grub_memcpy (id->uuid, label.disk_guid, LDM_GUID_STRLEN);
+ id->uuid[LDM_GUID_STRLEN] = 0;
+ id->uuidlen = grub_strlen ((char *) id->uuid);
+ *start_sector = grub_be_to_cpu64 (label.pv_start);
+
+ {
+ grub_size_t s;
+ for (s = 0; s < LDM_GUID_STRLEN && label.group_guid[s]; s++);
+ vg = grub_diskfilter_get_vg_by_uuid (s, label.group_guid);
+ if (! vg)
+ vg = make_vg (disk, &label);
+ }
+
+ if (!vg)
+ {
+ grub_free (id->uuid);
+ return NULL;
+ }
+ return vg;
+}
+
+#ifdef GRUB_UTIL
+
+char *
+grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start)
+{
+ struct grub_diskfilter_pv *pv = NULL;
+ struct grub_diskfilter_vg *vg = NULL;
+ struct grub_diskfilter_lv *res, *lv;
+ int i;
+
+ pv = grub_diskfilter_get_pv_from_disk (disk, &vg);
+
+ if (!pv)
+ return NULL;
+
+ for (lv = vg->lvs; lv; lv = lv->next)
+ if (lv->segment_count == 1 && lv->segments->node_count == 1
+ && lv->segments->type == GRUB_DISKFILTER_STRIPED
+ && lv->segments->nodes->pv == pv
+ && lv->segments->nodes->start + pv->start_sector == start)
+ {
+ res = lv;
+ break;
+ }
+ for (lv = vg->lvs; lv; lv = lv->next)
+ if (lv->segment_count == 1 && lv->segments->node_count == 1
+ && lv->segments->type == GRUB_DISKFILTER_MIRROR
+ && lv->segments->nodes->lv == lv)
+ {
+ res = lv;
+ break;
+ }
+ if (res->fullname)
+ return grub_strdup (lv->fullname);
+ return NULL;
+}
+
+int
+grub_util_is_ldm (grub_disk_t disk)
+{
+ int i;
+ for (i = 0; i < 3; i++)
+ {
+ grub_disk_addr_t sector;
+ grub_err_t err;
+ struct grub_ldm_label label;
+
+ switch (i)
+ {
+ case 0:
+ sector = LDM_LABEL_SECTOR;
+ break;
+ case 1:
+ /* LDM is never inside a partition. */
+ if (disk->partition)
+ continue;
+ sector = grub_disk_get_size (disk);
+ if (sector == GRUB_DISK_SIZE_UNKNOWN)
+ continue;
+ sector--;
+ break;
+ /* FIXME: try the third copy. */
+ case 2:
+ sector = gpt_ldm_sector (disk);
+ if (!sector)
+ continue;
+ break;
+ }
+ err = grub_disk_read (disk, sector, 0, sizeof(label), &label);
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return 0;
+ }
+ /* This check is more relaxed on purpose. */
+ if (grub_memcmp (label.magic, LDM_MAGIC, sizeof (label.magic)) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+grub_err_t
+grub_util_ldm_embed (struct grub_disk *disk, unsigned int *nsectors,
+ grub_embed_type_t embed_type,
+ grub_disk_addr_t **sectors)
+{
+ struct grub_diskfilter_pv *pv = NULL;
+ struct grub_diskfilter_vg *vg;
+ struct grub_diskfilter_lv *lv;
+ unsigned i;
+
+ if (embed_type != GRUB_EMBED_PCBIOS)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "GPT curently supports only PC-BIOS embedding");
+ if (disk->partition)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "disk isn't LDM");
+ pv = grub_diskfilter_get_pv_from_disk (disk, &vg);
+ if (!pv)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "disk isn't LDM");
+ for (lv = vg->lvs; lv; lv = lv->next)
+ {
+ struct grub_diskfilter_lv *comp;
+ struct grub_ldm_partition *part;
+
+ if (!lv->visible || !lv->fullname)
+ continue;
+
+ if (lv->segment_count != 1)
+ continue;
+ if (lv->segments->type != GRUB_DISKFILTER_MIRROR
+ || lv->segments->node_count != 1
+ || lv->segments->start_extent != 0
+ || lv->segments->extent_count != lv->size)
+ continue;
+
+ comp = lv->segments->nodes->lv;
+ if (!comp)
+ continue;
+
+ if (comp->segment_count != 1 || comp->size != lv->size)
+ continue;
+ if (comp->segments->type != GRUB_DISKFILTER_STRIPED
+ || comp->segments->node_count != 1
+ || comp->segments->start_extent != 0
+ || comp->segments->extent_count != lv->size)
+ continue;
+
+ /* How to implement proper check is to be discussed. */
+#if 1
+ if (1)
+ continue;
+#else
+ if (grub_strcmp (lv->name, "Volume5") != 0)
+ continue;
+#endif
+ if (lv->size < *nsectors)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ "Your LDM embed Partition is too small;"
+ " embedding won't be possible!");
+ *nsectors = lv->size;
+ *sectors = grub_malloc (*nsectors * sizeof (**sectors));
+ if (!*sectors)
+ return grub_errno;
+ for (i = 0; i < *nsectors; i++)
+ (*sectors)[i] = (lv->segments->nodes->start
+ + comp->segments->nodes->start
+ + comp->segments->nodes->pv->start_sector + i);
+ return GRUB_ERR_NONE;
+ }
+
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ "This LDM no Embedding Partition;"
+ " embedding won't be possible!");
+}
+#endif
+
+static struct grub_diskfilter grub_ldm_dev = {
+ .name = "ldm",
+ .detect = grub_ldm_detect,
+ .next = 0
+};
+
+GRUB_MOD_INIT (ldm)
+{
+ grub_diskfilter_register (&grub_ldm_dev);
+}
+
+GRUB_MOD_FINI (ldm)
+{
+ grub_diskfilter_unregister (&grub_ldm_dev);
+}
=== modified file 'grub-core/disk/lvm.c'
--- grub-core/disk/lvm.c 2011-11-30 15:20:13 +0000
+++ grub-core/disk/lvm.c 2012-01-28 14:32:56 +0000
@@ -33,12 +33,6 @@
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);
-
\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
@@ -50,7 +44,7 @@
if (! *p)
return 0;
*p += grub_strlen (str);
- return grub_strtoul (*p, NULL, 10);
+ return grub_strtoul (*p, p, 10);
}
#if 0
@@ -101,932 +95,660 @@
}
}
-static struct grub_lvm_lv *
-find_lv (const char *name)
-{
- struct grub_lvm_vg *vg;
- struct grub_lvm_lv *lv = NULL;
- for (vg = vg_list; vg; vg = vg->next)
- {
- if (vg->lvs)
- for (lv = vg->lvs; lv; lv = lv->next)
- if ((grub_strcmp (lv->fullname, name) == 0
- || grub_strcmp (lv->compatname, name) == 0)
- && is_lv_readable (lv))
- return lv;
- }
- return NULL;
-}
-
-static void
-do_lvm_scan (const char *scan_for)
-{
- auto int grub_lvm_scan_device (const char *name);
- int grub_lvm_scan_device (const char *name)
- {
- grub_err_t err;
- grub_disk_t disk;
- grub_uint64_t mda_offset, mda_size;
- char buf[GRUB_LVM_LABEL_SIZE];
- char vg_id[GRUB_LVM_ID_STRLEN+1];
- char pv_id[GRUB_LVM_ID_STRLEN+1];
- char *metadatabuf, *p, *q, *vgname;
- struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf;
- struct grub_lvm_pv_header *pvh;
- struct grub_lvm_disk_locn *dlocn;
- struct grub_lvm_mda_header *mdah;
- struct grub_lvm_raw_locn *rlocn;
- unsigned int i, j, vgname_len;
- struct grub_lvm_vg *vg;
- struct grub_lvm_pv *pv;
-
-#ifdef GRUB_UTIL
- grub_util_info ("scanning %s for LVM", name);
-#endif
-
- disk = grub_disk_open (name);
- if (!disk)
- {
- if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
- grub_errno = GRUB_ERR_NONE;
- 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_partition_get_start (pv->disk->partition)
- == grub_partition_get_start (disk->partition)
- && grub_disk_get_size (pv->disk)
- == grub_disk_get_size (disk))
- {
- grub_disk_close (disk);
- return 0;
- }
-
- /* Search for label. */
- for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++)
- {
- err = grub_disk_read (disk, i, 0, sizeof(buf), buf);
- if (err)
- goto fail;
-
- if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID,
- sizeof (lh->id)))
- && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL,
- sizeof (lh->type))))
- break;
- }
-
- /* Return if we didn't find a label. */
- if (i == GRUB_LVM_LABEL_SCAN_SECTORS)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("no LVM signature found");
-#endif
- goto fail;
- }
-
- pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
-
- for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++)
- {
- pv_id[j++] = pvh->pv_uuid[i];
- if ((i != 1) && (i != 29) && (i % 4 == 1))
- pv_id[j++] = '-';
- }
- pv_id[j] = '\0';
-
- dlocn = pvh->disk_areas_xl;
-
- dlocn++;
- /* Is it possible to have multiple data/metadata areas? I haven't
- seen devices that have it. */
- if (dlocn->offset)
- {
- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "we don't support multiple LVM data areas");
-
-#ifdef GRUB_UTIL
- grub_util_info ("we don't support multiple LVM data areas\n");
-#endif
- goto fail;
- }
-
- dlocn++;
- mda_offset = grub_le_to_cpu64 (dlocn->offset);
- mda_size = grub_le_to_cpu64 (dlocn->size);
-
- /* It's possible to have multiple copies of metadata areas, we just use the
- first one. */
-
- /* Allocate buffer space for the circular worst-case scenario. */
- metadatabuf = grub_malloc (2 * mda_size);
- if (! metadatabuf)
- goto fail;
-
- err = grub_disk_read (disk, 0, mda_offset, mda_size, metadatabuf);
- if (err)
- goto fail2;
-
- mdah = (struct grub_lvm_mda_header *) metadatabuf;
- if ((grub_strncmp ((char *)mdah->magic, GRUB_LVM_FMTT_MAGIC,
- sizeof (mdah->magic)))
- || (grub_le_to_cpu32 (mdah->version) != GRUB_LVM_FMTT_VERSION))
- {
- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "unknown LVM metadata header");
-#ifdef GRUB_UTIL
- grub_util_info ("unknown LVM metadata header\n");
-#endif
- goto fail2;
- }
-
- rlocn = mdah->raw_locns;
- if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) >
- grub_le_to_cpu64 (mdah->size))
- {
- /* Metadata is circular. Copy the wrap in place. */
- grub_memcpy (metadatabuf + mda_size,
- metadatabuf + GRUB_LVM_MDA_HEADER_SIZE,
- grub_le_to_cpu64 (rlocn->offset) +
- grub_le_to_cpu64 (rlocn->size) -
- grub_le_to_cpu64 (mdah->size));
- }
- p = q = metadatabuf + grub_le_to_cpu64 (rlocn->offset);
-
- while (*q != ' ' && q < metadatabuf + mda_size)
- q++;
-
- if (q == metadatabuf + mda_size)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("error parsing metadata\n");
-#endif
- goto fail2;
- }
-
- vgname_len = q - p;
- vgname = grub_malloc (vgname_len + 1);
- if (!vgname)
- goto fail2;
-
- grub_memcpy (vgname, p, vgname_len);
- vgname[vgname_len] = '\0';
-
- p = grub_strstr (q, "id = \"");
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("couldn't find ID\n");
-#endif
- goto fail3;
- }
- p += sizeof ("id = \"") - 1;
- grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN);
- vg_id[GRUB_LVM_ID_STRLEN] = '\0';
-
- for (vg = vg_list; vg; vg = vg->next)
- {
- if (! grub_memcmp(vg_id, vg->id, GRUB_LVM_ID_STRLEN))
- break;
- }
-
- if (! vg)
- {
- /* First time we see this volume group. We've to create the
- whole volume group structure. */
- vg = grub_malloc (sizeof (*vg));
- if (! vg)
- goto fail3;
- vg->name = vgname;
- grub_memcpy (vg->id, vg_id, GRUB_LVM_ID_STRLEN+1);
-
- vg->extent_size = grub_lvm_getvalue (&p, "extent_size = ");
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("unknown extent size\n");
-#endif
- goto fail4;
- }
-
- vg->lvs = NULL;
- vg->pvs = NULL;
-
- p = grub_strstr (p, "physical_volumes {");
- if (p)
- {
- p += sizeof ("physical_volumes {") - 1;
-
- /* Add all the pvs to the volume group. */
- while (1)
+static struct grub_diskfilter_vg *
+grub_lvm_detect (grub_disk_t disk,
+ struct grub_diskfilter_pv_id *id,
+ grub_disk_addr_t *start_sector)
+{
+ grub_err_t err;
+ grub_uint64_t mda_offset, mda_size;
+ char buf[GRUB_LVM_LABEL_SIZE];
+ char vg_id[GRUB_LVM_ID_STRLEN+1];
+ char pv_id[GRUB_LVM_ID_STRLEN+1];
+ char *metadatabuf, *p, *q, *vgname;
+ struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf;
+ struct grub_lvm_pv_header *pvh;
+ struct grub_lvm_disk_locn *dlocn;
+ struct grub_lvm_mda_header *mdah;
+ struct grub_lvm_raw_locn *rlocn;
+ unsigned int i, j, vgname_len;
+ struct grub_diskfilter_vg *vg;
+ struct grub_diskfilter_pv *pv;
+
+ /* Search for label. */
+ for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++)
+ {
+ err = grub_disk_read (disk, i, 0, sizeof(buf), buf);
+ if (err)
+ goto fail;
+
+ if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID,
+ sizeof (lh->id)))
+ && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL,
+ sizeof (lh->type))))
+ break;
+ }
+
+ /* Return if we didn't find a label. */
+ if (i == GRUB_LVM_LABEL_SCAN_SECTORS)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("no LVM signature found");
+#endif
+ goto fail;
+ }
+
+ pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
+
+ for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++)
+ {
+ pv_id[j++] = pvh->pv_uuid[i];
+ if ((i != 1) && (i != 29) && (i % 4 == 1))
+ pv_id[j++] = '-';
+ }
+ pv_id[j] = '\0';
+
+ dlocn = pvh->disk_areas_xl;
+
+ dlocn++;
+ /* Is it possible to have multiple data/metadata areas? I haven't
+ seen devices that have it. */
+ if (dlocn->offset)
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "we don't support multiple LVM data areas");
+
+#ifdef GRUB_UTIL
+ grub_util_info ("we don't support multiple LVM data areas\n");
+#endif
+ goto fail;
+ }
+
+ dlocn++;
+ mda_offset = grub_le_to_cpu64 (dlocn->offset);
+ mda_size = grub_le_to_cpu64 (dlocn->size);
+
+ /* It's possible to have multiple copies of metadata areas, we just use the
+ first one. */
+
+ /* Allocate buffer space for the circular worst-case scenario. */
+ metadatabuf = grub_malloc (2 * mda_size);
+ if (! metadatabuf)
+ goto fail;
+
+ err = grub_disk_read (disk, 0, mda_offset, mda_size, metadatabuf);
+ if (err)
+ goto fail2;
+
+ mdah = (struct grub_lvm_mda_header *) metadatabuf;
+ if ((grub_strncmp ((char *)mdah->magic, GRUB_LVM_FMTT_MAGIC,
+ sizeof (mdah->magic)))
+ || (grub_le_to_cpu32 (mdah->version) != GRUB_LVM_FMTT_VERSION))
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "unknown LVM metadata header");
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown LVM metadata header\n");
+#endif
+ goto fail2;
+ }
+
+ rlocn = mdah->raw_locns;
+ if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) >
+ grub_le_to_cpu64 (mdah->size))
+ {
+ /* Metadata is circular. Copy the wrap in place. */
+ grub_memcpy (metadatabuf + mda_size,
+ metadatabuf + GRUB_LVM_MDA_HEADER_SIZE,
+ grub_le_to_cpu64 (rlocn->offset) +
+ grub_le_to_cpu64 (rlocn->size) -
+ grub_le_to_cpu64 (mdah->size));
+ }
+ p = q = metadatabuf + grub_le_to_cpu64 (rlocn->offset);
+
+ while (*q != ' ' && q < metadatabuf + mda_size)
+ q++;
+
+ if (q == metadatabuf + mda_size)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("error parsing metadata\n");
+#endif
+ goto fail2;
+ }
+
+ vgname_len = q - p;
+ vgname = grub_malloc (vgname_len + 1);
+ if (!vgname)
+ goto fail2;
+
+ grub_memcpy (vgname, p, vgname_len);
+ vgname[vgname_len] = '\0';
+
+ p = grub_strstr (q, "id = \"");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("couldn't find ID\n");
+#endif
+ goto fail3;
+ }
+ p += sizeof ("id = \"") - 1;
+ grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN);
+ vg_id[GRUB_LVM_ID_STRLEN] = '\0';
+
+ vg = grub_diskfilter_get_vg_by_uuid (GRUB_LVM_ID_STRLEN, vg_id);
+
+ if (! vg)
+ {
+ /* First time we see this volume group. We've to create the
+ whole volume group structure. */
+ vg = grub_malloc (sizeof (*vg));
+ if (! vg)
+ goto fail3;
+ vg->name = vgname;
+ vg->uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
+ if (! vg->uuid)
+ goto fail3;
+ grub_memcpy (vg->uuid, vg_id, GRUB_LVM_ID_STRLEN);
+ vg->uuid_len = GRUB_LVM_ID_STRLEN;
+
+ vg->extent_size = grub_lvm_getvalue (&p, "extent_size = ");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown extent size\n");
+#endif
+ goto fail4;
+ }
+
+ vg->lvs = NULL;
+ vg->pvs = NULL;
+
+ p = grub_strstr (p, "physical_volumes {");
+ if (p)
+ {
+ p += sizeof ("physical_volumes {") - 1;
+
+ /* Add all the pvs to the volume group. */
+ while (1)
+ {
+ int s;
+ while (grub_isspace (*p))
+ p++;
+
+ if (*p == '}')
+ break;
+
+ pv = grub_zalloc (sizeof (*pv));
+ q = p;
+ while (*q != ' ')
+ q++;
+
+ s = q - p;
+ pv->name = grub_malloc (s + 1);
+ grub_memcpy (pv->name, p, s);
+ pv->name[s] = '\0';
+
+ p = grub_strstr (p, "id = \"");
+ if (p == NULL)
+ goto pvs_fail;
+ p += sizeof("id = \"") - 1;
+
+ pv->id.uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
+ if (!pv->id.uuid)
+ goto pvs_fail;
+ grub_memcpy (pv->id.uuid, p, GRUB_LVM_ID_STRLEN);
+ pv->id.uuidlen = GRUB_LVM_ID_STRLEN;
+
+ pv->start_sector = grub_lvm_getvalue (&p, "pe_start = ");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown pe_start\n");
+#endif
+ goto pvs_fail;
+ }
+
+ p = grub_strchr (p, '}');
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("error parsing pe_start\n");
+#endif
+ goto pvs_fail;
+ }
+ p++;
+
+ pv->disk = NULL;
+ pv->next = vg->pvs;
+ vg->pvs = pv;
+
+ continue;
+ pvs_fail:
+ grub_free (pv->name);
+ grub_free (pv);
+ goto fail4;
+ }
+ }
+
+ p = grub_strstr (p, "logical_volumes");
+ if (p)
+ {
+ p += sizeof ("logical_volumes = ") - 1;
+
+ /* And add all the lvs to the volume group. */
+ while (1)
+ {
+ int s;
+ int skip_lv = 0;
+ struct grub_diskfilter_lv *lv;
+ struct grub_diskfilter_segment *seg;
+ int is_pvmove;
+
+ while (grub_isspace (*p))
+ p++;
+
+ if (*p == '}')
+ break;
+
+ lv = grub_zalloc (sizeof (*lv));
+
+ q = p;
+ while (*q != ' ')
+ q++;
+
+ s = q - p;
+ lv->name = grub_strndup (p, s);
+ if (!lv->name)
+ goto lvs_fail;
+
{
- int s;
- while (grub_isspace (*p))
- p++;
-
- if (*p == '}')
- break;
-
- pv = grub_malloc (sizeof (*pv));
- q = p;
- while (*q != ' ')
- q++;
-
- s = q - p;
- pv->name = grub_malloc (s + 1);
- grub_memcpy (pv->name, p, s);
- pv->name[s] = '\0';
-
- p = grub_strstr (p, "id = \"");
- if (p == NULL)
- goto pvs_fail;
- p += sizeof("id = \"") - 1;
-
- grub_memcpy (pv->id, p, GRUB_LVM_ID_STRLEN);
- pv->id[GRUB_LVM_ID_STRLEN] = '\0';
-
- pv->start = grub_lvm_getvalue (&p, "pe_start = ");
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("unknown pe_start\n");
-#endif
- goto pvs_fail;
- }
-
+ const char *iptr;
+ char *optr;
+ lv->fullname = grub_malloc (sizeof ("lvm/") - 1 + 2 * vgname_len
+ + 1 + 2 * s + 1);
+ if (!lv->fullname)
+ goto lvs_fail;
+
+ grub_memcpy (lv->fullname, "lvm/", sizeof ("lvm/") - 1);
+ optr = lv->fullname + 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->visible = grub_lvm_check_flag (p, "status", "VISIBLE");
+ is_pvmove = grub_lvm_check_flag (p, "status", "PVMOVE");
+
+ lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown segment_count\n");
+#endif
+ goto lvs_fail;
+ }
+ lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count);
+ seg = lv->segments;
+
+ for (i = 0; i < lv->segment_count; i++)
+ {
+
+ p = grub_strstr (p, "segment");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown segment\n");
+#endif
+ goto lvs_segment_fail;
+ }
+
+ seg->start_extent = grub_lvm_getvalue (&p, "start_extent = ");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown start_extent\n");
+#endif
+ goto lvs_segment_fail;
+ }
+ seg->extent_count = grub_lvm_getvalue (&p, "extent_count = ");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown extent_count\n");
+#endif
+ goto lvs_segment_fail;
+ }
+
+ p = grub_strstr (p, "type = \"");
+ if (p == NULL)
+ goto lvs_segment_fail;
+ p += sizeof("type = \"") - 1;
+
+ lv->size += seg->extent_count * vg->extent_size;
+
+ if (grub_memcmp (p, "striped\"",
+ sizeof ("striped\"") - 1) == 0)
+ {
+ struct grub_diskfilter_node *stripe;
+
+ seg->type = GRUB_DISKFILTER_STRIPED;
+ seg->node_count = grub_lvm_getvalue (&p, "stripe_count = ");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown stripe_count\n");
+#endif
+ goto lvs_segment_fail;
+ }
+
+ if (seg->node_count != 1)
+ seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
+
+ seg->nodes = grub_zalloc (sizeof (*stripe)
+ * seg->node_count);
+ stripe = seg->nodes;
+
+ p = grub_strstr (p, "stripes = [");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown stripes\n");
+#endif
+ goto lvs_segment_fail2;
+ }
+ p += sizeof("stripes = [") - 1;
+
+ for (j = 0; j < seg->node_count; j++)
+ {
+ p = grub_strchr (p, '"');
+ if (p == NULL)
+ continue;
+ q = ++p;
+ while (*q != '"')
+ q++;
+
+ s = q - p;
+
+ stripe->name = grub_malloc (s + 1);
+ if (stripe->name == NULL)
+ goto lvs_segment_fail2;
+
+ grub_memcpy (stripe->name, p, s);
+ stripe->name[s] = '\0';
+
+ p = q + 1;
+
+ stripe->start = grub_lvm_getvalue (&p, ",")
+ * vg->extent_size;
+ if (p == NULL)
+ continue;
+
+ stripe++;
+ }
+ }
+ else if (grub_memcmp (p, "mirror\"", sizeof ("mirror\"") - 1)
+ == 0)
+ {
+ seg->type = GRUB_DISKFILTER_MIRROR;
+ seg->node_count = grub_lvm_getvalue (&p, "mirror_count = ");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown mirror_count\n");
+#endif
+ goto lvs_segment_fail;
+ }
+
+ seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
+ * seg->node_count);
+
+ p = grub_strstr (p, "mirrors = [");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown mirrors\n");
+#endif
+ goto lvs_segment_fail2;
+ }
+ p += sizeof("mirrors = [") - 1;
+
+ for (j = 0; j < seg->node_count; j++)
+ {
+ char *lvname;
+
+ p = grub_strchr (p, '"');
+ if (p == NULL)
+ continue;
+ q = ++p;
+ while (*q != '"')
+ q++;
+
+ s = q - p;
+
+ lvname = grub_malloc (s + 1);
+ if (lvname == NULL)
+ goto lvs_segment_fail2;
+
+ grub_memcpy (lvname, p, s);
+ lvname[s] = '\0';
+ seg->nodes[j].name = lvname;
+ p = q + 1;
+ }
+ /* Only first (original) is ok with in progress pvmove. */
+ if (is_pvmove)
+ seg->node_count = 1;
+ }
+ else if (grub_memcmp (p, "raid", sizeof ("raid") - 1)
+ == 0 && (p[sizeof ("raid") - 1] >= '4'
+ && p[sizeof ("raid") - 1] <= '6')
+ && p[sizeof ("raidX") - 1] == '"')
+ {
+ switch (p[sizeof ("raid") - 1])
+ {
+ case '4':
+ seg->type = GRUB_DISKFILTER_RAID4;
+ seg->layout = 0;
+ break;
+ case '5':
+ seg->type = GRUB_DISKFILTER_RAID5;
+ seg->layout = GRUB_RAID_LAYOUT_SYMMETRIC_MASK;
+ break;
+ case '6':
+ seg->type = GRUB_DISKFILTER_RAID6;
+ seg->layout = GRUB_RAID_LAYOUT_RIGHT_MASK;
+ break;
+ }
+ seg->node_count = grub_lvm_getvalue (&p, "device_count = ");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown device_count\n");
+#endif
+ goto lvs_segment_fail;
+ }
+
+ seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown stripe_size\n");
+#endif
+ goto lvs_segment_fail;
+ }
+
+
+ seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
+ * seg->node_count);
+
+ p = grub_strstr (p, "raids = [");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown mirrors\n");
+#endif
+ goto lvs_segment_fail2;
+ }
+ p += sizeof("raids = [") - 1;
+
+ for (j = 0; j < seg->node_count; j++)
+ {
+ char *lvname;
+
+ p = grub_strchr (p, '"');
+ p = p ? grub_strchr (p + 1, '"') : 0;
+ p = p ? grub_strchr (p + 1, '"') : 0;
+ if (p == NULL)
+ continue;
+ q = ++p;
+ while (*q != '"')
+ q++;
+
+ s = q - p;
+
+ lvname = grub_malloc (s + 1);
+ if (lvname == NULL)
+ goto lvs_segment_fail2;
+
+ grub_memcpy (lvname, p, s);
+ lvname[s] = '\0';
+ seg->nodes[j].name = lvname;
+ p = q + 1;
+ }
+ }
+ else
+ {
+#ifdef GRUB_UTIL
+ char *p2;
+ p2 = grub_strchr (p, '"');
+ if (p2)
+ *p2 = 0;
+ grub_util_info ("unknown LVM type %s\n", p);
+ if (p2)
+ *p2 ='"';
+#endif
+ /* Found a non-supported type, give up and move on. */
+ skip_lv = 1;
+ break;
+ }
+
+ seg++;
+
+ continue;
+ lvs_segment_fail2:
+ grub_free (seg->nodes);
+ lvs_segment_fail:
+ goto fail4;
+ }
+
+ if (p != NULL)
p = grub_strchr (p, '}');
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("error parsing pe_start\n");
-#endif
- goto pvs_fail;
- }
- p++;
-
- pv->disk = NULL;
- pv->next = vg->pvs;
- vg->pvs = pv;
-
- continue;
- pvs_fail:
- grub_free (pv->name);
- grub_free (pv);
- goto fail4;
- }
- }
-
- p = grub_strstr (p, "logical_volumes");
- if (p)
- {
- p += 18;
-
- /* And add all the lvs to the volume group. */
- while (1)
+ if (p == NULL)
+ goto lvs_fail;
+ p += 3;
+
+ if (skip_lv)
+ {
+ grub_free (lv->name);
+ grub_free (lv);
+ continue;
+ }
+
+ lv->vg = vg;
+ lv->next = vg->lvs;
+ vg->lvs = lv;
+
+ continue;
+ lvs_fail:
+ grub_free (lv->name);
+ grub_free (lv);
+ goto fail4;
+ }
+ }
+
+ /* Match lvs. */
+ {
+ struct grub_diskfilter_lv *lv1;
+ struct grub_diskfilter_lv *lv2;
+ for (lv1 = vg->lvs; lv1; lv1 = lv1->next)
+ for (i = 0; i < lv1->segment_count; i++)
+ for (j = 0; j < lv1->segments[i].node_count; j++)
{
- int s;
- int skip_lv = 0;
- struct grub_lvm_lv *lv;
- struct grub_lvm_segment *seg;
- int is_pvmove;
-
- while (grub_isspace (*p))
- p++;
-
- if (*p == '}')
- break;
-
- lv = grub_malloc (sizeof (*lv));
-
- q = p;
- while (*q != ' ')
- q++;
-
- s = q - p;
- lv->name = grub_strndup (p, s);
- if (!lv->name)
- goto lvs_fail;
- lv->compatname = grub_malloc (vgname_len + 1 + s + 1);
- 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->visible = grub_lvm_check_flag (p, "status", "VISIBLE");
- is_pvmove = grub_lvm_check_flag (p, "status", "PVMOVE");
-
- lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("unknown segment_count\n");
-#endif
- goto lvs_fail;
- }
- lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count);
- seg = lv->segments;
-
- for (i = 0; i < lv->segment_count; i++)
- {
-
- p = grub_strstr (p, "segment");
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("unknown segment\n");
-#endif
- goto lvs_segment_fail;
- }
-
- seg->start_extent = grub_lvm_getvalue (&p, "start_extent = ");
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("unknown start_extent\n");
-#endif
- goto lvs_segment_fail;
- }
- seg->extent_count = grub_lvm_getvalue (&p, "extent_count = ");
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("unknown extent_count\n");
-#endif
- goto lvs_segment_fail;
- }
-
- p = grub_strstr (p, "type = \"");
- if (p == NULL)
- goto lvs_segment_fail;
- p += sizeof("type = \"") - 1;
-
- lv->size += seg->extent_count * vg->extent_size;
-
- if (grub_memcmp (p, "striped\"",
- sizeof ("striped\"") - 1) == 0)
- {
- struct grub_lvm_node *stripe;
-
- seg->type = GRUB_LVM_STRIPED;
- seg->node_count = grub_lvm_getvalue (&p, "stripe_count = ");
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("unknown stripe_count\n");
-#endif
- goto lvs_segment_fail;
- }
-
- if (seg->node_count != 1)
- seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
-
- seg->nodes = grub_zalloc (sizeof (*stripe)
- * seg->node_count);
- stripe = seg->nodes;
-
- p = grub_strstr (p, "stripes = [");
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("unknown stripes\n");
-#endif
- goto lvs_segment_fail2;
- }
- p += sizeof("stripes = [") - 1;
-
- for (j = 0; j < seg->node_count; j++)
- {
- p = grub_strchr (p, '"');
- if (p == NULL)
- continue;
- q = ++p;
- while (*q != '"')
- q++;
-
- s = q - p;
-
- stripe->name = grub_malloc (s + 1);
- if (stripe->name == NULL)
- goto lvs_segment_fail2;
-
- grub_memcpy (stripe->name, p, s);
- stripe->name[s] = '\0';
-
- stripe->start = grub_lvm_getvalue (&p, ",");
- if (p == NULL)
- continue;
-
- stripe++;
- }
- }
- else if (grub_memcmp (p, "mirror\"", sizeof ("mirror\"") - 1)
- == 0)
- {
- seg->type = GRUB_LVM_MIRROR;
- seg->node_count = grub_lvm_getvalue (&p, "mirror_count = ");
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("unknown mirror_count\n");
-#endif
- goto lvs_segment_fail;
- }
-
- seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
- * seg->node_count);
-
- p = grub_strstr (p, "mirrors = [");
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("unknown mirrors\n");
-#endif
- goto lvs_segment_fail2;
- }
- p += sizeof("mirrors = [") - 1;
-
- for (j = 0; j < seg->node_count; j++)
- {
- char *lvname;
-
- p = grub_strchr (p, '"');
- if (p == NULL)
- continue;
- q = ++p;
- while (*q != '"')
- q++;
-
- s = q - p;
-
- lvname = grub_malloc (s + 1);
- if (lvname == NULL)
- goto lvs_segment_fail2;
-
- grub_memcpy (lvname, p, s);
- lvname[s] = '\0';
- seg->nodes[j].name = lvname;
- p = q + 1;
- }
- /* Only first (original) is ok with in progress pvmove. */
- if (is_pvmove)
- seg->node_count = 1;
- }
- else
- {
-#ifdef GRUB_UTIL
- char *p2;
- p2 = grub_strchr (p, '"');
- if (p2)
- *p2 = 0;
- grub_util_info ("unknown LVM type %s\n", p);
- if (p2)
- *p2 ='"';
-#endif
- /* Found a non-supported type, give up and move on. */
- skip_lv = 1;
- break;
- }
-
- seg++;
-
- continue;
- lvs_segment_fail2:
- grub_free (seg->nodes);
- lvs_segment_fail:
- goto fail4;
- }
-
- if (p != NULL)
- p = grub_strchr (p, '}');
- if (p == NULL)
- goto lvs_fail;
- p += 3;
-
- if (skip_lv)
- {
- grub_free (lv->name);
- grub_free (lv);
- continue;
- }
-
- lv->number = lv_count++;
- lv->vg = vg;
- lv->next = vg->lvs;
- vg->lvs = lv;
-
- continue;
- lvs_fail:
- grub_free (lv->name);
- grub_free (lv);
- goto fail4;
+ if (vg->pvs)
+ for (pv = vg->pvs; pv; pv = pv->next)
+ {
+ if (! grub_strcmp (pv->name,
+ lv1->segments[i].nodes[j].name))
+ {
+ lv1->segments[i].nodes[j].pv = pv;
+ break;
+ }
+ }
+ if (lv1->segments[i].nodes[j].pv == NULL)
+ for (lv2 = vg->lvs; lv2; lv2 = lv2->next)
+ if (grub_strcmp (lv2->name,
+ lv1->segments[i].nodes[j].name) == 0)
+ lv1->segments[i].nodes[j].lv = lv2;
}
- }
-
- /* Match lvs. */
- {
- struct grub_lvm_lv *lv1;
- struct grub_lvm_lv *lv2;
- for (lv1 = vg->lvs; lv1; lv1 = lv1->next)
- for (i = 0; i < lv1->segment_count; i++)
- for (j = 0; j < lv1->segments[i].node_count; j++)
- {
- if (vg->pvs)
- for (pv = vg->pvs; pv; pv = pv->next)
- {
- if (! grub_strcmp (pv->name,
- lv1->segments[i].nodes[j].name))
- {
- lv1->segments[i].nodes[j].pv = pv;
- break;
- }
- }
- if (lv1->segments[i].nodes[j].pv == NULL)
- for (lv2 = vg->lvs; lv2; lv2 = lv2->next)
- if (grub_strcmp (lv2->name + grub_strlen (vg->name) + 1,
- lv1->segments[i].nodes[j].name) == 0)
- lv1->segments[i].nodes[j].lv = lv2;
- }
- }
-
- vg->next = vg_list;
- vg_list = vg;
- }
- else
- {
- grub_free (vgname);
- }
-
- /* Match the device we are currently reading from with the right
- PV. */
- if (vg->pvs)
- for (pv = vg->pvs; pv; pv = pv->next)
- {
- if (! grub_memcmp (pv->id, pv_id, GRUB_LVM_ID_STRLEN))
- {
- /* This could happen to LVM on RAID, pv->disk points to the
- raid device, we shouldn't change it. */
- if (! pv->disk)
- pv->disk = grub_disk_open (name);
- break;
- }
- }
-
- goto fail2;
-
- /* Failure path. */
- fail4:
- grub_free (vg);
- fail3:
- grub_free (vgname);
-
- /* Normal exit path. */
- fail2:
- grub_free (metadatabuf);
- fail:
- grub_disk_close (disk);
- 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;
- }
-
- scan_depth++;
- grub_device_iterate (&grub_lvm_scan_device);
- scan_depth--;
-}
-
-static int
-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)
- do_lvm_scan (NULL);
- }
- 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 && lv->number >= old_count)
- {
- if (hook (lv->fullname))
- return 1;
- }
- }
-
- return 0;
-}
-
-#ifdef GRUB_UTIL
-static grub_disk_memberlist_t
-grub_lvm_memberlist (grub_disk_t disk)
-{
- struct grub_lvm_lv *lv = disk->data;
- grub_disk_memberlist_t list = NULL, tmp;
- struct grub_lvm_pv *pv;
-
- if (lv->vg->pvs)
- for (pv = lv->vg->pvs; pv; pv = pv->next)
- {
- if (!pv->disk)
- grub_util_error (_("Couldn't find PV %s. Check your device.map"),
- pv->name);
- tmp = grub_malloc (sizeof (*tmp));
- tmp->disk = pv->disk;
- tmp->next = list;
- list = tmp;
- }
-
- return list;
-}
-#endif
-
-static grub_err_t
-grub_lvm_open (const char *name, grub_disk_t disk)
-{
- 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 && explicit)
- {
- do_lvm_scan (name);
- if (grub_errno)
- {
- grub_print_error ();
- grub_errno = GRUB_ERR_NONE;
- }
- lv = find_lv (name);
- }
-
- if (! lv)
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown LVM device %s", name);
-
- disk->id = lv->number;
- disk->data = lv;
- disk->total_sectors = lv->size;
-
- return 0;
-}
-
-static void
-grub_lvm_close (grub_disk_t disk __attribute ((unused)))
-{
- return;
-}
-
-static grub_err_t
-read_lv (struct grub_lvm_lv *lv, grub_disk_addr_t sector,
- grub_size_t size, char *buf);
-
-static grub_err_t
-read_node (const struct grub_lvm_node *node, grub_disk_addr_t sector,
- grub_size_t size, char *buf)
-{
- /* Check whether we actually know the physical volume we want to
- read from. */
- if (node->pv)
- {
- if (node->pv->disk)
- return grub_disk_read (node->pv->disk, sector + node->pv->start, 0,
- size << GRUB_DISK_SECTOR_BITS, buf);
- else
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
- "physical volume %s not found", node->pv->name);
-
- }
- if (node->lv)
- return read_lv (node->lv, sector, size, buf);
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown node '%s'", node->name);
-}
-
-static grub_err_t
-read_lv (struct grub_lvm_lv *lv, grub_disk_addr_t sector,
- grub_size_t size, char *buf)
-{
- grub_err_t err = 0;
- struct grub_lvm_vg *vg = lv->vg;
- struct grub_lvm_segment *seg = lv->segments;
- struct grub_lvm_node *node;
- grub_uint64_t offset;
- grub_uint64_t extent;
- unsigned int i;
-
- if (!lv)
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown volume");
-
- extent = grub_divmod64 (sector, vg->extent_size, NULL);
-
- /* Find the right segment. */
- for (i = 0; i < lv->segment_count; i++)
- {
- if ((seg->start_extent <= extent)
- && ((seg->start_extent + seg->extent_count) > extent))
- {
- break;
- }
-
- seg++;
- }
-
- if (i == lv->segment_count)
- return grub_error (GRUB_ERR_READ_ERROR, "incorrect segment");
-
- switch (seg->type)
- {
- case GRUB_LVM_STRIPED:
- if (seg->node_count == 1)
- {
- /* This segment is linear, so that's easy. We just need to find
- out the offset in the physical volume and read SIZE bytes
- from that. */
- struct grub_lvm_node *stripe = seg->nodes;
- grub_uint64_t seg_offset; /* Offset of the segment in PV device. */
-
- node = stripe;
- seg_offset = ((grub_uint64_t) stripe->start
- * (grub_uint64_t) vg->extent_size);
-
- offset = sector - ((grub_uint64_t) seg->start_extent
- * (grub_uint64_t) vg->extent_size) + seg_offset;
- }
- else
- {
- /* This is a striped segment. We have to find the right PV
- similar to RAID0. */
- struct grub_lvm_node *stripe = seg->nodes;
- grub_uint64_t a, b;
- grub_uint64_t seg_offset; /* Offset of the segment in PV device. */
- grub_uint64_t stripenr;
-
- offset = sector - ((grub_uint64_t) seg->start_extent
- * (grub_uint64_t) vg->extent_size);
-
- a = grub_divmod64 (offset, seg->stripe_size, NULL);
- grub_divmod64 (a, seg->node_count, &stripenr);
-
- a = grub_divmod64 (offset, seg->stripe_size * seg->node_count, NULL);
- grub_divmod64 (offset, seg->stripe_size, &b);
- offset = a * seg->stripe_size + b;
-
- stripe += stripenr;
- node = stripe;
-
- seg_offset = ((grub_uint64_t) stripe->start
- * (grub_uint64_t) vg->extent_size);
-
- offset += seg_offset;
- }
- return read_node (node, offset, size, buf);
- case GRUB_LVM_MIRROR:
- i = 0;
- while (1)
- {
- err = read_node (&seg->nodes[i], sector, size, buf);
- if (!err)
- return err;
- if (++i >= seg->node_count)
- return err;
- grub_errno = GRUB_ERR_NONE;
- }
- }
- 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 read_lv (disk->data, sector, size, buf);
-}
-
-static grub_err_t
-grub_lvm_write (grub_disk_t disk __attribute ((unused)),
- grub_disk_addr_t sector __attribute ((unused)),
- grub_size_t size __attribute ((unused)),
- const char *buf __attribute ((unused)))
-{
- return GRUB_ERR_NOT_IMPLEMENTED_YET;
-}
-
-static struct grub_disk_dev grub_lvm_dev =
- {
- .name = "lvm",
- .id = GRUB_DISK_DEVICE_LVM_ID,
- .iterate = grub_lvm_iterate,
- .open = grub_lvm_open,
- .close = grub_lvm_close,
- .read = grub_lvm_read,
- .write = grub_lvm_write,
-#ifdef GRUB_UTIL
- .memberlist = grub_lvm_memberlist,
-#endif
- .next = 0
- };
+ }
+ if (grub_diskfilter_vg_register (vg))
+ goto fail4;
+ }
+ else
+ {
+ grub_free (vgname);
+ }
+
+ id->uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
+ if (!id->uuid)
+ goto fail4;
+ grub_memcpy (id->uuid, pv_id, GRUB_LVM_ID_STRLEN);
+ id->uuidlen = GRUB_LVM_ID_STRLEN;
+ grub_free (metadatabuf);
+ *start_sector = -1;
+ return vg;
+
+ /* Failure path. */
+ fail4:
+ grub_free (vg);
+ fail3:
+ grub_free (vgname);
+
+ fail2:
+ grub_free (metadatabuf);
+ fail:
+ return NULL;
+}
\f
-GRUB_MOD_INIT(lvm)
+
+static struct grub_diskfilter grub_lvm_dev = {
+ .name = "lvm",
+ .detect = grub_lvm_detect,
+ .next = 0
+};
+
+GRUB_MOD_INIT (lvm)
{
- grub_disk_dev_register (&grub_lvm_dev);
+ grub_diskfilter_register (&grub_lvm_dev);
}
-GRUB_MOD_FINI(lvm)
+GRUB_MOD_FINI (lvm)
{
- grub_disk_dev_unregister (&grub_lvm_dev);
- vg_list = NULL;
- /* FIXME: free the lvm list. */
+ grub_diskfilter_unregister (&grub_lvm_dev);
}
=== modified file 'grub-core/disk/mdraid1x_linux.c'
--- grub-core/disk/mdraid1x_linux.c 2011-04-11 21:01:51 +0000
+++ grub-core/disk/mdraid1x_linux.c 2012-01-28 13:51:46 +0000
@@ -22,7 +22,7 @@
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
-#include <grub/raid.h>
+#include <grub/diskfilter.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -103,8 +103,9 @@
#define WriteMostly1 1 /* Mask for writemostly flag in above devflags. */
-static grub_err_t
-grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
+static struct grub_diskfilter_vg *
+grub_mdraid_detect (grub_disk_t disk,
+ struct grub_diskfilter_pv_id *id,
grub_disk_addr_t *start_sector)
{
grub_disk_addr_t sector = 0;
@@ -142,7 +143,7 @@
if (grub_disk_read (disk, sector, 0, sizeof (struct grub_raid_super_1x),
&sb))
- return grub_errno;
+ return NULL;
if (grub_le_to_cpu32 (sb.magic) != SB_MAGIC
|| grub_le_to_cpu64 (sb.super_offset) != sector)
@@ -154,9 +155,12 @@
grub_uint32_t level;
if (grub_le_to_cpu32 (sb.major_version) != 1)
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "Unsupported RAID version: %d",
- grub_le_to_cpu32 (sb.major_version));
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "Unsupported RAID version: %d",
+ grub_le_to_cpu32 (sb.major_version));
+ return NULL;
+ }
level = grub_le_to_cpu32 (sb.level);
@@ -166,8 +170,11 @@
if (level != 0 && level != 1 && level != 4 &&
level != 5 && level != 6 && level != 10)
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "Unsupported RAID level: %d", sb.level);
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "Unsupported RAID level: %d", sb.level);
+ return NULL;
+ }
/* 1.x superblocks don't have a fixed size on disk. So we have to
read it again now that we now the max device count. */
@@ -175,62 +182,68 @@
+ 2 * grub_le_to_cpu32 (sb.max_dev);
real_sb = grub_malloc (sb_size);
if (! real_sb)
- return grub_errno;
+ return NULL;
if (grub_disk_read (disk, sector, 0, sb_size, real_sb))
{
grub_free (real_sb);
- return grub_errno;
- }
-
- array->name = grub_strdup (real_sb->set_name);
- if (! array->name)
- {
- grub_free (real_sb);
- return grub_errno;
- }
-
- array->number = 0;
- array->level = grub_le_to_cpu32 (real_sb->level);
- array->layout = grub_le_to_cpu32 (real_sb->layout);
- array->total_devs = grub_le_to_cpu32 (real_sb->raid_disks);
- if (real_sb->size)
- array->disk_size = grub_le_to_cpu64 (real_sb->size);
- else
- array->disk_size = grub_le_to_cpu64 (real_sb->data_size);
- array->chunk_size = grub_le_to_cpu32 (real_sb->chunksize);
+ return NULL;
+ }
+
+ struct grub_diskfilter_vg *array;
+ char *uuid;
if (grub_le_to_cpu32 (real_sb->dev_number) >=
grub_le_to_cpu32 (real_sb->max_dev))
- return grub_error (GRUB_ERR_OUT_OF_RANGE,
- "spares aren't implemented");
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE,
+ "spares aren't implemented");
+ return NULL;
+ }
- array->index = grub_le_to_cpu16
+ id->uuidlen = 0;
+ id->id = grub_le_to_cpu16
(real_sb->dev_roles[grub_le_to_cpu32 (real_sb->dev_number)]);
- if (array->index >= array->total_devs)
- return grub_error (GRUB_ERR_OUT_OF_RANGE,
- "spares aren't implemented");
- array->uuid_len = 16;
- array->uuid = grub_malloc (16);
- if (!array->uuid)
+
+ uuid = grub_malloc (16);
+ if (!uuid)
{
grub_free (real_sb);
- return grub_errno;
+ return NULL;
}
- grub_memcpy (array->uuid, real_sb->set_uuid, 16);
-
+ grub_memcpy (uuid, real_sb->set_uuid, 16);
+
*start_sector = grub_le_to_cpu64 (real_sb->data_offset);
+ if (grub_le_to_cpu32 (real_sb->dev_number)
+ >= grub_le_to_cpu32 (real_sb->raid_disks))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE,
+ "spares aren't implemented");
+ return NULL;
+ }
+
+ array = grub_diskfilter_make_raid (16, uuid,
+ grub_le_to_cpu32 (real_sb->raid_disks),
+ real_sb->set_name,
+ (real_sb->size)
+ ? grub_le_to_cpu64 (real_sb->size)
+ : grub_le_to_cpu64 (real_sb->data_size),
+ grub_le_to_cpu32 (real_sb->chunksize),
+ grub_le_to_cpu32 (real_sb->layout),
+ grub_le_to_cpu32 (real_sb->level));
+
grub_free (real_sb);
- return 0;
+ return array;
}
}
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 1.x raid");
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "not 1.x raid");
+ return NULL;
}
-static struct grub_raid grub_mdraid_dev = {
+static struct grub_diskfilter grub_mdraid_dev = {
.name = "mdraid1x",
.detect = grub_mdraid_detect,
.next = 0
@@ -238,10 +251,10 @@
GRUB_MOD_INIT (mdraid1x)
{
- grub_raid_register (&grub_mdraid_dev);
+ grub_diskfilter_register (&grub_mdraid_dev);
}
GRUB_MOD_FINI (mdraid1x)
{
- grub_raid_unregister (&grub_mdraid_dev);
+ grub_diskfilter_unregister (&grub_mdraid_dev);
}
=== modified file 'grub-core/disk/mdraid_linux.c'
--- grub-core/disk/mdraid_linux.c 2011-12-13 01:13:44 +0000
+++ grub-core/disk/mdraid_linux.c 2012-01-28 13:51:46 +0000
@@ -22,7 +22,7 @@
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
-#include <grub/raid.h>
+#include <grub/diskfilter.h>
/* Linux RAID on disk structures and constants,
copied from include/linux/raid/md_p.h. */
@@ -161,8 +161,9 @@
struct grub_raid_disk_09 this_disk;
} __attribute__ ((packed));
-static grub_err_t
-grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
+static struct grub_diskfilter_vg *
+grub_mdraid_detect (grub_disk_t disk,
+ struct grub_diskfilter_pv_id *id,
grub_disk_addr_t *start_sector)
{
grub_disk_addr_t sector;
@@ -174,22 +175,31 @@
/* The sector where the mdraid 0.90 superblock is stored, if available. */
size = grub_disk_get_size (disk);
if (size == GRUB_DISK_SIZE_UNKNOWN)
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
+ return NULL;
+ }
sector = NEW_SIZE_SECTORS (size);
if (grub_disk_read (disk, sector, 0, SB_BYTES, &sb))
- return grub_errno;
+ return NULL;
/* Look whether there is a mdraid 0.90 superblock. */
if (grub_le_to_cpu32 (sb.md_magic) != SB_MAGIC)
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
+ return NULL;
+ }
if (grub_le_to_cpu32 (sb.major_version) != 0
|| grub_le_to_cpu32 (sb.minor_version) != 90)
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "unsupported RAID version: %d.%d",
- grub_le_to_cpu32 (sb.major_version),
- grub_le_to_cpu32 (sb.minor_version));
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "unsupported RAID version: %d.%d",
+ grub_le_to_cpu32 (sb.major_version),
+ grub_le_to_cpu32 (sb.minor_version));
+ return NULL;
+ }
/* FIXME: Check the checksum. */
@@ -200,26 +210,22 @@
if (level != 0 && level != 1 && level != 4 &&
level != 5 && level != 6 && level != 10)
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "unsupported RAID level: %d", level);
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "unsupported RAID level: %d", level);
+ return NULL;
+ }
if (grub_le_to_cpu32 (sb.this_disk.number) == 0xffff
|| grub_le_to_cpu32 (sb.this_disk.number) == 0xfffe)
- return grub_error (GRUB_ERR_OUT_OF_RANGE,
- "spares aren't implemented");
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE,
+ "spares aren't implemented");
+ return NULL;
+ }
- array->name = NULL;
- array->number = grub_le_to_cpu32 (sb.md_minor);
- array->level = level;
- array->layout = grub_le_to_cpu32 (sb.layout);
- array->total_devs = grub_le_to_cpu32 (sb.raid_disks);
- array->disk_size = (sb.size) ? grub_le_to_cpu32 (sb.size) * 2 : sector;
- array->chunk_size = grub_le_to_cpu32 (sb.chunk_size) >> 9;
- array->index = grub_le_to_cpu32 (sb.this_disk.number);
- array->uuid_len = 16;
uuid = grub_malloc (16);
- array->uuid = (char *) uuid;
- if (!array->uuid)
- return grub_errno;
+ if (!uuid)
+ return NULL;
uuid[0] = grub_swap_bytes32 (sb.set_uuid0);
uuid[1] = grub_swap_bytes32 (sb.set_uuid1);
@@ -228,10 +234,21 @@
*start_sector = 0;
- return 0;
+ id->uuidlen = 0;
+ id->id = grub_le_to_cpu32 (sb.this_disk.number);
+
+ char buf[32];
+ grub_snprintf (buf, sizeof (buf), "md%d", grub_le_to_cpu32 (sb.md_minor));
+ return grub_diskfilter_make_raid (16, (char *) uuid,
+ grub_le_to_cpu32 (sb.raid_disks), buf,
+ (sb.size) ? grub_le_to_cpu32 (sb.size) * 2
+ : sector,
+ grub_le_to_cpu32 (sb.chunk_size) >> 9,
+ grub_le_to_cpu32 (sb.layout),
+ level);
}
-static struct grub_raid grub_mdraid_dev = {
+static struct grub_diskfilter grub_mdraid_dev = {
.name = "mdraid09",
.detect = grub_mdraid_detect,
.next = 0
@@ -239,10 +256,10 @@
GRUB_MOD_INIT (mdraid09)
{
- grub_raid_register (&grub_mdraid_dev);
+ grub_diskfilter_register (&grub_mdraid_dev);
}
GRUB_MOD_FINI (mdraid09)
{
- grub_raid_unregister (&grub_mdraid_dev);
+ grub_diskfilter_unregister (&grub_mdraid_dev);
}
=== modified file 'grub-core/disk/raid5_recover.c'
--- grub-core/disk/raid5_recover.c 2011-12-13 00:26:53 +0000
+++ grub-core/disk/raid5_recover.c 2012-01-28 13:51:46 +0000
@@ -22,13 +22,13 @@
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
-#include <grub/raid.h>
+#include <grub/diskfilter.h>
#include <grub/crypto.h>
GRUB_MOD_LICENSE ("GPLv3+");
static grub_err_t
-grub_raid5_recover (struct grub_raid_array *array, int disknr,
+grub_raid5_recover (struct grub_diskfilter_segment *array, int disknr,
char *buf, grub_disk_addr_t sector, int size)
{
char *buf2;
@@ -41,16 +41,15 @@
grub_memset (buf, 0, size);
- for (i = 0; i < (int) array->total_devs; i++)
+ for (i = 0; i < (int) array->node_count; i++)
{
grub_err_t err;
if (i == disknr)
continue;
- err = grub_disk_read (array->members[i].device,
- array->members[i].start_sector + sector,
- 0, size, buf2);
+ err = grub_diskfilter_read_node (&array->nodes[i], sector,
+ size >> GRUB_DISK_SECTOR_BITS, buf2);
if (err)
{
@@ -58,7 +57,7 @@
return err;
}
- grub_crypto_xor (buf, buf2, buf2, size);
+ grub_crypto_xor (buf, buf, buf2, size);
}
grub_free (buf2);
=== modified file 'grub-core/disk/raid6_recover.c'
--- grub-core/disk/raid6_recover.c 2011-12-13 00:26:53 +0000
+++ grub-core/disk/raid6_recover.c 2012-01-28 13:51:46 +0000
@@ -22,7 +22,7 @@
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
-#include <grub/raid.h>
+#include <grub/diskfilter.h>
#include <grub/crypto.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -64,7 +64,7 @@
}
static grub_err_t
-grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
+grub_raid6_recover (struct grub_diskfilter_segment *array, int disknr, int p,
char *buf, grub_disk_addr_t sector, int size)
{
int i, q, pos;
@@ -81,23 +81,21 @@
goto quit;
q = p + 1;
- if (q == (int) array->total_devs)
+ if (q == (int) array->node_count)
q = 0;
pos = q + 1;
- if (pos == (int) array->total_devs)
+ if (pos == (int) array->node_count)
pos = 0;
- for (i = 0; i < (int) array->total_devs - 2; i++)
+ for (i = 0; i < (int) array->node_count - 2; i++)
{
if (pos == disknr)
bad1 = i;
else
{
- if ((array->members[pos].device) &&
- (! grub_disk_read (array->members[pos].device,
- array->members[pos].start_sector + sector,
- 0, size, buf)))
+ if (! grub_diskfilter_read_node (&array->nodes[pos], sector,
+ size >> GRUB_DISK_SECTOR_BITS, buf))
{
grub_crypto_xor (pbuf, pbuf, buf, size);
grub_raid_block_mulx (i, buf, size);
@@ -115,7 +113,7 @@
}
pos++;
- if (pos == (int) array->total_devs)
+ if (pos == (int) array->node_count)
pos = 0;
}
@@ -126,24 +124,16 @@
if (bad2 < 0)
{
/* One bad device */
- if ((array->members[p].device) &&
- (! grub_disk_read (array->members[p].device,
- array->members[p].start_sector + sector,
- 0, size, buf)))
+ if ((! grub_diskfilter_read_node (&array->nodes[p], sector,
+ size >> GRUB_DISK_SECTOR_BITS, buf)))
{
grub_crypto_xor (buf, buf, pbuf, size);
goto quit;
}
- if (! array->members[q].device)
- {
- grub_error (GRUB_ERR_READ_ERROR, "not enough disk to restore");
- goto quit;
- }
-
grub_errno = GRUB_ERR_NONE;
- if (grub_disk_read (array->members[q].device,
- array->members[q].start_sector + sector, 0, size, buf))
+ if (grub_diskfilter_read_node (&array->nodes[q], sector,
+ size >> GRUB_DISK_SECTOR_BITS, buf))
goto quit;
grub_crypto_xor (buf, buf, qbuf, size);
@@ -155,22 +145,14 @@
/* Two bad devices */
int c;
- if ((! array->members[p].device) || (! array->members[q].device))
- {
- grub_error (GRUB_ERR_READ_ERROR, "not enough disk to restore");
- goto quit;
- }
-
- if (grub_disk_read (array->members[p].device,
- array->members[p].start_sector + sector,
- 0, size, buf))
+ if (grub_diskfilter_read_node (&array->nodes[p], sector,
+ size >> GRUB_DISK_SECTOR_BITS, buf))
goto quit;
grub_crypto_xor (pbuf, pbuf, buf, size);
- if (grub_disk_read (array->members[q].device,
- array->members[q].start_sector + sector,
- 0, size, buf))
+ if (grub_diskfilter_read_node (&array->nodes[q], sector,
+ size >> GRUB_DISK_SECTOR_BITS, buf))
goto quit;
grub_crypto_xor (qbuf, qbuf, buf, size);
=== modified file 'grub-core/kern/disk.c'
--- grub-core/kern/disk.c 2011-12-24 01:43:21 +0000
+++ grub-core/kern/disk.c 2012-01-28 13:51:46 +0000
@@ -177,7 +177,7 @@
\f
-static grub_disk_dev_t grub_disk_dev_list;
+grub_disk_dev_t grub_disk_dev_list;
void
grub_disk_dev_register (grub_disk_dev_t dev)
@@ -199,20 +199,6 @@
}
}
-int
-grub_disk_dev_iterate (int (*hook) (const char *name))
-{
- grub_disk_dev_t p;
- grub_disk_pull_t pull;
-
- for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
- for (p = grub_disk_dev_list; p; p = p->next)
- if (p->iterate && (p->iterate) (hook, pull))
- return 1;
-
- return 0;
-}
-
/* Return the location of the first ',', if any, which is not
escaped by a '\'. */
static const char *
=== modified file 'grub-core/kern/emu/full.c'
--- grub-core/kern/emu/full.c 2011-01-02 23:04:39 +0000
+++ grub-core/kern/emu/full.c 2012-01-28 13:51:46 +0000
@@ -72,8 +72,8 @@
grub_lvm_fini ();
grub_mdraid09_fini ();
grub_mdraid1x_fini ();
- grub_raid_fini ();
- grub_raid_init ();
+ grub_diskfilter_fini ();
+ grub_diskfilter_init ();
grub_mdraid09_init ();
grub_mdraid1x_init ();
grub_lvm_init ();
=== modified file 'grub-core/kern/emu/hostdisk.c'
--- grub-core/kern/emu/hostdisk.c 2012-01-24 12:31:12 +0000
+++ grub-core/kern/emu/hostdisk.c 2012-01-28 13:51:46 +0000
@@ -68,26 +68,12 @@
# ifndef BLKGETSIZE64
# define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */
# endif /* ! BLKGETSIZE64 */
-# ifndef MAJOR
-# ifndef MINORBITS
-# define MINORBITS 8
-# endif /* ! MINORBITS */
-# define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS))
-# endif /* ! MAJOR */
-# ifndef FLOPPY_MAJOR
-# define FLOPPY_MAJOR 2
-# endif /* ! FLOPPY_MAJOR */
-# ifndef LOOP_MAJOR
-# define LOOP_MAJOR 7
-# endif /* ! LOOP_MAJOR */
#endif /* __linux__ */
#ifdef __CYGWIN__
# include <sys/ioctl.h>
# include <cygwin/fs.h> /* BLKGETSIZE64 */
# include <cygwin/hdreg.h> /* HDIO_GETGEO */
-# define MAJOR(dev) ((unsigned) ((dev) >> 16))
-# define FLOPPY_MAJOR 2
#endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
@@ -96,8 +82,6 @@
# include <sys/sysctl.h>
# include <sys/mount.h>
#include <libgeom.h>
-# define MAJOR(dev) major(dev)
-# define FLOPPY_MAJOR 2
#endif
#if defined (__sun__)
@@ -125,9 +109,6 @@
# include <util.h> /* getrawpartition */
# endif /* HAVE_GETRAWPARTITION */
# include <sys/fdio.h>
-# ifndef FLOPPY_MAJOR
-# define FLOPPY_MAJOR 2
-# endif /* ! FLOPPY_MAJOR */
# ifndef RAW_FLOPPY_MAJOR
# define RAW_FLOPPY_MAJOR 9
# endif /* ! RAW_FLOPPY_MAJOR */
@@ -481,8 +462,8 @@
*off_out = 0;
}
-static grub_disk_addr_t
-find_partition_start (const char *dev)
+grub_disk_addr_t
+grub_hostdisk_find_partition_start (const char *dev)
{
grub_disk_addr_t out;
if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
@@ -493,8 +474,8 @@
}
#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined (__sun__)
-static grub_disk_addr_t
-find_partition_start (const char *dev)
+grub_disk_addr_t
+grub_hostdisk_find_partition_start (const char *dev)
{
int fd;
#ifdef __sun__
@@ -706,7 +687,7 @@
missing = 0;
close (fd);
- start = find_partition_start (real_dev);
+ start = grub_hostdisk_find_partition_start (real_dev);
/* We don't care about errors here. */
grub_errno = GRUB_ERR_NONE;
@@ -761,6 +742,32 @@
}
#endif
+const char *
+grub_hostdisk_os_dev_to_grub_drive (const char *os_disk, int add)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE (map); i++)
+ if (! map[i].device)
+ break;
+ else if (strcmp (map[i].device, os_disk) == 0)
+ return map[i].drive;
+
+ if (!add)
+ return NULL;
+
+ if (i == ARRAY_SIZE (map))
+ grub_util_error (_("device count exceeds limit"));
+
+ map[i].device = xstrdup (os_disk);
+ map[i].drive = xmalloc (sizeof ("hostdisk/") + strlen (os_disk));
+ strcpy (map[i].drive, "hostdisk/");
+ strcpy (map[i].drive + sizeof ("hostdisk/") - 1, os_disk);
+ map[i].device_map = 0;
+
+ return map[i].drive;
+}
+
static int
open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
{
@@ -1241,743 +1248,6 @@
grub_disk_dev_unregister (&grub_util_biosdisk_dev);
}
-/*
- * Note: we do not use the new partition naming scheme as dos_part does not
- * necessarily correspond to an msdos partition.
- */
-static char *
-make_device_name (int drive, int dos_part, int bsd_part)
-{
- char *ret, *ptr, *end;
- const char *iptr;
-
- ret = xmalloc (strlen (map[drive].drive) * 2
- + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
- ",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
- end = (ret + strlen (map[drive].drive) * 2
- + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
- ",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
- ptr = ret;
- for (iptr = map[drive].drive; *iptr; iptr++)
- {
- if (*iptr == ',')
- *ptr++ = '\\';
- *ptr++ = *iptr;
- }
- *ptr = 0;
- if (dos_part >= 0)
- snprintf (ptr, end - ptr, ",%d", dos_part + 1);
- ptr += strlen (ptr);
- if (bsd_part >= 0)
- snprintf (ptr, end - ptr, ",%d", bsd_part + 1);
-
- return ret;
-}
-
-#ifdef HAVE_DEVICE_MAPPER
-static int
-grub_util_get_dm_node_linear_info (const char *dev,
- int *maj, int *min)
-{
- struct dm_task *dmt;
- void *next = NULL;
- uint64_t length, start;
- char *target, *params;
- char *ptr;
- int major, minor;
-
- dmt = dm_task_create(DM_DEVICE_TABLE);
- if (!dmt)
- return 0;
-
- if (!dm_task_set_name(dmt, dev))
- return 0;
- dm_task_no_open_count(dmt);
- if (!dm_task_run(dmt))
- return 0;
- next = dm_get_next_target(dmt, next, &start, &length,
- &target, ¶ms);
- if (grub_strcmp (target, "linear") != 0)
- return 0;
- major = grub_strtoul (params, &ptr, 10);
- if (grub_errno)
- {
- grub_errno = GRUB_ERR_NONE;
- return 0;
- }
- if (*ptr != ':')
- return 0;
- ptr++;
- minor = grub_strtoul (ptr, 0, 10);
- if (grub_errno)
- {
- grub_errno = GRUB_ERR_NONE;
- return 0;
- }
- if (maj)
- *maj = major;
- if (min)
- *min = minor;
- return 1;
-}
-#endif
-
-static char *
-convert_system_partition_to_system_disk (const char *os_dev, struct stat *st)
-{
-#if defined(__linux__)
- char *path = xmalloc (PATH_MAX);
- if (! realpath (os_dev, path))
- return NULL;
-
- if (strncmp ("/dev/", path, 5) == 0)
- {
- char *p = path + 5;
-
- /* If this is an IDE disk. */
- if (strncmp ("ide/", p, 4) == 0)
- {
- p = strstr (p, "part");
- if (p)
- strcpy (p, "disc");
-
- return path;
- }
-
- /* If this is a SCSI disk. */
- if (strncmp ("scsi/", p, 5) == 0)
- {
- p = strstr (p, "part");
- if (p)
- strcpy (p, "disc");
-
- return path;
- }
-
- /* If this is a DAC960 disk. */
- if (strncmp ("rd/c", p, 4) == 0)
- {
- /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- *p = '\0';
-
- return path;
- }
-
- /* If this is a Mylex AcceleRAID Array. */
- if (strncmp ("rs/c", p, 4) == 0)
- {
- /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- *p = '\0';
-
- return path;
- }
- /* If this is a CCISS disk. */
- if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0)
- {
- /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- *p = '\0';
-
- return path;
- }
-
- /* If this is a Compaq Intelligent Drive Array. */
- if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0)
- {
- /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- *p = '\0';
-
- return path;
- }
-
- /* If this is an I2O disk. */
- if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0)
- {
- /* /dev/i2o/hd[a-z]([0-9]+)? */
- p[sizeof ("i2o/hda") - 1] = '\0';
- return path;
- }
-
- /* If this is a MultiMediaCard (MMC). */
- if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0)
- {
- /* /dev/mmcblk[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- *p = '\0';
-
- return path;
- }
-
- if (strncmp ("md", p, 2) == 0
- && p[2] >= '0' && p[2] <= '9')
- {
- char *ptr = p + 2;
- while (*ptr >= '0' && *ptr <= '9')
- ptr++;
- *ptr = 0;
- return path;
- }
-
- /* If this is an IDE, SCSI or Virtio disk. */
- if (strncmp ("vdisk", p, 5) == 0
- && p[5] >= 'a' && p[5] <= 'z')
- {
- /* /dev/vdisk[a-z][0-9]* */
- p[6] = '\0';
- return path;
- }
- if ((strncmp ("hd", p, 2) == 0
- || strncmp ("vd", p, 2) == 0
- || strncmp ("sd", p, 2) == 0)
- && p[2] >= 'a' && p[2] <= 'z')
- {
- char *pp = p + 2;
- while (*pp >= 'a' && *pp <= 'z')
- pp++;
- /* /dev/[hsv]d[a-z]+[0-9]* */
- *pp = '\0';
- return path;
- }
-
- /* If this is a Xen virtual block device. */
- if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
- {
- char *pp = p + 3;
- while (*pp >= 'a' && *pp <= 'z')
- pp++;
- /* /dev/xvd[a-z]+[0-9]* */
- *pp = '\0';
- return path;
- }
-
-#ifdef HAVE_DEVICE_MAPPER
- /* If this is a DM-RAID device.
- Compare os_dev rather than path here, since nodes under
- /dev/mapper/ are often symlinks. */
- if ((strncmp ("/dev/mapper/", os_dev, 12) == 0))
- {
- struct dm_tree *tree;
- uint32_t maj, min;
- struct dm_tree_node *node = NULL, *child;
- void *handle;
- const char *node_uuid, *mapper_name = NULL, *child_uuid, *child_name;
-
- tree = dm_tree_create ();
- if (! tree)
- {
- grub_dprintf ("hostdisk", "dm_tree_create failed\n");
- goto devmapper_out;
- }
-
- 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");
- goto devmapper_out;
- }
-
- node = dm_tree_find_node (tree, maj, min);
- if (! node)
- {
- grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
- goto devmapper_out;
- }
- node_uuid = dm_tree_node_get_uuid (node);
- if (! node_uuid)
- {
- grub_dprintf ("hostdisk", "%s has no DM uuid\n", path);
- node = NULL;
- goto devmapper_out;
- }
- if (strncmp (node_uuid, "LVM-", 4) == 0)
- {
- grub_dprintf ("hostdisk", "%s is an LVM\n", path);
- node = NULL;
- goto devmapper_out;
- }
- if (strncmp (node_uuid, "mpath-", 6) == 0)
- {
- /* Multipath partitions have partN-mpath-* UUIDs, and are
- linear mappings so are handled by
- grub_util_get_dm_node_linear_info. Multipath disks are not
- linear mappings and must be handled specially. */
- grub_dprintf ("hostdisk", "%s is a multipath disk\n", path);
- mapper_name = dm_tree_node_get_name (node);
- goto devmapper_out;
- }
- if (strncmp (node_uuid, "DMRAID-", 7) != 0)
- {
- int major, minor;
- const char *node_name;
- grub_dprintf ("hostdisk", "%s is not DM-RAID\n", path);
-
- if ((node_name = dm_tree_node_get_name (node))
- && grub_util_get_dm_node_linear_info (node_name,
- &major, &minor))
- {
- if (tree)
- dm_tree_free (tree);
- free (path);
- char *ret = grub_find_device ("/dev",
- (major << 8) | minor);
- return ret;
- }
-
- node = NULL;
- goto devmapper_out;
- }
-
- handle = NULL;
- /* Counter-intuitively, device-mapper refers to the disk-like
- device containing a DM-RAID partition device as a "child" of
- the partition device. */
- child = dm_tree_next_child (&handle, node, 0);
- if (! child)
- {
- grub_dprintf ("hostdisk", "%s has no DM children\n", path);
- goto devmapper_out;
- }
- child_uuid = dm_tree_node_get_uuid (child);
- if (! child_uuid)
- {
- grub_dprintf ("hostdisk", "%s child has no DM uuid\n", path);
- goto devmapper_out;
- }
- else if (strncmp (child_uuid, "DMRAID-", 7) != 0)
- {
- grub_dprintf ("hostdisk", "%s child is not DM-RAID\n", path);
- goto devmapper_out;
- }
- child_name = dm_tree_node_get_name (child);
- if (! child_name)
- {
- grub_dprintf ("hostdisk", "%s child has no DM name\n", path);
- goto devmapper_out;
- }
- mapper_name = child_name;
-
-devmapper_out:
- if (! mapper_name && node)
- {
- /* This is a DM-RAID disk, not a partition. */
- mapper_name = dm_tree_node_get_name (node);
- if (! mapper_name)
- grub_dprintf ("hostdisk", "%s has no DM name\n", path);
- }
- if (tree)
- dm_tree_free (tree);
- free (path);
- if (mapper_name)
- return xasprintf ("/dev/mapper/%s", mapper_name);
- else
- return NULL;
- }
-#endif /* HAVE_DEVICE_MAPPER */
- }
-
- return path;
-
-#elif defined(__GNU__)
- char *path = xstrdup (os_dev);
- if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0)
- {
- char *p = strchr (path + 7, 's');
- if (p)
- *p = '\0';
- }
- return path;
-
-#elif defined(__CYGWIN__)
- char *path = xstrdup (os_dev);
- if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z')
- path[8] = 0;
- return path;
-
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- char *out, *out2;
- if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
- return xstrdup (os_dev);
- grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
-
- out2 = xasprintf ("/dev/%s", out);
- free (out);
-
- return out2;
-#elif defined(__APPLE__)
- char *path = xstrdup (os_dev);
- if (strncmp ("/dev/", path, 5) == 0)
- {
- char *p;
- for (p = path + 5; *p; ++p)
- if (grub_isdigit(*p))
- {
- p = strpbrk (p, "sp");
- if (p)
- *p = '\0';
- break;
- }
- }
- return path;
-
-#elif defined(__NetBSD__)
- /* NetBSD uses "/dev/r[a-z]+[0-9][a-z]". */
- char *path = xstrdup (os_dev);
- if (strncmp ("/dev/r", path, sizeof("/dev/r") - 1) == 0 &&
- (path[sizeof("/dev/r") - 1] >= 'a' && path[sizeof("/dev/r") - 1] <= 'z') &&
- strncmp ("fd", path + sizeof("/dev/r") - 1, sizeof("fd") - 1) != 0) /* not a floppy device name */
- {
- char *p;
- for (p = path + sizeof("/dev/r"); *p >= 'a' && *p <= 'z'; p++);
- if (grub_isdigit(*p))
- {
- p++;
- if ((*p >= 'a' && *p <= 'z') && (*(p+1) == '\0'))
- {
- /* path matches the required regular expression and
- p points to its last character. */
- int rawpart = -1;
-# ifdef HAVE_GETRAWPARTITION
- rawpart = getrawpartition();
-# endif /* HAVE_GETRAWPARTITION */
- if (rawpart >= 0)
- *p = 'a' + rawpart;
- }
- }
- }
- return path;
-
-#elif defined (__sun__)
- char *colon = grub_strrchr (os_dev, ':');
- if (grub_memcmp (os_dev, "/devices", sizeof ("/devices") - 1) == 0
- && colon)
- {
- char *ret = xmalloc (colon - os_dev + sizeof (":q,raw"));
- grub_memcpy (ret, os_dev, colon - os_dev);
- grub_memcpy (ret + (colon - os_dev), ":q,raw", sizeof (":q,raw"));
- return ret;
- }
- else
- return xstrdup (os_dev);
-#else
-# warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
- return xstrdup (os_dev);
-#endif
-}
-
-#if defined(__sun__)
-static int
-device_is_wholedisk (const char *os_dev)
-{
- if (grub_memcmp (os_dev, "/devices/", sizeof ("/devices/") - 1) != 0)
- return 1;
- if (grub_memcmp (os_dev + strlen (os_dev) - (sizeof (":q,raw") - 1),
- ":q,raw", (sizeof (":q,raw") - 1)) == 0)
- return 1;
- return 0;
-}
-#endif
-
-#if defined(__linux__) || defined(__CYGWIN__)
-static int
-device_is_wholedisk (const char *os_dev)
-{
- int len = strlen (os_dev);
-
- if (os_dev[len - 1] < '0' || os_dev[len - 1] > '9')
- return 1;
- return 0;
-}
-#endif
-
-#if defined(__NetBSD__)
-/* Try to determine whether a given device name corresponds to a whole disk.
- This function should give in most cases a definite answer, but it may
- actually give an approximate one in the following sense: if the return
- value is 0 then the device name does not correspond to a whole disk. */
-static int
-device_is_wholedisk (const char *os_dev)
-{
- int len = strlen (os_dev);
- int rawpart = -1;
-
-# ifdef HAVE_GETRAWPARTITION
- rawpart = getrawpartition();
-# endif /* HAVE_GETRAWPARTITION */
- if (rawpart < 0)
- return 1;
- return (os_dev[len - 1] == ('a' + rawpart));
-}
-#endif /* defined(__NetBSD__) */
-
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-static int
-device_is_wholedisk (const char *os_dev)
-{
- const char *p;
-
- if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
- return 0;
-
- for (p = os_dev + sizeof ("/dev/") - 1; *p; ++p)
- if (grub_isdigit (*p))
- {
- if (strchr (p, 's'))
- return 0;
- break;
- }
-
- return 1;
-}
-#endif /* defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
-
-static int
-find_system_device (const char *os_dev, struct stat *st, int convert, int add)
-{
- unsigned int i;
- char *os_disk;
-
- if (convert)
- os_disk = convert_system_partition_to_system_disk (os_dev, st);
- else
- os_disk = xstrdup (os_dev);
- if (! os_disk)
- return -1;
-
- for (i = 0; i < ARRAY_SIZE (map); i++)
- if (! map[i].device)
- break;
- else if (strcmp (map[i].device, os_disk) == 0)
- {
- free (os_disk);
- return i;
- }
-
- if (!add)
- {
- free (os_disk);
- return -1;
- }
-
- if (i == ARRAY_SIZE (map))
- grub_util_error (_("device count exceeds limit"));
-
- map[i].device = os_disk;
- map[i].drive = xmalloc (sizeof ("hostdisk/") + strlen (os_disk));
- strcpy (map[i].drive, "hostdisk/");
- strcpy (map[i].drive + sizeof ("hostdisk/") - 1, os_disk);
- map[i].device_map = 0;
-
- return i;
-}
-
-int
-grub_util_biosdisk_is_present (const char *os_dev)
-{
- struct stat st;
-
- if (stat (os_dev, &st) < 0)
- return 0;
-
- return find_system_device (os_dev, &st, 1, 0) != -1;
-}
-
-char *
-grub_util_biosdisk_get_grub_dev (const char *os_dev)
-{
- struct stat st;
- int drive;
- char *sys_disk;
-
- grub_util_info ("Looking for %s", os_dev);
-
- if (stat (os_dev, &st) < 0)
- {
- grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev);
- grub_util_info ("cannot stat `%s'", os_dev);
- return 0;
- }
-
- drive = find_system_device (os_dev, &st, 1, 1);
- if (drive < 0)
- {
- grub_error (GRUB_ERR_UNKNOWN_DEVICE,
- "no mapping exists for `%s'", os_dev);
- grub_util_info ("no mapping exists for `%s'", os_dev);
- return 0;
- }
-
- sys_disk = convert_system_partition_to_system_disk (os_dev, &st);
- if (grub_strcmp (os_dev, sys_disk) == 0)
- {
- free (sys_disk);
- return make_device_name (drive, -1, -1);
- }
- free (sys_disk);
-
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__)
- if (! S_ISCHR (st.st_mode))
-#else
- if (! S_ISBLK (st.st_mode))
-#endif
- return make_device_name (drive, -1, -1);
-
-#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__sun__)
-
- /* Linux counts partitions uniformly, whether a BSD partition or a DOS
- partition, so mapping them to GRUB devices is not trivial.
- Here, get the start sector of a partition by HDIO_GETGEO, and
- compare it with each partition GRUB recognizes.
-
- Cygwin /dev/sdXN emulation uses Windows partition mapping. It
- does not count the extended partition and missing primary
- partitions. Use same method as on Linux here.
-
- For NetBSD and FreeBSD, proceed as for Linux, except that the start
- sector is obtained from the disk label. */
- {
- char *name, *partname;
- grub_disk_t disk;
- grub_disk_addr_t start;
- auto int find_partition (grub_disk_t dsk,
- const grub_partition_t partition);
-
- int find_partition (grub_disk_t dsk __attribute__ ((unused)),
- const grub_partition_t partition)
- {
- grub_disk_addr_t part_start = 0;
- grub_util_info ("Partition %d starts from %lu",
- partition->number, partition->start);
-
- part_start = grub_partition_get_start (partition);
-
- if (start == part_start)
- {
- partname = grub_partition_get_name (partition);
- return 1;
- }
-
- return 0;
- }
-
- name = make_device_name (drive, -1, -1);
-
-# if !defined(HAVE_DIOCGDINFO) && !defined(__sun__)
- if (MAJOR (st.st_rdev) == FLOPPY_MAJOR)
- return name;
-# else /* defined(HAVE_DIOCGDINFO) */
- /* Since os_dev and convert_system_partition_to_system_disk (os_dev) are
- * different, we know that os_dev cannot be a floppy device. */
-# endif /* !defined(HAVE_DIOCGDINFO) */
-
- start = find_partition_start (os_dev);
- if (grub_errno != GRUB_ERR_NONE)
- {
- free (name);
- return 0;
- }
-
- grub_util_info ("%s starts from %lu", os_dev, start);
-
- if (start == 0 && device_is_wholedisk (os_dev))
- return name;
-
- grub_util_info ("opening the device %s", name);
- disk = grub_disk_open (name);
- free (name);
-
- if (! disk)
- {
- /* We already know that the partition exists. Given that we already
- checked the device map above, we can only get
- GRUB_ERR_UNKNOWN_DEVICE at this point if the disk does not exist.
- This can happen on Xen, where disk images in the host can be
- assigned to devices that have partition-like names in the guest
- but are really more like disks. */
- if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
- {
- grub_util_warn
- ("disk does not exist, so falling back to partition device %s",
- os_dev);
-
- drive = find_system_device (os_dev, &st, 0, 1);
- if (drive < 0)
- {
- grub_error (GRUB_ERR_UNKNOWN_DEVICE,
- "no mapping exists for `%s'", os_dev);
- return 0;
- }
-
- return make_device_name (drive, -1, -1);
- }
- else
- return 0;
- }
-
- partname = NULL;
- grub_partition_iterate (disk, find_partition);
- if (grub_errno != GRUB_ERR_NONE)
- {
- grub_disk_close (disk);
- return 0;
- }
-
- if (partname == NULL)
- {
- grub_disk_close (disk);
- grub_util_info ("cannot find the partition of `%s'", os_dev);
- grub_error (GRUB_ERR_BAD_DEVICE,
- "cannot find the partition of `%s'", os_dev);
- return 0;
- }
-
- name = grub_xasprintf ("%s,%s", disk->name, partname);
- free (partname);
- grub_disk_close (disk);
- return name;
- }
-
-#elif defined(__GNU__)
- /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
- {
- char *p;
- int dos_part = -1;
- int bsd_part = -1;
-
- p = strrchr (os_dev, 's');
- if (p)
- {
- long int n;
- char *q;
-
- p++;
- n = strtol (p, &q, 10);
- if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX)
- {
- dos_part = (int) n - 1;
-
- if (*q >= 'a' && *q <= 'g')
- bsd_part = *q - 'a';
- }
- }
-
- return make_device_name (drive, dos_part, bsd_part);
- }
-
-#else
-# warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly."
- return make_device_name (drive, -1, -1);
-#endif
-}
-
const char *
grub_util_biosdisk_get_compatibility_hint (grub_disk_t disk)
{
@@ -1989,48 +1259,8 @@
const char *
grub_util_biosdisk_get_osdev (grub_disk_t disk)
{
+ if (disk->dev != &grub_util_biosdisk_dev)
+ return 0;
+
return map[disk->id].device;
}
-
-int
-grub_util_biosdisk_is_floppy (grub_disk_t disk)
-{
- struct stat st;
- int fd;
-
- if (disk->dev != &grub_util_biosdisk_dev)
- return 0;
-
- fd = open (map[disk->id].device, O_RDONLY);
- /* Shouldn't happen. */
- if (fd == -1)
- return 0;
-
- /* Shouldn't happen either. */
- if (fstat (fd, &st) < 0)
- {
- close (fd);
- return 0;
- }
-
- close (fd);
-
-#if defined(__NetBSD__)
- if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
- return 1;
-#endif
-
-#if defined(FLOPPY_MAJOR)
- if (major(st.st_rdev) == FLOPPY_MAJOR)
-#else
- /* Some kernels (e.g. kFreeBSD) don't have a static major number
- for floppies, but they still use a "fd[0-9]" pathname. */
- if (map[disk->id].device[5] == 'f'
- && map[disk->id].device[6] == 'd'
- && map[disk->id].device[7] >= '0'
- && map[disk->id].device[7] <= '9')
-#endif
- return 1;
-
- return 0;
-}
=== modified file 'grub-core/kern/env.c'
--- grub-core/kern/env.c 2011-11-11 19:34:37 +0000
+++ grub-core/kern/env.c 2012-01-28 13:51:46 +0000
@@ -109,9 +109,6 @@
if (! var)
return grub_errno;
- /* This is not necessary. But leave this for readability. */
- var->global = 0;
-
var->name = grub_strdup (name);
if (! var->name)
goto fail;
=== modified file 'grub-core/kern/i386/realmode.S'
--- grub-core/kern/i386/realmode.S 2011-12-15 18:17:36 +0000
+++ grub-core/kern/i386/realmode.S 2012-01-28 13:51:46 +0000
@@ -46,8 +46,6 @@
* This is the area for all of the special variables.
*/
- .p2align 5 /* force 4-byte alignment */
-
protstack:
.long GRUB_MEMORY_MACHINE_PROT_STACK
=== modified file 'grub-core/kern/ieee1275/openfw.c'
--- grub-core/kern/ieee1275/openfw.c 2011-12-24 01:45:17 +0000
+++ grub-core/kern/ieee1275/openfw.c 2012-01-28 13:51:46 +0000
@@ -453,7 +453,7 @@
encoding = grub_xasprintf ("ieee1275/%s,%d", device, partno);
}
else
- encoding = grub_strdup (device);
+ encoding = grub_xasprintf ("ieee1275/%s", device);
grub_free (partition);
grub_free (device);
=== modified file 'grub-core/partmap/gpt.c'
--- grub-core/partmap/gpt.c 2011-11-12 23:07:08 +0000
+++ grub-core/partmap/gpt.c 2012-01-28 13:51:46 +0000
@@ -45,10 +45,10 @@
\f
-static grub_err_t
-gpt_partition_map_iterate (grub_disk_t disk,
- int (*hook) (grub_disk_t disk,
- const grub_partition_t partition))
+grub_err_t
+grub_gpt_partition_map_iterate (grub_disk_t disk,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition))
{
struct grub_partition part;
struct grub_gpt_header gpt;
@@ -167,7 +167,7 @@
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"GPT currently supports only PC-BIOS embedding");
- err = gpt_partition_map_iterate (disk, find_usable_region);
+ err = grub_gpt_partition_map_iterate (disk, find_usable_region);
if (err)
return err;
@@ -197,7 +197,7 @@
static struct grub_partition_map grub_gpt_partition_map =
{
.name = "gpt",
- .iterate = gpt_partition_map_iterate,
+ .iterate = grub_gpt_partition_map_iterate,
#ifdef GRUB_UTIL
.embed = gpt_partition_map_embed
#endif
=== modified file 'include/grub/disk.h'
--- include/grub/disk.h 2011-11-13 11:48:39 +0000
+++ include/grub/disk.h 2012-01-28 13:56:26 +0000
@@ -32,8 +32,7 @@
GRUB_DISK_DEVICE_OFDISK_ID,
GRUB_DISK_DEVICE_LOOPBACK_ID,
GRUB_DISK_DEVICE_EFIDISK_ID,
- GRUB_DISK_DEVICE_RAID_ID,
- GRUB_DISK_DEVICE_LVM_ID,
+ GRUB_DISK_DEVICE_DISKFILTER_ID,
GRUB_DISK_DEVICE_HOST_ID,
GRUB_DISK_DEVICE_ATA_ID,
GRUB_DISK_DEVICE_MEMDISK_ID,
@@ -96,6 +95,8 @@
};
typedef struct grub_disk_dev *grub_disk_dev_t;
+extern grub_disk_dev_t EXPORT_VAR (grub_disk_dev_list);
+
struct grub_partition;
/* Disk. */
@@ -158,7 +159,19 @@
void EXPORT_FUNC(grub_disk_dev_register) (grub_disk_dev_t dev);
void EXPORT_FUNC(grub_disk_dev_unregister) (grub_disk_dev_t dev);
-int EXPORT_FUNC(grub_disk_dev_iterate) (int (*hook) (const char *name));
+static inline int
+grub_disk_dev_iterate (int (*hook) (const char *name))
+{
+ grub_disk_dev_t p;
+ grub_disk_pull_t pull;
+
+ for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
+ for (p = grub_disk_dev_list; p; p = p->next)
+ if (p->iterate && (p->iterate) (hook, pull))
+ return 1;
+
+ return 0;
+}
grub_disk_t EXPORT_FUNC(grub_disk_open) (const char *name);
void EXPORT_FUNC(grub_disk_close) (grub_disk_t disk);
@@ -185,13 +198,15 @@
#if defined (GRUB_UTIL) || defined (GRUB_MACHINE_EMU)
void grub_lvm_init (void);
+void grub_ldm_init (void);
void grub_mdraid09_init (void);
void grub_mdraid1x_init (void);
-void grub_raid_init (void);
+void grub_diskfilter_init (void);
void grub_lvm_fini (void);
+void grub_ldm_fini (void);
void grub_mdraid09_fini (void);
void grub_mdraid1x_fini (void);
-void grub_raid_fini (void);
+void grub_diskfilter_fini (void);
#endif
#endif /* ! GRUB_DISK_HEADER */
=== renamed file 'include/grub/raid.h' => 'include/grub/diskfilter.h'
--- include/grub/raid.h 2011-04-21 22:09:07 +0000
+++ include/grub/diskfilter.h 2012-01-28 13:55:10 +0000
@@ -1,4 +1,4 @@
-/* raid.h - On disk structures for RAID. */
+/* diskfilter.h - On disk structures for RAID. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2006,2007,2008,2010 Free Software Foundation, Inc.
@@ -17,10 +17,11 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef GRUB_RAID_H
-#define GRUB_RAID_H 1
+#ifndef GRUB_DISKFILTER_H
+#define GRUB_DISKFILTER_H 1
#include <grub/types.h>
+#include <grub/list.h>
#define GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC 0
#define GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC 1
@@ -30,63 +31,137 @@
#define GRUB_RAID_LAYOUT_RIGHT_MASK 1
#define GRUB_RAID_LAYOUT_SYMMETRIC_MASK 2
-struct grub_raid_member
-{
- grub_disk_t device; /* Array of total_devs devices. */
- grub_disk_addr_t start_sector;
- /* Start of each device, in 512 byte sectors. */
-};
-
-struct grub_raid_array
-{
- int number; /* The device number, taken from md_minor so we
- are consistent with the device name in
- Linux. */
+struct grub_diskfilter_vg {
+ char *uuid;
+ grub_size_t uuid_len;
+ /* Optional. */
+ char *name;
+ int extent_size;
+ struct grub_diskfilter_pv *pvs;
+ struct grub_diskfilter_lv *lvs;
+ struct grub_diskfilter_vg *next;
+
+#ifdef GRUB_UTIL
+ struct grub_diskfilter *driver;
+#endif
+};
+
+struct grub_diskfilter_pv_id {
+ union
+ {
+ char *uuid;
+ int id;
+ };
+ grub_size_t uuidlen;
+};
+
+struct grub_diskfilter_pv {
+ struct grub_diskfilter_pv_id id;
+ /* Optional. */
+ char *name;
+ grub_disk_t disk;
+ grub_disk_addr_t part_start;
+ grub_disk_addr_t part_size;
+ grub_disk_addr_t start_sector; /* Sector number where the data area starts. */
+ struct grub_diskfilter_pv *next;
+ /* Optional. */
+ grub_uint8_t *internal_id;
+};
+
+struct grub_diskfilter_lv {
+ /* Name used for disk. */
+ char *fullname;
+ /* Optional. */
+ char *name;
+ int number;
+ unsigned int segment_count;
+ grub_size_t segment_alloc;
+ grub_uint64_t size;
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. */
- grub_size_t chunk_size; /* The size of a chunk, in 512 byte sectors. */
- grub_uint64_t disk_size; /* Size of an individual disk, in 512 byte
- sectors. */
- unsigned int index; /* Index of current device. */
- int uuid_len; /* The length of uuid. */
- char *uuid; /* The UUID of the device. */
-
- /* The following field is setup by the caller. */
- char *name; /* That will be "md<number>". */
- unsigned int nr_devs; /* The number of devices we've found so far. */
- unsigned int allocated_devs;
- struct grub_raid_member *members;
- struct grub_raid_array *next;
-
-#ifdef GRUB_UTIL
- struct grub_raid *driver;
-#endif
-};
-
-struct grub_raid
+
+ int visible;
+
+ /* Pointer to segment_count segments. */
+ struct grub_diskfilter_segment *segments;
+ struct grub_diskfilter_vg *vg;
+ struct grub_diskfilter_lv *next;
+
+ /* Optional. */
+ char *internal_id;
+};
+
+struct grub_diskfilter_segment {
+ unsigned int start_extent;
+ unsigned int extent_count;
+ enum
+ {
+ GRUB_DISKFILTER_STRIPED = 0,
+ GRUB_DISKFILTER_MIRROR = 1,
+ GRUB_DISKFILTER_RAID4 = 4,
+ GRUB_DISKFILTER_RAID5 = 5,
+ GRUB_DISKFILTER_RAID6 = 6,
+ GRUB_DISKFILTER_RAID10 = 10,
+ } type;
+ int layout;
+ /* valid only for raid10. */
+ grub_uint64_t raid_member_size;
+
+ unsigned int node_count;
+ unsigned int node_alloc;
+ struct grub_diskfilter_node *nodes;
+
+ unsigned int stripe_size;
+};
+
+struct grub_diskfilter_node {
+ grub_disk_addr_t start;
+ /* Optional. */
+ char *name;
+ struct grub_diskfilter_pv *pv;
+ struct grub_diskfilter_lv *lv;
+};
+
+struct grub_diskfilter_vg *
+grub_diskfilter_get_vg_by_uuid (grub_size_t uuidlen, char *uuid);
+
+struct grub_diskfilter
{
+ struct grub_diskfilter *next;
+ struct grub_diskfilter **prev;
+
const char *name;
- grub_err_t (*detect) (grub_disk_t disk, struct grub_raid_array *array,
- grub_disk_addr_t *start_sector);
-
- struct grub_raid *next;
+ struct grub_diskfilter_vg * (*detect) (grub_disk_t disk,
+ struct grub_diskfilter_pv_id *id,
+ grub_disk_addr_t *start_sector);
};
-typedef struct grub_raid *grub_raid_t;
-
-void grub_raid_register (grub_raid_t raid);
-void grub_raid_unregister (grub_raid_t raid);
-
-void grub_raid_block_xor (char *buf1, const char *buf2, int size);
-
-typedef grub_err_t (*grub_raid5_recover_func_t) (struct grub_raid_array *array,
+typedef struct grub_diskfilter *grub_diskfilter_t;
+
+extern grub_diskfilter_t grub_diskfilter_list;
+static inline void
+grub_diskfilter_register (grub_diskfilter_t diskfilter)
+{
+ grub_list_push (GRUB_AS_LIST_P (&grub_diskfilter_list),
+ GRUB_AS_LIST (diskfilter));
+}
+static inline void
+grub_diskfilter_unregister (grub_diskfilter_t diskfilter)
+{
+ grub_list_remove (GRUB_AS_LIST (diskfilter));
+}
+
+struct grub_diskfilter_vg *
+grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb,
+ char *name, grub_uint64_t disk_size,
+ grub_uint64_t stripe_size,
+ int layout, int level);
+
+typedef grub_err_t (*grub_raid5_recover_func_t) (struct grub_diskfilter_segment *array,
int disknr, char *buf,
grub_disk_addr_t sector,
int size);
-typedef grub_err_t (*grub_raid6_recover_func_t) (struct grub_raid_array *array,
+typedef grub_err_t (*grub_raid6_recover_func_t) (struct grub_diskfilter_segment *array,
int disknr, int p, char *buf,
grub_disk_addr_t sector,
int size);
@@ -94,4 +169,17 @@
extern grub_raid5_recover_func_t grub_raid5_recover_func;
extern grub_raid6_recover_func_t grub_raid6_recover_func;
+grub_err_t grub_diskfilter_vg_register (struct grub_diskfilter_vg *vg);
+
+grub_err_t
+grub_diskfilter_read_node (const struct grub_diskfilter_node *node,
+ grub_disk_addr_t sector,
+ grub_size_t size, char *buf);
+
+#ifdef GRUB_UTIL
+struct grub_diskfilter_pv *
+grub_diskfilter_get_pv_from_disk (grub_disk_t disk,
+ struct grub_diskfilter_vg **vg);
+#endif
+
#endif /* ! GRUB_RAID_H */
=== modified file 'include/grub/emu/hostdisk.h'
--- include/grub/emu/hostdisk.h 2011-12-23 17:49:00 +0000
+++ include/grub/emu/hostdisk.h 2012-01-28 13:51:46 +0000
@@ -21,6 +21,7 @@
#define GRUB_BIOSDISK_MACHINE_UTIL_HEADER 1
#include <grub/disk.h>
+#include <grub/partition.h>
#include <sys/types.h>
void grub_util_biosdisk_init (const char *dev_map);
@@ -39,6 +40,21 @@
grub_err_t
grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat);
void grub_util_cryptodisk_print_uuid (grub_disk_t disk);
+char *
+grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start);
+int
+grub_util_is_ldm (grub_disk_t disk);
+#ifdef GRUB_UTIL
+grub_err_t
+grub_util_ldm_embed (struct grub_disk *disk, unsigned int *nsectors,
+ grub_embed_type_t embed_type,
+ grub_disk_addr_t **sectors);
+#endif
+grub_disk_addr_t
+grub_hostdisk_find_partition_start (const char *dev);
+const char *
+grub_hostdisk_os_dev_to_grub_drive (const char *os_dev, int add);
+
#if !defined(__MINGW32__)
grub_uint64_t
grub_util_get_fd_sectors (int fd, unsigned *log_secsize);
=== modified file 'include/grub/gpt_partition.h'
--- include/grub/gpt_partition.h 2010-11-26 21:29:19 +0000
+++ include/grub/gpt_partition.h 2012-01-28 13:51:46 +0000
@@ -20,6 +20,7 @@
#define GRUB_GPT_PARTITION_HEADER 1
#include <grub/types.h>
+#include <grub/partition.h>
struct grub_gpt_part_type
{
@@ -36,10 +37,19 @@
}
#define GRUB_GPT_PARTITION_TYPE_BIOS_BOOT \
- { grub_cpu_to_le32_compile_time (0x21686148), grub_cpu_to_le16_compile_time (0x6449), grub_cpu_to_le16_compile_time (0x6e6f), \
+ { grub_cpu_to_le32_compile_time (0x21686148), \
+ grub_cpu_to_le16_compile_time (0x6449), \
+ grub_cpu_to_le16_compile_time (0x6e6f), \
{ 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } \
}
+#define GRUB_GPT_PARTITION_TYPE_LDM \
+ { grub_cpu_to_le32_compile_time (0x5808C8AAU),\
+ grub_cpu_to_le16_compile_time (0x7E8F), \
+ grub_cpu_to_le16_compile_time (0x42E0), \
+ { 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF, 0xB3 } \
+ }
+
struct grub_gpt_header
{
grub_uint8_t magic[8];
@@ -68,4 +78,10 @@
char name[72];
} __attribute__ ((packed));
+grub_err_t
+grub_gpt_partition_map_iterate (grub_disk_t disk,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition));
+
+
#endif /* ! GRUB_GPT_PARTITION_HEADER */
=== modified file 'include/grub/lvm.h'
--- include/grub/lvm.h 2011-11-12 22:35:20 +0000
+++ include/grub/lvm.h 2012-01-28 13:51:46 +0000
@@ -21,60 +21,11 @@
#define GRUB_LVM_H 1
#include <grub/types.h>
+#include <grub/diskfilter.h>
/* Length of ID string, excluding terminating zero. */
#define GRUB_LVM_ID_STRLEN 38
-struct grub_lvm_vg {
- char id[GRUB_LVM_ID_STRLEN+1];
- char *name;
- int extent_size;
- struct grub_lvm_pv *pvs;
- struct grub_lvm_lv *lvs;
- struct grub_lvm_vg *next;
-};
-
-struct grub_lvm_pv {
- char id[GRUB_LVM_ID_STRLEN+1];
- char *name;
- grub_disk_t disk;
- grub_disk_addr_t start; /* Sector number where the data area starts. */
- struct grub_lvm_pv *next;
-};
-
-struct grub_lvm_lv {
- char *name;
- char *fullname;
- char *compatname;
- unsigned int number;
- unsigned int segment_count;
- grub_uint64_t size;
-
- int visible;
-
- struct grub_lvm_segment *segments; /* Pointer to segment_count segments. */
- struct grub_lvm_vg *vg;
- struct grub_lvm_lv *next;
-};
-
-struct grub_lvm_segment {
- unsigned int start_extent;
- unsigned int extent_count;
- enum { GRUB_LVM_STRIPED, GRUB_LVM_MIRROR } type;
-
- unsigned int node_count;
- struct grub_lvm_node *nodes;
-
- unsigned int stripe_size;
-};
-
-struct grub_lvm_node {
- grub_disk_addr_t start;
- char *name;
- struct grub_lvm_pv *pv;
- struct grub_lvm_lv *lv;
-};
-
#define GRUB_LVM_LABEL_SIZE GRUB_DISK_SECTOR_SIZE
#define GRUB_LVM_LABEL_SCAN_SECTORS 4L
=== modified file 'util/getroot.c'
--- util/getroot.c 2011-12-23 18:25:24 +0000
+++ util/getroot.c 2012-01-28 13:51:46 +0000
@@ -76,6 +76,71 @@
#include <grub/emu/hostdisk.h>
#include <grub/emu/getroot.h>
+#ifdef __linux__
+# include <sys/ioctl.h> /* ioctl */
+# include <sys/mount.h>
+# ifndef MAJOR
+# ifndef MINORBITS
+# define MINORBITS 8
+# endif /* ! MINORBITS */
+# define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS))
+# endif /* ! MAJOR */
+# ifndef FLOPPY_MAJOR
+# define FLOPPY_MAJOR 2
+# endif /* ! FLOPPY_MAJOR */
+#endif
+
+#ifdef __CYGWIN__
+# include <sys/ioctl.h>
+# include <cygwin/fs.h> /* BLKGETSIZE64 */
+# include <cygwin/hdreg.h> /* HDIO_GETGEO */
+# define MAJOR(dev) ((unsigned) ((dev) >> 16))
+# define FLOPPY_MAJOR 2
+#endif
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+# include <sys/disk.h> /* DIOCGMEDIASIZE */
+# include <sys/param.h>
+# include <sys/sysctl.h>
+# include <sys/mount.h>
+#include <libgeom.h>
+# define MAJOR(dev) major(dev)
+# define FLOPPY_MAJOR 2
+#endif
+
+#if defined (__sun__)
+# include <sys/dkio.h>
+#endif
+
+#if defined(__APPLE__)
+# include <sys/disk.h>
+#endif
+
+#ifdef HAVE_DEVICE_MAPPER
+# include <libdevmapper.h>
+#endif
+
+#if defined(__NetBSD__)
+# define HAVE_DIOCGDINFO
+# include <sys/ioctl.h>
+# include <sys/disklabel.h> /* struct disklabel */
+#else /* !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) */
+# undef HAVE_DIOCGDINFO
+#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
+
+#if defined(__NetBSD__)
+# ifdef HAVE_GETRAWPARTITION
+# include <util.h> /* getrawpartition */
+# endif /* HAVE_GETRAWPARTITION */
+# include <sys/fdio.h>
+# ifndef FLOPPY_MAJOR
+# define FLOPPY_MAJOR 2
+# endif /* ! FLOPPY_MAJOR */
+# ifndef RAW_FLOPPY_MAJOR
+# define RAW_FLOPPY_MAJOR 9
+# endif /* ! RAW_FLOPPY_MAJOR */
+#endif /* defined(__NetBSD__) */
+
static void
strip_extra_slashes (char *dir)
{
@@ -1164,6 +1229,773 @@
}
}
+#ifdef HAVE_DEVICE_MAPPER
+static int
+grub_util_get_dm_node_linear_info (const char *dev,
+ int *maj, int *min)
+{
+ struct dm_task *dmt;
+ void *next = NULL;
+ uint64_t length, start;
+ char *target, *params;
+ char *ptr;
+ int major, minor;
+
+ dmt = dm_task_create(DM_DEVICE_TABLE);
+ if (!dmt)
+ return 0;
+
+ if (!dm_task_set_name(dmt, dev))
+ return 0;
+ dm_task_no_open_count(dmt);
+ if (!dm_task_run(dmt))
+ return 0;
+ next = dm_get_next_target(dmt, next, &start, &length,
+ &target, ¶ms);
+ if (grub_strcmp (target, "linear") != 0)
+ return 0;
+ major = grub_strtoul (params, &ptr, 10);
+ if (grub_errno)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return 0;
+ }
+ if (*ptr != ':')
+ return 0;
+ ptr++;
+ minor = grub_strtoul (ptr, 0, 10);
+ if (grub_errno)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return 0;
+ }
+ if (maj)
+ *maj = major;
+ if (min)
+ *min = minor;
+ return 1;
+}
+#endif
+
+int
+grub_util_biosdisk_is_floppy (grub_disk_t disk)
+{
+ struct stat st;
+ int fd;
+ const char *dname;
+
+ dname = grub_util_biosdisk_get_osdev (disk);
+
+ if (!dname)
+ return 0;
+
+ fd = open (dname, O_RDONLY);
+ /* Shouldn't happen. */
+ if (fd == -1)
+ return 0;
+
+ /* Shouldn't happen either. */
+ if (fstat (fd, &st) < 0)
+ {
+ close (fd);
+ return 0;
+ }
+
+ close (fd);
+
+#if defined(__NetBSD__)
+ if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
+ return 1;
+#endif
+
+#if defined(FLOPPY_MAJOR)
+ if (major(st.st_rdev) == FLOPPY_MAJOR)
+#else
+ /* Some kernels (e.g. kFreeBSD) don't have a static major number
+ for floppies, but they still use a "fd[0-9]" pathname. */
+ if (map[disk->id].device[5] == 'f'
+ && map[disk->id].device[6] == 'd'
+ && map[disk->id].device[7] >= '0'
+ && map[disk->id].device[7] <= '9')
+#endif
+ return 1;
+
+ return 0;
+}
+
+static char *
+convert_system_partition_to_system_disk (const char *os_dev, struct stat *st)
+{
+#if defined(__linux__)
+ char *path = xmalloc (PATH_MAX);
+ if (! realpath (os_dev, path))
+ return NULL;
+
+ if (strncmp ("/dev/", path, 5) == 0)
+ {
+ char *p = path + 5;
+
+ /* If this is an IDE disk. */
+ if (strncmp ("ide/", p, 4) == 0)
+ {
+ p = strstr (p, "part");
+ if (p)
+ strcpy (p, "disc");
+
+ return path;
+ }
+
+ /* If this is a SCSI disk. */
+ if (strncmp ("scsi/", p, 5) == 0)
+ {
+ p = strstr (p, "part");
+ if (p)
+ strcpy (p, "disc");
+
+ return path;
+ }
+
+ /* If this is a DAC960 disk. */
+ if (strncmp ("rd/c", p, 4) == 0)
+ {
+ /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ *p = '\0';
+
+ return path;
+ }
+
+ /* If this is a Mylex AcceleRAID Array. */
+ if (strncmp ("rs/c", p, 4) == 0)
+ {
+ /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ *p = '\0';
+
+ return path;
+ }
+ /* If this is a CCISS disk. */
+ if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0)
+ {
+ /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ *p = '\0';
+
+ return path;
+ }
+
+ /* If this is a Compaq Intelligent Drive Array. */
+ if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0)
+ {
+ /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ *p = '\0';
+
+ return path;
+ }
+
+ /* If this is an I2O disk. */
+ if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0)
+ {
+ /* /dev/i2o/hd[a-z]([0-9]+)? */
+ p[sizeof ("i2o/hda") - 1] = '\0';
+ return path;
+ }
+
+ /* If this is a MultiMediaCard (MMC). */
+ if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0)
+ {
+ /* /dev/mmcblk[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ *p = '\0';
+
+ return path;
+ }
+
+ if (strncmp ("md", p, 2) == 0
+ && p[2] >= '0' && p[2] <= '9')
+ {
+ char *ptr = p + 2;
+ while (*ptr >= '0' && *ptr <= '9')
+ ptr++;
+ *ptr = 0;
+ return path;
+ }
+
+ /* If this is an IDE, SCSI or Virtio disk. */
+ if (strncmp ("vdisk", p, 5) == 0
+ && p[5] >= 'a' && p[5] <= 'z')
+ {
+ /* /dev/vdisk[a-z][0-9]* */
+ p[6] = '\0';
+ return path;
+ }
+ if ((strncmp ("hd", p, 2) == 0
+ || strncmp ("vd", p, 2) == 0
+ || strncmp ("sd", p, 2) == 0)
+ && p[2] >= 'a' && p[2] <= 'z')
+ {
+ char *pp = p + 2;
+ while (*pp >= 'a' && *pp <= 'z')
+ pp++;
+ /* /dev/[hsv]d[a-z]+[0-9]* */
+ *pp = '\0';
+ return path;
+ }
+
+ /* If this is a Xen virtual block device. */
+ if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
+ {
+ char *pp = p + 3;
+ while (*pp >= 'a' && *pp <= 'z')
+ pp++;
+ /* /dev/xvd[a-z]+[0-9]* */
+ *pp = '\0';
+ return path;
+ }
+
+#ifdef HAVE_DEVICE_MAPPER
+ /* If this is a DM-RAID device.
+ Compare os_dev rather than path here, since nodes under
+ /dev/mapper/ are often symlinks. */
+ if ((strncmp ("/dev/mapper/", os_dev, 12) == 0))
+ {
+ struct dm_tree *tree;
+ uint32_t maj, min;
+ struct dm_tree_node *node = NULL, *child;
+ void *handle;
+ const char *node_uuid, *mapper_name = NULL, *child_uuid, *child_name;
+
+ tree = dm_tree_create ();
+ if (! tree)
+ {
+ grub_dprintf ("hostdisk", "dm_tree_create failed\n");
+ goto devmapper_out;
+ }
+
+ 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");
+ goto devmapper_out;
+ }
+
+ node = dm_tree_find_node (tree, maj, min);
+ if (! node)
+ {
+ grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
+ goto devmapper_out;
+ }
+ node_uuid = dm_tree_node_get_uuid (node);
+ if (! node_uuid)
+ {
+ grub_dprintf ("hostdisk", "%s has no DM uuid\n", path);
+ node = NULL;
+ goto devmapper_out;
+ }
+ if (strncmp (node_uuid, "LVM-", 4) == 0)
+ {
+ grub_dprintf ("hostdisk", "%s is an LVM\n", path);
+ node = NULL;
+ goto devmapper_out;
+ }
+ if (strncmp (node_uuid, "mpath-", 6) == 0)
+ {
+ /* Multipath partitions have partN-mpath-* UUIDs, and are
+ linear mappings so are handled by
+ grub_util_get_dm_node_linear_info. Multipath disks are not
+ linear mappings and must be handled specially. */
+ grub_dprintf ("hostdisk", "%s is a multipath disk\n", path);
+ mapper_name = dm_tree_node_get_name (node);
+ goto devmapper_out;
+ }
+ if (strncmp (node_uuid, "DMRAID-", 7) != 0)
+ {
+ int major, minor;
+ const char *node_name;
+ grub_dprintf ("hostdisk", "%s is not DM-RAID\n", path);
+
+ if ((node_name = dm_tree_node_get_name (node))
+ && grub_util_get_dm_node_linear_info (node_name,
+ &major, &minor))
+ {
+ if (tree)
+ dm_tree_free (tree);
+ free (path);
+ char *ret = grub_find_device ("/dev",
+ (major << 8) | minor);
+ return ret;
+ }
+
+ node = NULL;
+ goto devmapper_out;
+ }
+
+ handle = NULL;
+ /* Counter-intuitively, device-mapper refers to the disk-like
+ device containing a DM-RAID partition device as a "child" of
+ the partition device. */
+ child = dm_tree_next_child (&handle, node, 0);
+ if (! child)
+ {
+ grub_dprintf ("hostdisk", "%s has no DM children\n", path);
+ goto devmapper_out;
+ }
+ child_uuid = dm_tree_node_get_uuid (child);
+ if (! child_uuid)
+ {
+ grub_dprintf ("hostdisk", "%s child has no DM uuid\n", path);
+ goto devmapper_out;
+ }
+ else if (strncmp (child_uuid, "DMRAID-", 7) != 0)
+ {
+ grub_dprintf ("hostdisk", "%s child is not DM-RAID\n", path);
+ goto devmapper_out;
+ }
+ child_name = dm_tree_node_get_name (child);
+ if (! child_name)
+ {
+ grub_dprintf ("hostdisk", "%s child has no DM name\n", path);
+ goto devmapper_out;
+ }
+ mapper_name = child_name;
+
+devmapper_out:
+ if (! mapper_name && node)
+ {
+ /* This is a DM-RAID disk, not a partition. */
+ mapper_name = dm_tree_node_get_name (node);
+ if (! mapper_name)
+ grub_dprintf ("hostdisk", "%s has no DM name\n", path);
+ }
+ if (tree)
+ dm_tree_free (tree);
+ free (path);
+ if (mapper_name)
+ return xasprintf ("/dev/mapper/%s", mapper_name);
+ else
+ return NULL;
+ }
+#endif /* HAVE_DEVICE_MAPPER */
+ }
+
+ return path;
+
+#elif defined(__GNU__)
+ char *path = xstrdup (os_dev);
+ if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0)
+ {
+ char *p = strchr (path + 7, 's');
+ if (p)
+ *p = '\0';
+ }
+ return path;
+
+#elif defined(__CYGWIN__)
+ char *path = xstrdup (os_dev);
+ if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z')
+ path[8] = 0;
+ return path;
+
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ char *out, *out2;
+ if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
+ return xstrdup (os_dev);
+ grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
+
+ out2 = xasprintf ("/dev/%s", out);
+ free (out);
+
+ return out2;
+#elif defined(__APPLE__)
+ char *path = xstrdup (os_dev);
+ if (strncmp ("/dev/", path, 5) == 0)
+ {
+ char *p;
+ for (p = path + 5; *p; ++p)
+ if (grub_isdigit(*p))
+ {
+ p = strpbrk (p, "sp");
+ if (p)
+ *p = '\0';
+ break;
+ }
+ }
+ return path;
+
+#elif defined(__NetBSD__)
+ /* NetBSD uses "/dev/r[a-z]+[0-9][a-z]". */
+ char *path = xstrdup (os_dev);
+ if (strncmp ("/dev/r", path, sizeof("/dev/r") - 1) == 0 &&
+ (path[sizeof("/dev/r") - 1] >= 'a' && path[sizeof("/dev/r") - 1] <= 'z') &&
+ strncmp ("fd", path + sizeof("/dev/r") - 1, sizeof("fd") - 1) != 0) /* not a floppy device name */
+ {
+ char *p;
+ for (p = path + sizeof("/dev/r"); *p >= 'a' && *p <= 'z'; p++);
+ if (grub_isdigit(*p))
+ {
+ p++;
+ if ((*p >= 'a' && *p <= 'z') && (*(p+1) == '\0'))
+ {
+ /* path matches the required regular expression and
+ p points to its last character. */
+ int rawpart = -1;
+# ifdef HAVE_GETRAWPARTITION
+ rawpart = getrawpartition();
+# endif /* HAVE_GETRAWPARTITION */
+ if (rawpart >= 0)
+ *p = 'a' + rawpart;
+ }
+ }
+ }
+ return path;
+
+#elif defined (__sun__)
+ char *colon = grub_strrchr (os_dev, ':');
+ if (grub_memcmp (os_dev, "/devices", sizeof ("/devices") - 1) == 0
+ && colon)
+ {
+ char *ret = xmalloc (colon - os_dev + sizeof (":q,raw"));
+ grub_memcpy (ret, os_dev, colon - os_dev);
+ grub_memcpy (ret + (colon - os_dev), ":q,raw", sizeof (":q,raw"));
+ return ret;
+ }
+ else
+ return xstrdup (os_dev);
+#else
+# warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
+ return xstrdup (os_dev);
+#endif
+}
+
+static const char *
+find_system_device (const char *os_dev, struct stat *st, int convert, int add)
+{
+ unsigned int i;
+ char *os_disk;
+ const char *drive;
+
+ if (convert)
+ os_disk = convert_system_partition_to_system_disk (os_dev, st);
+ else
+ os_disk = xstrdup (os_dev);
+ if (! os_disk)
+ return NULL;
+
+ drive = grub_hostdisk_os_dev_to_grub_drive (os_disk, add);
+ free (os_disk);
+ return drive;
+}
+
+/*
+ * Note: we do not use the new partition naming scheme as dos_part does not
+ * necessarily correspond to an msdos partition.
+ */
+static char *
+make_device_name (const char *drive, int dos_part, int bsd_part)
+{
+ char *ret, *ptr, *end;
+ const char *iptr;
+
+ ret = xmalloc (strlen (drive) * 2
+ + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
+ ",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
+ end = (ret + strlen (drive) * 2
+ + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
+ ",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
+ ptr = ret;
+ for (iptr = drive; *iptr; iptr++)
+ {
+ if (*iptr == ',')
+ *ptr++ = '\\';
+ *ptr++ = *iptr;
+ }
+ *ptr = 0;
+ if (dos_part >= 0)
+ snprintf (ptr, end - ptr, ",%d", dos_part + 1);
+ ptr += strlen (ptr);
+ if (bsd_part >= 0)
+ snprintf (ptr, end - ptr, ",%d", bsd_part + 1);
+
+ return ret;
+}
+
+#if defined(__sun__)
+static int
+device_is_wholedisk (const char *os_dev)
+{
+ if (grub_memcmp (os_dev, "/devices/", sizeof ("/devices/") - 1) != 0)
+ return 1;
+ if (grub_memcmp (os_dev + strlen (os_dev) - (sizeof (":q,raw") - 1),
+ ":q,raw", (sizeof (":q,raw") - 1)) == 0)
+ return 1;
+ return 0;
+}
+#endif
+
+#if defined(__linux__) || defined(__CYGWIN__)
+static int
+device_is_wholedisk (const char *os_dev)
+{
+ int len = strlen (os_dev);
+
+ if (os_dev[len - 1] < '0' || os_dev[len - 1] > '9')
+ return 1;
+ return 0;
+}
+#endif
+
+#if defined(__NetBSD__)
+/* Try to determine whether a given device name corresponds to a whole disk.
+ This function should give in most cases a definite answer, but it may
+ actually give an approximate one in the following sense: if the return
+ value is 0 then the device name does not correspond to a whole disk. */
+static int
+device_is_wholedisk (const char *os_dev)
+{
+ int len = strlen (os_dev);
+ int rawpart = -1;
+
+# ifdef HAVE_GETRAWPARTITION
+ rawpart = getrawpartition();
+# endif /* HAVE_GETRAWPARTITION */
+ if (rawpart < 0)
+ return 1;
+ return (os_dev[len - 1] == ('a' + rawpart));
+}
+#endif /* defined(__NetBSD__) */
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+static int
+device_is_wholedisk (const char *os_dev)
+{
+ const char *p;
+
+ if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
+ return 0;
+
+ for (p = os_dev + sizeof ("/dev/") - 1; *p; ++p)
+ if (grub_isdigit (*p))
+ {
+ if (strchr (p, 's'))
+ return 0;
+ break;
+ }
+
+ return 1;
+}
+#endif /* defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
+
+char *
+grub_util_biosdisk_get_grub_dev (const char *os_dev)
+{
+ struct stat st;
+ const char *drive;
+ char *sys_disk;
+
+ grub_util_info ("Looking for %s", os_dev);
+
+ if (stat (os_dev, &st) < 0)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev);
+ grub_util_info ("cannot stat `%s'", os_dev);
+ return 0;
+ }
+
+ drive = find_system_device (os_dev, &st, 1, 1);
+ if (!drive)
+ {
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+ "no mapping exists for `%s'", os_dev);
+ grub_util_info ("no mapping exists for `%s'", os_dev);
+ return 0;
+ }
+
+ sys_disk = convert_system_partition_to_system_disk (os_dev, &st);
+ if (grub_strcmp (os_dev, sys_disk) == 0)
+ {
+ free (sys_disk);
+ return make_device_name (drive, -1, -1);
+ }
+ free (sys_disk);
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__)
+ if (! S_ISCHR (st.st_mode))
+#else
+ if (! S_ISBLK (st.st_mode))
+#endif
+ return make_device_name (drive, -1, -1);
+
+#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__sun__)
+
+ /* Linux counts partitions uniformly, whether a BSD partition or a DOS
+ partition, so mapping them to GRUB devices is not trivial.
+ Here, get the start sector of a partition by HDIO_GETGEO, and
+ compare it with each partition GRUB recognizes.
+
+ Cygwin /dev/sdXN emulation uses Windows partition mapping. It
+ does not count the extended partition and missing primary
+ partitions. Use same method as on Linux here.
+
+ For NetBSD and FreeBSD, proceed as for Linux, except that the start
+ sector is obtained from the disk label. */
+ {
+ char *name, *partname;
+ grub_disk_t disk;
+ grub_disk_addr_t start;
+ auto int find_partition (grub_disk_t dsk,
+ const grub_partition_t partition);
+
+ int find_partition (grub_disk_t dsk __attribute__ ((unused)),
+ const grub_partition_t partition)
+ {
+ grub_disk_addr_t part_start = 0;
+ grub_util_info ("Partition %d starts from %lu",
+ partition->number, partition->start);
+
+ part_start = grub_partition_get_start (partition);
+
+ if (start == part_start)
+ {
+ partname = grub_partition_get_name (partition);
+ return 1;
+ }
+
+ return 0;
+ }
+
+ name = make_device_name (drive, -1, -1);
+
+# if !defined(HAVE_DIOCGDINFO) && !defined(__sun__)
+ if (MAJOR (st.st_rdev) == FLOPPY_MAJOR)
+ return name;
+# else /* defined(HAVE_DIOCGDINFO) */
+ /* Since os_dev and convert_system_partition_to_system_disk (os_dev) are
+ * different, we know that os_dev cannot be a floppy device. */
+# endif /* !defined(HAVE_DIOCGDINFO) */
+
+ start = grub_hostdisk_find_partition_start (os_dev);
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ free (name);
+ return 0;
+ }
+
+ grub_util_info ("%s starts from %lu", os_dev, start);
+
+ if (start == 0 && device_is_wholedisk (os_dev))
+ return name;
+
+ grub_util_info ("opening the device %s", name);
+ disk = grub_disk_open (name);
+ free (name);
+
+ if (! disk)
+ {
+ /* We already know that the partition exists. Given that we already
+ checked the device map above, we can only get
+ GRUB_ERR_UNKNOWN_DEVICE at this point if the disk does not exist.
+ This can happen on Xen, where disk images in the host can be
+ assigned to devices that have partition-like names in the guest
+ but are really more like disks. */
+ if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
+ {
+ grub_util_warn
+ ("disk does not exist, so falling back to partition device %s",
+ os_dev);
+
+ drive = find_system_device (os_dev, &st, 0, 1);
+ if (!drive)
+ {
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+ "no mapping exists for `%s'", os_dev);
+ return 0;
+ }
+
+ return make_device_name (drive, -1, -1);
+ }
+ else
+ return 0;
+ }
+
+ name = grub_util_get_ldm (disk, start);
+ if (name)
+ return name;
+
+ partname = NULL;
+
+ grub_partition_iterate (disk, find_partition);
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_disk_close (disk);
+ return 0;
+ }
+
+ if (partname == NULL)
+ {
+ grub_disk_close (disk);
+ grub_util_info ("cannot find the partition of `%s'", os_dev);
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "cannot find the partition of `%s'", os_dev);
+ return 0;
+ }
+
+ name = grub_xasprintf ("%s,%s", disk->name, partname);
+ free (partname);
+ grub_disk_close (disk);
+ return name;
+ }
+
+#elif defined(__GNU__)
+ /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
+ {
+ char *p;
+ int dos_part = -1;
+ int bsd_part = -1;
+
+ p = strrchr (os_dev, 's');
+ if (p)
+ {
+ long int n;
+ char *q;
+
+ p++;
+ n = strtol (p, &q, 10);
+ if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX)
+ {
+ dos_part = (int) n - 1;
+
+ if (*q >= 'a' && *q <= 'g')
+ bsd_part = *q - 'a';
+ }
+ }
+
+ return make_device_name (drive, dos_part, bsd_part);
+ }
+
+#else
+# warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly."
+ return make_device_name (drive, -1, -1);
+#endif
+}
+
+int
+grub_util_biosdisk_is_present (const char *os_dev)
+{
+ struct stat st;
+
+ if (stat (os_dev, &st) < 0)
+ return 0;
+
+ return find_system_device (os_dev, &st, 1, 0) != NULL;
+}
+
char *
grub_util_get_grub_dev (const char *os_dev)
{
=== modified file 'util/grub-fstest.c'
--- util/grub-fstest.c 2011-11-13 18:53:12 +0000
+++ util/grub-fstest.c 2012-01-28 13:51:46 +0000
@@ -344,14 +344,16 @@
}
}
+ grub_ldm_fini ();
grub_lvm_fini ();
grub_mdraid09_fini ();
grub_mdraid1x_fini ();
- grub_raid_fini ();
- grub_raid_init ();
+ grub_diskfilter_fini ();
+ grub_diskfilter_init ();
grub_mdraid09_init ();
grub_mdraid1x_init ();
grub_lvm_init ();
+ grub_ldm_init ();
switch (cmd)
{
=== modified file 'util/grub-mount.c'
--- util/grub-mount.c 2011-11-13 18:53:12 +0000
+++ util/grub-mount.c 2012-01-28 13:51:46 +0000
@@ -364,8 +364,8 @@
grub_lvm_fini ();
grub_mdraid09_fini ();
grub_mdraid1x_fini ();
- grub_raid_fini ();
- grub_raid_init ();
+ grub_diskfilter_fini ();
+ grub_diskfilter_init ();
grub_mdraid09_init ();
grub_mdraid1x_init ();
grub_lvm_init ();
=== modified file 'util/grub-probe.c'
--- util/grub-probe.c 2012-01-23 18:33:40 +0000
+++ util/grub-probe.c 2012-01-28 13:51:46 +0000
@@ -31,7 +31,7 @@
#include <grub/emu/getroot.h>
#include <grub/term.h>
#include <grub/env.h>
-#include <grub/raid.h>
+#include <grub/diskfilter.h>
#include <grub/i18n.h>
#include <grub/emu/misc.h>
#include <grub/util/ofpath.h>
@@ -128,10 +128,15 @@
if (!disk)
return -1;
- if (disk->dev->id != GRUB_DISK_DEVICE_RAID_ID)
- return -1;
-
- return ((struct grub_raid_array *) disk->data)->level;
+ if (disk->dev->id != GRUB_DISK_DEVICE_DISKFILTER_ID)
+ return -1;
+
+ if (disk->name[0] != 'm' || disk->name[1] != 'd')
+ return -1;
+
+ if (!((struct grub_diskfilter_lv *) disk->data)->segments)
+ return -1;
+ return ((struct grub_diskfilter_lv *) disk->data)->segments->type;
}
/* Since OF path names can have "," characters in them, and GRUB
@@ -281,9 +286,14 @@
list = tmp;
}
- if (disk->dev->id == GRUB_DISK_DEVICE_LVM_ID)
+ if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID
+ && grub_memcmp (disk->name, "lvm/", sizeof ("lvm/") - 1) == 0)
printf ("lvm ");
+ if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID
+ && grub_memcmp (disk->name, "ldm/", sizeof ("ldm/") - 1) == 0)
+ printf ("ldm ");
+
if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
grub_util_cryptodisk_print_abstraction (disk);
@@ -747,8 +757,8 @@
grub_lvm_fini ();
grub_mdraid09_fini ();
grub_mdraid1x_fini ();
- grub_raid_fini ();
- grub_raid_init ();
+ grub_diskfilter_fini ();
+ grub_diskfilter_init ();
grub_mdraid09_init ();
grub_mdraid1x_init ();
grub_lvm_init ();
=== modified file 'util/grub-setup.c'
--- util/grub-setup.c 2012-01-24 13:39:29 +0000
+++ util/grub-setup.c 2012-01-28 13:51:46 +0000
@@ -133,7 +133,7 @@
static void
setup (const char *dir,
const char *boot_file, const char *core_file,
- const char *root, const char *dest, int must_embed, int force,
+ const char *root, const char *dest, int force,
int fs_probe, int allow_floppy)
{
char *boot_path, *core_path, *core_path_dev, *core_path_dev_full;
@@ -281,6 +281,7 @@
grub_partition_map_t dest_partmap = NULL;
grub_partition_t container = dest_dev->disk->partition;
int multiple_partmaps = 0;
+ int is_ldm;
grub_err_t err;
grub_disk_addr_t *sectors;
int i;
@@ -328,6 +329,8 @@
if (!fs)
grub_errno = GRUB_ERR_NONE;
+ is_ldm = grub_util_is_ldm (dest_dev->disk);
+
#ifdef GRUB_MACHINE_PCBIOS
if (fs_probe)
{
@@ -352,6 +355,17 @@
"result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
"by grub-setup (--skip-fs-probe disables this "
"check, use at your own risk)"), dest_dev->disk->name, dest_partmap->name);
+ if (is_ldm && dest_partmap && strcmp (dest_partmap->name, "msdos") != 0
+ && strcmp (dest_partmap->name, "gpt") != 0)
+ grub_util_error (_("%s appears to contain a %s partition map and "
+ "LDM which isn't known to be a safe combination."
+ " Installing GRUB there could "
+ "result in FILESYSTEM DESTRUCTION if valuable data"
+ " is overwritten "
+ "by grub-setup (--skip-fs-probe disables this "
+ "check, use at your own risk)"),
+ dest_dev->disk->name, dest_partmap->name);
+
}
#endif
@@ -364,14 +378,14 @@
free (tmp_img);
- if (! dest_partmap && ! fs)
+ if (! dest_partmap && ! fs && !is_ldm)
{
grub_util_warn (_("Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea."));
goto unable_to_embed;
}
- if (multiple_partmaps || (dest_partmap && fs))
+ if (multiple_partmaps || (dest_partmap && fs) || (is_ldm && fs))
{
- grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem. This is not supported yet."));
+ grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels. This is not supported yet."));
goto unable_to_embed;
}
@@ -390,7 +404,10 @@
}
nsec = core_sectors;
- if (dest_partmap)
+ if (is_ldm)
+ err = grub_util_ldm_embed (dest_dev->disk, &nsec,
+ GRUB_EMBED_PCBIOS, §ors);
+ else if (dest_partmap)
err = dest_partmap->embed (dest_dev->disk, &nsec,
GRUB_EMBED_PCBIOS, §ors);
else
@@ -485,15 +502,10 @@
unable_to_embed:
- if (must_embed)
- grub_util_error (_("embedding is not possible, but this is required when "
- "the root device is on a RAID array or LVM volume"));
-
-#ifdef GRUB_MACHINE_PCBIOS
- if (dest_dev->disk->id != root_dev->disk->id)
+ if (dest_dev->disk->id != root_dev->disk->id
+ || dest_dev->disk->dev->id != root_dev->disk->dev->id)
grub_util_error (_("embedding is not possible, but this is required for "
- "cross-disk install"));
-#endif
+ "cross-disk, RAID and LVM install"));
grub_util_warn (_("Embedding is not possible. GRUB can only be installed in this "
"setup by using blocklists. However, blocklists are UNRELIABLE and "
@@ -853,7 +865,6 @@
{
char *root_dev = NULL;
char *dest_dev = NULL;
- int must_embed = 0;
struct arguments arguments;
set_program_name (argv[0]);
@@ -888,8 +899,8 @@
grub_lvm_fini ();
grub_mdraid09_fini ();
grub_mdraid1x_fini ();
- grub_raid_fini ();
- grub_raid_init ();
+ grub_diskfilter_fini ();
+ grub_diskfilter_init ();
grub_mdraid09_init ();
grub_mdraid1x_init ();
grub_lvm_init ();
@@ -944,53 +955,12 @@
arguments.dir ? : DEFAULT_DIRECTORY);
}
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- if (grub_util_lvm_isvolume (root_dev))
- must_embed = 1;
-#endif
-
-#ifdef __linux__
- if (root_dev[0] == 'm' && root_dev[1] == 'd'
- && ((root_dev[2] >= '0' && root_dev[2] <= '9') || root_dev[2] == '/'))
- {
- /* FIXME: we can avoid this on RAID1. */
- must_embed = 1;
- }
-
- if (dest_dev[0] == 'm' && dest_dev[1] == 'd'
- && ((dest_dev[2] >= '0' && dest_dev[2] <= '9') || dest_dev[2] == '/'))
- {
- char **devicelist;
- int i;
-
- if (arguments.device[0] == '/')
- devicelist = grub_util_raid_getmembers (arguments.device, 1);
- else
- {
- char *devname;
- devname = xasprintf ("/dev/%s", dest_dev);
- devicelist = grub_util_raid_getmembers (dest_dev, 1);
- free (devname);
- }
-
- for (i = 0; devicelist[i]; i++)
- {
- setup (arguments.dir ? : DEFAULT_DIRECTORY,
- arguments.boot_file ? : DEFAULT_BOOT_FILE,
- arguments.core_file ? : DEFAULT_CORE_FILE,
- root_dev, grub_util_get_grub_dev (devicelist[i]), 1,
- arguments.force, arguments.fs_probe,
- arguments.allow_floppy);
- }
- }
- else
-#endif
- /* Do the real work. */
- setup (arguments.dir ? : DEFAULT_DIRECTORY,
- arguments.boot_file ? : DEFAULT_BOOT_FILE,
- arguments.core_file ? : DEFAULT_CORE_FILE,
- root_dev, dest_dev, must_embed, arguments.force,
- arguments.fs_probe, arguments.allow_floppy);
+ /* Do the real work. */
+ setup (arguments.dir ? : DEFAULT_DIRECTORY,
+ arguments.boot_file ? : DEFAULT_BOOT_FILE,
+ arguments.core_file ? : DEFAULT_CORE_FILE,
+ root_dev, dest_dev, arguments.force,
+ arguments.fs_probe, arguments.allow_floppy);
/* Free resources. */
grub_fini_all ();
next reply other threads:[~2012-01-28 14:37 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-01-28 14:36 Vladimir 'φ-coder/phcoder' Serbinenko [this message]
2012-01-29 13:29 ` Unify raid and lvm handling Vladimir 'φ-coder/phcoder' Serbinenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4F240803.70202@gmail.com \
--to=phcoder@gmail.com \
--cc=grub-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.