]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Merge common RAID and LVM logic to an abstract diskfilter.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sun, 29 Jan 2012 13:28:01 +0000 (14:28 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sun, 29 Jan 2012 13:28:01 +0000 (14:28 +0100)
Add LDM support using the same framework.

* Makefile.util.def (libgrubkern): Add grub-core/disk/ldm.c,
grub-core/disk/diskfilter.c and grub-core/partmap/gpt.c.
(libgrubmods): Remove grub-core/disk/raid.c and
grub-core/partmap/gpt.c.
* grub-core/Makefile.core.def (ldm): New module.
(raid): Renamed to diskfilter. All users updated.
* grub-core/disk/raid.c: Moved to ...
* grub-core/disk/diskfilter.c: ... here.
* grub-core/disk/diskfilter.c: Rename grub_raid_ to grub_diskfilter_.
(lv_num): New var.
(find_array): Renamed to ...
(find_lv): ... this. Support multi-LV. Skip nameless LVs
(grub_is_array_readable): Renamed to ...
(grub_is_lv_readable): ... this. Support multinode hierarchy.
(insert_array): New argument id.
(is_node_readable): New function.
(scan_device): Rename to ...
(scan_disk): .. this. Restrict to one disk.
(scan_devices): New function.
(grub_diskfilter_iterate): Support multi-LV.
Skip invisible and nameless LVs.
(grub_diskfilter_memberlist): Support multi-LV.
(grub_diskfilter_read_node): New function.
(grub_raid_read): Most of logic moved to ...
(read_segment): ... here
(read_lv): New function.
(grub_diskfilter_get_vg_by_uuid): New function.
(grub_diskfilter_make_raid): Likewise.
* grub-core/disk/ldm.c: New file.
* grub-core/disk/lvm.c (vg_list): Removed.
(lv_count): Likewise.
(scan_depth): Likewise.
(is_lv_readable): Likewise.
(grub_lvm_getvalue): Advance pointer past the number.
(find_lv): Removed.
(do_lvm_scan): Refactored into ...
(grub_lvm_detect): ... this. Support raid.
(grub_lvm_iterate): Removed.
(grub_lvm_memberlist): Likewise.
(grub_lvm_open): Likewise.
(grub_lvm_close): Likewise.
(read_lv): Likewise.
(read_node): Likewise.
(is_node_readable): Likewise.
(is_lv_readable): Likewise.
(grub_lvm_read): Likewise.
(grub_lvm_write): Likewise.
(grub_lvm_dev): Use diskfilter
(GRUB_MOD_INIT): Likewise.
(GRUB_MOD_FINI): Likewise.
* grub-core/disk/dmraid_nvidia.c (grub_dmraid_nv_detect): Use
new interface.
* grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): Likewise.
* grub-core/disk/mdraid_linux.c (grub_mdraid_detect): Likewise.
* grub-core/disk/raid5_recover.c (grub_raid5_recover): Use
grub_diskfilter_read_node.
Fix a bug with xor.
* grub-core/disk/raid6_recover.c (grub_raid6_recover): Use
grub_diskfilter_read_node.
Support GRUB_RAID_LAYOUT_MUL_FROM_POS.
* grub-core/kern/disk.c (grub_disk_dev_list): Make global.
(grub_disk_dev_iterate): Move from here...
* include/grub/disk.h (grub_disk_dev_iterate): ... to here. Inlined.
* grub-core/kern/emu/hostdisk.c (grub_hostdisk_find_partition_start):
Make global.
(grub_hostdisk_find_partition_start): Likewise.
(grub_hostdisk_os_dev_to_grub_drive): New function.
(grub_util_biosdisk_get_osdev): Check that disk is biosdisk.
* grub-core/kern/emu/hostdisk.c (make_device_name): Move to ...
* util/getroot.c (make_device_name): ... here.
* grub-core/kern/emu/hostdisk.c (grub_util_get_dm_node_linear_info):
Move to ...
* util/getroot.c (grub_util_get_dm_node_linear_info): ...here.
* grub-core/kern/emu/hostdisk.c
(convert_system_partition_to_system_disk): Move to ...
* util/getroot.c (convert_system_partition_to_system_disk): ...here.
* grub-core/kern/emu/hostdisk.c (device_is_wholedisk): Move to ...
* util/getroot.c (device_is_wholedisk): ... here.
* grub-core/kern/emu/hostdisk.c (find_system_device): Move to ...
* util/getroot.c (find_system_device): ... here.
* grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_present):
Move to ...
* util/getroot.c (grub_util_biosdisk_is_present): ...here.
* grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_get_grub_dev):
Move to ...
* util/getroot.c (grub_util_biosdisk_get_grub_dev): ... here.
Handle LDM.
* grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_floppy):
Move to ...
* util/getroot.c (grub_util_biosdisk_is_floppy): ... here.
* grub-core/partmap/gpt.c (grub_gpt_partition_map_iterate): Made global.
* include/grub/disk.h (grub_disk_dev_id): Replaced RAID and LVM with
DISKFILTER.
* include/grub/raid.h: Renamed to ...
* include/grub/diskfilter.h: ... this.
* include/grub/diskfilter.h: Rename grub_raid_* to grub_diskfilter_*
(GRUB_RAID_LAYOUT_*): Make into array.
(GRUB_RAID_LAYOUT_MUL_FROM_POS): New value.
(grub_diskfilter_vg): New struct.
(grub_diskfilter_pv_id): Likewise.
(grub_raid_member): Removed.
(grub_raid_array): Likewise.
(grub_diskfilter_pv): New struct.
(grub_diskfilter_lv): Likewise.
(grub_diskfilter_segment): Likewise.
(grub_diskfilter_node): Likewise.
(grub_diskfilter_get_vg_by_uuid): New proto.
(grub_raid_register): Inline.
(grub_diskfilter_unregister): Likewise.
(grub_diskfilter_make_raid): New proto.
(grub_diskfilter_vg_register): Likewise.
(grub_diskfilter_read_node): Likewise.
(grub_diskfilter_get_pv_from_disk) [GRUB_UTIL]: Likewise.
* include/grub/emu/hostdisk.h (grub_util_get_ldm): New proto.
(grub_util_is_ldm): Likewise.
(grub_util_ldm_embed) [GRUB_UTIL]: Likewise.
(grub_hostdisk_find_partition_start): Likewise.
(grub_hostdisk_os_dev_to_grub_drive): Likewise.
* include/grub/gpt_partition.h (GRUB_GPT_PARTITION_TYPE_LDM):
New definition.
(grub_gpt_partition_map_iterate): New proto.
* include/grub/lvm.h (grub_lvm_vg): Removed.
(grub_lvm_pv): Likewise.
(grub_lvm_lv): Likewise.
(grub_lvm_segment): Likewise.
(grub_lvm_node): Likewise.
* util/getroot.c [...]
* util/grub-probe.c (probe_raid_level): Handle diskfilter.
(probe_abstraction): Likewise.
* util/grub-setup.c (setup): Remove must_embed. Support LDM.
(main): Remove dead logic.

27 files changed:
ChangeLog
Makefile.util.def
grub-core/Makefile.core.def
grub-core/disk/diskfilter.c [new file with mode: 0644]
grub-core/disk/dmraid_nvidia.c
grub-core/disk/ldm.c [new file with mode: 0644]
grub-core/disk/lvm.c
grub-core/disk/mdraid1x_linux.c
grub-core/disk/mdraid_linux.c
grub-core/disk/raid.c [deleted file]
grub-core/disk/raid5_recover.c
grub-core/disk/raid6_recover.c
grub-core/kern/disk.c
grub-core/kern/emu/full.c
grub-core/kern/emu/hostdisk.c
grub-core/partmap/gpt.c
include/grub/disk.h
include/grub/diskfilter.h [new file with mode: 0644]
include/grub/emu/hostdisk.h
include/grub/gpt_partition.h
include/grub/lvm.h
include/grub/raid.h [deleted file]
util/getroot.c
util/grub-fstest.c
util/grub-mount.c
util/grub-probe.c
util/grub-setup.c

index fdbeaeb76f573ff8a927b756ed05d2d1b4a3c633..13ee2dae68a6aae4239e3c551f9a5d7a2a2bdb74 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,140 @@
+2012-01-29  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Merge common RAID and LVM logic to an abstract diskfilter.
+       Add LDM support using the same framework.
+
+       * Makefile.util.def (libgrubkern): Add grub-core/disk/ldm.c,
+       grub-core/disk/diskfilter.c and grub-core/partmap/gpt.c.
+       (libgrubmods): Remove grub-core/disk/raid.c and
+       grub-core/partmap/gpt.c.
+       * grub-core/Makefile.core.def (ldm): New module.
+       (raid): Renamed to diskfilter. All users updated.
+       * grub-core/disk/raid.c: Moved to ...
+       * grub-core/disk/diskfilter.c: ... here.
+       * grub-core/disk/diskfilter.c: Rename grub_raid_ to grub_diskfilter_.
+       (lv_num): New var.
+       (find_array): Renamed to ...
+       (find_lv): ... this. Support multi-LV. Skip nameless LVs
+       (grub_is_array_readable): Renamed to ...
+       (grub_is_lv_readable): ... this. Support multinode hierarchy.
+       (insert_array): New argument id.
+       (is_node_readable): New function.
+       (scan_device): Rename to ...
+       (scan_disk): .. this. Restrict to one disk.
+       (scan_devices): New function.
+       (grub_diskfilter_iterate): Support multi-LV.
+       Skip invisible and nameless LVs.
+       (grub_diskfilter_memberlist): Support multi-LV.
+       (grub_diskfilter_read_node): New function.
+       (grub_raid_read): Most of logic moved to ...
+       (read_segment): ... here
+       (read_lv): New function.
+       (grub_diskfilter_get_vg_by_uuid): New function.
+       (grub_diskfilter_make_raid): Likewise.
+       * grub-core/disk/ldm.c: New file.
+       * grub-core/disk/lvm.c (vg_list): Removed.
+       (lv_count): Likewise.
+       (scan_depth): Likewise.
+       (is_lv_readable): Likewise.
+       (grub_lvm_getvalue): Advance pointer past the number.
+       (find_lv): Removed.
+       (do_lvm_scan): Refactored into ...
+       (grub_lvm_detect): ... this. Support raid.
+       (grub_lvm_iterate): Removed.
+       (grub_lvm_memberlist): Likewise.
+       (grub_lvm_open): Likewise.
+       (grub_lvm_close): Likewise.
+       (read_lv): Likewise.
+       (read_node): Likewise.
+       (is_node_readable): Likewise.
+       (is_lv_readable): Likewise.
+       (grub_lvm_read): Likewise.
+       (grub_lvm_write): Likewise.
+       (grub_lvm_dev): Use diskfilter
+       (GRUB_MOD_INIT): Likewise.
+       (GRUB_MOD_FINI): Likewise.
+       * grub-core/disk/dmraid_nvidia.c (grub_dmraid_nv_detect): Use
+       new interface.
+       * grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): Likewise.
+       * grub-core/disk/mdraid_linux.c (grub_mdraid_detect): Likewise.
+       * grub-core/disk/raid5_recover.c (grub_raid5_recover): Use
+       grub_diskfilter_read_node.
+       Fix a bug with xor.
+       * grub-core/disk/raid6_recover.c (grub_raid6_recover): Use
+       grub_diskfilter_read_node.
+       Support GRUB_RAID_LAYOUT_MUL_FROM_POS.
+       * grub-core/kern/disk.c (grub_disk_dev_list): Make global.
+       (grub_disk_dev_iterate): Move from here...
+       * include/grub/disk.h (grub_disk_dev_iterate): ... to here. Inlined.
+       * grub-core/kern/emu/hostdisk.c (grub_hostdisk_find_partition_start):
+       Make global.
+       (grub_hostdisk_find_partition_start): Likewise.
+       (grub_hostdisk_os_dev_to_grub_drive): New function.
+       (grub_util_biosdisk_get_osdev): Check that disk is biosdisk.
+       * grub-core/kern/emu/hostdisk.c (make_device_name): Move to ...
+       * util/getroot.c (make_device_name): ... here.
+       * grub-core/kern/emu/hostdisk.c (grub_util_get_dm_node_linear_info):
+       Move to ...
+       * util/getroot.c (grub_util_get_dm_node_linear_info): ...here.
+       * grub-core/kern/emu/hostdisk.c
+       (convert_system_partition_to_system_disk): Move to ...
+       * util/getroot.c (convert_system_partition_to_system_disk): ...here.
+       * grub-core/kern/emu/hostdisk.c (device_is_wholedisk): Move to ...
+       * util/getroot.c (device_is_wholedisk): ... here.
+       * grub-core/kern/emu/hostdisk.c (find_system_device): Move to ...
+       * util/getroot.c (find_system_device): ... here.
+       * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_present):
+       Move to ...
+       * util/getroot.c (grub_util_biosdisk_is_present): ...here.
+       * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_get_grub_dev):
+       Move to ...
+       * util/getroot.c (grub_util_biosdisk_get_grub_dev): ... here.
+       Handle LDM.
+       * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_floppy):
+       Move to ...
+       * util/getroot.c (grub_util_biosdisk_is_floppy): ... here.
+       * grub-core/partmap/gpt.c (grub_gpt_partition_map_iterate): Made global.
+       * include/grub/disk.h (grub_disk_dev_id): Replaced RAID and LVM with
+       DISKFILTER.
+       * include/grub/raid.h: Renamed to ...
+       * include/grub/diskfilter.h: ... this.
+       * include/grub/diskfilter.h: Rename grub_raid_* to grub_diskfilter_*
+       (GRUB_RAID_LAYOUT_*): Make into array.
+       (GRUB_RAID_LAYOUT_MUL_FROM_POS): New value.
+       (grub_diskfilter_vg): New struct.
+       (grub_diskfilter_pv_id): Likewise.
+       (grub_raid_member): Removed.
+       (grub_raid_array): Likewise.
+       (grub_diskfilter_pv): New struct.
+       (grub_diskfilter_lv): Likewise.
+       (grub_diskfilter_segment): Likewise.
+       (grub_diskfilter_node): Likewise.
+       (grub_diskfilter_get_vg_by_uuid): New proto.
+       (grub_raid_register): Inline.
+       (grub_diskfilter_unregister): Likewise.
+       (grub_diskfilter_make_raid): New proto.
+       (grub_diskfilter_vg_register): Likewise.
+       (grub_diskfilter_read_node): Likewise.
+       (grub_diskfilter_get_pv_from_disk) [GRUB_UTIL]: Likewise.
+       * include/grub/emu/hostdisk.h (grub_util_get_ldm): New proto.
+       (grub_util_is_ldm): Likewise.
+       (grub_util_ldm_embed) [GRUB_UTIL]: Likewise.
+       (grub_hostdisk_find_partition_start): Likewise.
+       (grub_hostdisk_os_dev_to_grub_drive): Likewise.
+       * include/grub/gpt_partition.h (GRUB_GPT_PARTITION_TYPE_LDM):
+       New definition.
+       (grub_gpt_partition_map_iterate): New proto.
+       * include/grub/lvm.h (grub_lvm_vg): Removed.
+       (grub_lvm_pv): Likewise.
+       (grub_lvm_lv): Likewise.
+       (grub_lvm_segment): Likewise.
+       (grub_lvm_node): Likewise.
+       * util/getroot.c [...]
+       * util/grub-probe.c (probe_raid_level): Handle diskfilter.
+       (probe_abstraction): Likewise.
+       * util/grub-setup.c (setup): Remove must_embed. Support LDM.
+       (main): Remove dead logic.
+
 2012-01-28  Vladimir Serbinenko  <phcoder@gmail.com>
 
        Simplify root device discover and don't fail when trying to open
index c865870be157dd3a767e43c63b041917a78f99f0..9902584ba911026c7e1c8a4491ad7ce8dea31a6c 100644 (file)
@@ -29,6 +29,9 @@ library = {
   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 @@ library = {
   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 @@ library = {
   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;
index 645deb92faeefa917f6bb9be9699fbdc1ed1f653..cd56b103a084ff2922d69cd73794ce1c4d9f5fdd 100644 (file)
@@ -874,6 +874,11 @@ module = {
   common = disk/lvm.c;
 };
 
+module = {
+  name = ldm;
+  common = disk/ldm.c;
+};
+
 module = {
   name = mdraid09;
   common = disk/mdraid_linux.c;
@@ -885,8 +890,8 @@ module = {
 };
 
 module = {
-  name = raid;
-  common = disk/raid.c;
+  name = diskfilter;
+  common = disk/diskfilter.c;
 };
 
 module = {
diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c
new file mode 100644 (file)
index 0000000..da93776
--- /dev/null
@@ -0,0 +1,1081 @@
+/* diskfilter.c - module to read RAID arrays.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007,2008,2009,2010  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/partition.h>
+#ifdef GRUB_UTIL
+#include <grub/i18n.h>
+#include <grub/util/misc.h>
+#endif
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* 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;
+grub_diskfilter_t grub_diskfilter_list;
+static int inscnt = 0;
+static int lv_num = 0;
+
+static struct grub_diskfilter_lv *
+find_lv (const char *name);
+static int is_lv_readable (struct grub_diskfilter_lv *lv);
+
+\f
+
+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++)
+    {
+      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 1;
+}
+
+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)));
+
+static int
+scan_disk (const char *name)
+{
+  auto int hook (grub_disk_t disk, grub_partition_t p);
+  int hook (grub_disk_t disk, grub_partition_t p)
+    {
+      struct grub_diskfilter_vg *arr;
+      grub_disk_addr_t start_sector;
+      struct grub_diskfilter_pv_id id;
+      grub_diskfilter_t diskfilter;
+
+      grub_dprintf ("diskfilter", "Scanning for DISKFILTER devices on disk %s\n",
+                   name);
+#ifdef GRUB_UTIL
+      grub_util_info ("Scanning for DISKFILTER devices on disk %s", name);
+#endif
+
+      disk->partition = p;
+      
+      for (arr = array_list; arr != NULL; arr = arr->next)
+       {
+         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;
+  static int scan_depth = 0;
+
+  if (scan_depth > 100)
+    return 0;
+
+  disk = grub_disk_open (name);
+  if (!disk)
+    {
+      grub_errno = GRUB_ERR_NONE;
+      return 0;
+    }
+  scan_depth++;
+  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_diskfilter_iterate (int (*hook) (const char *name),
+                  grub_disk_pull_t pull)
+{
+  struct grub_diskfilter_vg *array;
+  int islcnt = 0;
+
+  if (pull == GRUB_DISK_PULL_RESCAN)
+    {
+      islcnt = inscnt;
+      scan_devices (NULL);
+    }
+
+  if (pull != GRUB_DISK_PULL_NONE && pull != GRUB_DISK_PULL_RESCAN)
+    return 0;
+
+  for (array = array_list; array; array = array->next)
+    {
+      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;
+}
+
+#ifdef GRUB_UTIL
+static grub_disk_memberlist_t
+grub_diskfilter_memberlist (grub_disk_t disk)
+{
+  struct grub_diskfilter_lv *lv = disk->data;
+  grub_disk_memberlist_t list = NULL, tmp;
+  struct grub_diskfilter_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;
+}
+
+static const char *
+grub_diskfilter_getname (struct grub_disk *disk)
+{
+  struct grub_diskfilter_lv *array = disk->data;
+
+  return array->vg->driver->name;
+}
+#endif
+
+static inline int
+ascii2hex (char c)
+{
+  if (c >= '0' && c <= '9')
+    return c - '0';
+  if (c >= 'a' && c <= 'f')
+    return c - 'a' + 10;
+  if (c >= 'A' && c <= 'F')
+    return c - 'A' + 10;
+  return 0;
+}
+
+static struct grub_diskfilter_lv *
+find_lv (const char *name)
+{
+  struct grub_diskfilter_vg *vg;
+  struct grub_diskfilter_lv *lv = NULL;
+
+  if (grub_memcmp (name, "mduuid/", sizeof ("mduuid/") - 1) == 0)
+    {
+      const char *uuidstr = name + sizeof ("mduuid/") - 1;
+      grub_size_t uuid_len = grub_strlen (uuidstr) / 2;
+      grub_uint8_t uuidbin[uuid_len];
+      unsigned i;
+      for (i = 0; i < uuid_len; i++)
+       uuidbin[i] = ascii2hex (uuidstr[2 * i + 1])
+         | (ascii2hex (uuidstr[2 * i]) << 4);
+
+      for (vg = array_list; vg; vg = vg->next)      
+       {
+         if (uuid_len == vg->uuid_len
+             && grub_memcmp (uuidbin, vg->uuid, uuid_len) == 0)
+           if (is_lv_readable (vg->lvs))
+             return vg->lvs;
+       }
+    }
+
+  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_diskfilter_open (const char *name, grub_disk_t disk)
+{
+  struct grub_diskfilter_lv *lv;
+
+  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);
+
+  lv = find_lv (name);
+
+  if (! lv)
+    {
+      scan_devices (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 DISKFILTER device %s",
+                       name);
+
+  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_diskfilter_close (grub_disk_t disk __attribute ((unused)))
+{
+  return;
+}
+
+static grub_err_t
+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_uint64_t disknr, b, near, far, ofs;
+       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)
+             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 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 = seg->type / 3;
+
+       /* Find the first sector to read. */
+       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 = 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)
+             {
+               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;
+           disknr++;
+
+           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");
+      }
+      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 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)))
+{
+  return GRUB_ERR_NOT_IMPLEMENTED_YET;
+}
+
+struct grub_diskfilter_vg *
+grub_diskfilter_get_vg_by_uuid (grub_size_t uuidlen, char *uuid)
+{
+  struct grub_diskfilter_vg *p;
+
+  for (p = array_list; p != NULL; p = p->next)
+    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)
+    {
+      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)
+             {
+               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 (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. */
+      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;
+  grub_err_t err;
+
+  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;
+      pv->next = array->pvs;
+      array->pvs = pv;
+      array->lvs->segments->nodes[i].pv = pv;
+    }
+
+  err = grub_diskfilter_vg_register (array);
+  if (err)
+    goto fail;
+
+  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;
+}
+
+static void
+free_array (void)
+{
+  while (array_list)
+    {
+      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;
+}
+
+#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)
+      {
+       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_diskfilter_dev =
+  {
+    .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_diskfilter_memberlist,
+    .raidname = grub_diskfilter_getname,
+#endif
+    .next = 0
+  };
+
+\f
+GRUB_MOD_INIT(diskfilter)
+{
+  grub_disk_dev_register (&grub_diskfilter_dev);
+}
+
+GRUB_MOD_FINI(diskfilter)
+{
+  grub_disk_dev_unregister (&grub_diskfilter_dev);
+  free_array ();
+}
index 08600519a44a36db0d08cf7fcc2f28e6a1a3b566..aa3a6ef6c5079bf2fa3fd3bfe1665f0e7505f888 100644 (file)
@@ -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_super
   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;
-
-  grub_memcpy (array->uuid, (char *) &sb.array.signature,
+  uuid = grub_malloc (sizeof (sb.array.signature));
+  if (! uuid)
+    return NULL;
+
+  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 @@ static struct grub_raid grub_dmraid_nv_dev =
 
 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);
 }
diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c
new file mode 100644 (file)
index 0000000..08568e9
--- /dev/null
@@ -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);
+}
index f3a99c66eaee193ee5ac0d4cae67b1593895f88f..d7be3e8a5a0100425525eec82a68ee7b55c520c2 100644 (file)
 
 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 @@ grub_lvm_getvalue (char **p, const char *str)
   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,671 @@ grub_lvm_check_flag (char *p, const char *str, const char *flag)
     }
 }
 
-static struct grub_lvm_lv *
-find_lv (const char *name)
+static struct grub_diskfilter_vg * 
+grub_lvm_detect (grub_disk_t disk,
+                struct grub_diskfilter_pv_id *id,
+                grub_disk_addr_t *start_sector)
 {
-  struct grub_lvm_vg *vg;
-  struct grub_lvm_lv *lv = NULL;
-  for (vg = vg_list; vg; vg = vg->next)
+  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++)
     {
-      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;
-}
+      err = grub_disk_read (disk, i, 0, sizeof(buf), buf);
+      if (err)
+       goto fail;
 
-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;
+      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 ("scanning %s for LVM", name);
+      grub_util_info ("no LVM signature found");
 #endif
+      goto fail;
+    }
 
-    disk = grub_disk_open (name);
-    if (!disk)
-      {
-       if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
-         grub_errno = GRUB_ERR_NONE;
-       return 0;
-      }
+  pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
 
-    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;
-         }
+  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';
 
-    /* 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;
-      }
+  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");
 
-    /* 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");
+      grub_util_info ("we don't support multiple LVM data areas\n");
 #endif
-       goto fail;
-      }
+      goto fail;
+    }
 
-    pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
+  dlocn++;
+  mda_offset = grub_le_to_cpu64 (dlocn->offset);
+  mda_size = grub_le_to_cpu64 (dlocn->size);
 
-    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';
+  /* It's possible to have multiple copies of metadata areas, we just use the
+     first one.  */
 
-    dlocn = pvh->disk_areas_xl;
+  /* Allocate buffer space for the circular worst-case scenario. */
+  metadatabuf = grub_malloc (2 * mda_size);
+  if (! metadatabuf)
+    goto fail;
 
-    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");
+  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 ("we don't support multiple LVM data areas\n");
+      grub_util_info ("unknown LVM metadata header\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.  */
+      goto fail2;
+    }
 
-    /* Allocate buffer space for the circular worst-case scenario. */
-    metadatabuf = grub_malloc (2 * mda_size);
-    if (! metadatabuf)
-      goto fail;
+  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);
 
-    err = grub_disk_read (disk, 0, mda_offset, mda_size, metadatabuf);
-    if (err)
-      goto fail2;
+  while (*q != ' ' && q < metadatabuf + mda_size)
+    q++;
 
-    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");
+  if (q == metadatabuf + mda_size)
+    {
 #ifdef GRUB_UTIL
-       grub_util_info ("unknown LVM metadata header\n");
+      grub_util_info ("error parsing metadata\n");
 #endif
-       goto fail2;
-      }
+      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);
+  vgname_len = q - p;
+  vgname = grub_malloc (vgname_len + 1);
+  if (!vgname)
+    goto fail2;
 
-    while (*q != ' ' && q < metadatabuf + mda_size)
-      q++;
+  grub_memcpy (vgname, p, vgname_len);
+  vgname[vgname_len] = '\0';
 
-    if (q == metadatabuf + mda_size)
-      {
+  p = grub_strstr (q, "id = \"");
+  if (p == NULL)
+    {
 #ifdef GRUB_UTIL
-       grub_util_info ("error parsing metadata\n");
+      grub_util_info ("couldn't find ID\n");
 #endif
-       goto fail2;
-      }
-
-    vgname_len = q - p;
-    vgname = grub_malloc (vgname_len + 1);
-    if (!vgname)
-      goto fail2;
+      goto fail3;
+    }
+  p += sizeof ("id = \"") - 1;
+  grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN);
+  vg_id[GRUB_LVM_ID_STRLEN] = '\0';
 
-    grub_memcpy (vgname, p, vgname_len);
-    vgname[vgname_len] = '\0';
+  vg = grub_diskfilter_get_vg_by_uuid (GRUB_LVM_ID_STRLEN, vg_id);
 
-    p = grub_strstr (q, "id = \"");
-    if (p == NULL)
-      {
-#ifdef GRUB_UTIL
-       grub_util_info ("couldn't find ID\n");
-#endif
+  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;
-      }
-    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;
-      }
+      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;
 
-    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)
-         {
+      vg->extent_size = grub_lvm_getvalue (&p, "extent_size = ");
+      if (p == NULL)
+       {
 #ifdef GRUB_UTIL
-           grub_util_info ("unknown extent size\n");
+         grub_util_info ("unknown extent size\n");
 #endif
-           goto fail4;
-         }
+         goto fail4;
+       }
 
-       vg->lvs = NULL;
-       vg->pvs = NULL;
+      vg->lvs = NULL;
+      vg->pvs = NULL;
 
-       p = grub_strstr (p, "physical_volumes {");
-       if (p)
-         {
-           p += sizeof ("physical_volumes {") - 1;
+      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++;
+         /* Add all the pvs to the volume group. */
+         while (1)
+           {
+             int s;
+             while (grub_isspace (*p))
+               p++;
 
-               if (*p == '}')
-                 break;
+             if (*p == '}')
+               break;
 
-               pv = grub_malloc (sizeof (*pv));
-               q = p;
-               while (*q != ' ')
-                 q++;
+             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';
+             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;
+             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->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 = grub_lvm_getvalue (&p, "pe_start = ");
-               if (p == NULL)
-                 {
+             pv->start_sector = grub_lvm_getvalue (&p, "pe_start = ");
+             if (p == NULL)
+               {
 #ifdef GRUB_UTIL
-                   grub_util_info ("unknown pe_start\n");
+                 grub_util_info ("unknown pe_start\n");
 #endif
-                   goto pvs_fail;
-                 }
+                 goto pvs_fail;
+               }
 
-               p = grub_strchr (p, '}');
-               if (p == NULL)
-                 {
+             p = grub_strchr (p, '}');
+             if (p == NULL)
+               {
 #ifdef GRUB_UTIL
-                   grub_util_info ("error parsing pe_start\n");
+                 grub_util_info ("error parsing pe_start\n");
 #endif
-                   goto pvs_fail;
-                 }
-               p++;
+                 goto pvs_fail;
+               }
+             p++;
 
-               pv->disk = NULL;
-               pv->next = vg->pvs;
-               vg->pvs = pv;
+             pv->disk = NULL;
+             pv->next = vg->pvs;
+             vg->pvs = pv;
 
-               continue;
-             pvs_fail:
-               grub_free (pv->name);
-               grub_free (pv);
-               goto fail4;
-             }
-         }
+             continue;
+           pvs_fail:
+             grub_free (pv->name);
+             grub_free (pv);
+             goto fail4;
+           }
+       }
 
-       p = grub_strstr (p, "logical_volumes");
-       if (p)
-         {
-           p += 18;
+      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_lvm_lv *lv;
-               struct grub_lvm_segment *seg;
-               int is_pvmove;
+         /* 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++;
+             while (grub_isspace (*p))
+               p++;
 
-               if (*p == '}')
-                 break;
+             if (*p == '}')
+               break;
 
-               lv = grub_malloc (sizeof (*lv));
+             lv = grub_zalloc (sizeof (*lv));
 
-               q = p;
-               while (*q != ' ')
-                 q++;
+             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)
+             s = q - p;
+             lv->name = grub_strndup (p, s);
+             if (!lv->name)
+               goto lvs_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->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;
-               }
+               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->size = 0;
 
-               lv->visible = grub_lvm_check_flag (p, "status", "VISIBLE");
-               is_pvmove = grub_lvm_check_flag (p, "status", "PVMOVE");
+             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)
-                 {
+             lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
+             if (p == NULL)
+               {
 #ifdef GRUB_UTIL
-                   grub_util_info ("unknown segment_count\n");
+                 grub_util_info ("unknown segment_count\n");
 #endif
-                   goto lvs_fail;
-                 }
-               lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count);
-               seg = lv->segments;
+                 goto lvs_fail;
+               }
+             lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count);
+             seg = lv->segments;
 
-               for (i = 0; i < lv->segment_count; i++)
-                 {
+             for (i = 0; i < lv->segment_count; i++)
+               {
 
-                   p = grub_strstr (p, "segment");
-                   if (p == NULL)
-                     {
+                 p = grub_strstr (p, "segment");
+                 if (p == NULL)
+                   {
 #ifdef GRUB_UTIL
-                       grub_util_info ("unknown segment\n");
+                     grub_util_info ("unknown segment\n");
 #endif
-                       goto lvs_segment_fail;
-                     }
+                     goto lvs_segment_fail;
+                   }
 
-                   seg->start_extent = grub_lvm_getvalue (&p, "start_extent = ");
-                   if (p == NULL)
-                     {
+                 seg->start_extent = grub_lvm_getvalue (&p, "start_extent = ");
+                 if (p == NULL)
+                   {
 #ifdef GRUB_UTIL
-                       grub_util_info ("unknown start_extent\n");
+                     grub_util_info ("unknown start_extent\n");
 #endif
-                       goto lvs_segment_fail;
-                     }
-                   seg->extent_count = grub_lvm_getvalue (&p, "extent_count = ");
-                   if (p == NULL)
-                     {
+                     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");
+                     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;
+                 p = grub_strstr (p, "type = \"");
+                 if (p == NULL)
+                   goto lvs_segment_fail;
+                 p += sizeof("type = \"") - 1;
 
-                   if (grub_memcmp (p, "striped\"",
-                                    sizeof ("striped\"") - 1) == 0)
-                     {
-                       struct grub_lvm_node *stripe;
+                 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_LVM_STRIPED;
-                       seg->node_count = grub_lvm_getvalue (&p, "stripe_count = ");
-                       if (p == NULL)
-                         {
+                     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");
+                         grub_util_info ("unknown stripe_count\n");
 #endif
-                           goto lvs_segment_fail;
-                         }
+                         goto lvs_segment_fail;
+                       }
 
-                       if (seg->node_count != 1)
-                         seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
+                     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;
+                     seg->nodes = grub_zalloc (sizeof (*stripe)
+                                               * seg->node_count);
+                     stripe = seg->nodes;
 
-                       p = grub_strstr (p, "stripes = [");
-                       if (p == NULL)
-                         {
+                     p = grub_strstr (p, "stripes = [");
+                     if (p == NULL)
+                       {
 #ifdef GRUB_UTIL
-                           grub_util_info ("unknown stripes\n");
+                         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;
-                         }
-                       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);
+                         grub_memcpy (stripe->name, p, s);
+                         stripe->name[s] = '\0';
 
-                       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;
-                 }
+                         p = q + 1;
 
-               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;
-             }
-         }
-
-       /* 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);
-      }
+                         stripe->start = grub_lvm_getvalue (&p, ",")
+                           * vg->extent_size;
+                         if (p == NULL)
+                           continue;
 
-    /* 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;
-           }
-       }
+                         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;
+                       }
 
-    goto fail2;
+                     seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
+                                               * seg->node_count);
 
-    /* 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;
-  }
+                     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;
 
-  scan_depth++;
-  grub_device_iterate (&grub_lvm_scan_device);
-  scan_depth--;
-}
+                     for (j = 0; j < seg->node_count; j++)
+                       {
+                         char *lvname;
 
-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;
+                         p = grub_strchr (p, '"');
+                         if (p == NULL)
+                           continue;
+                         q = ++p;
+                         while (*q != '"')
+                           q++;
 
-  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;
-           }
-    }
+                         s = q - p;
 
-  return 0;
-}
+                         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 = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC;
+                         break;
+                       case '5':
+                         seg->type = GRUB_DISKFILTER_RAID5;
+                         seg->layout = GRUB_RAID_LAYOUT_LEFT_SYMMETRIC;
+                         break;
+                       case '6':
+                         seg->type = GRUB_DISKFILTER_RAID6;
+                         seg->layout = (GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC
+                                        | GRUB_RAID_LAYOUT_MUL_FROM_POS);
+                         break;
+                       }
+                     seg->node_count = grub_lvm_getvalue (&p, "device_count = ");
+
+                     if (p == NULL)
+                       {
 #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;
-}
+                         grub_util_info ("unknown device_count\n");
 #endif
+                         goto lvs_segment_fail;
+                       }
 
-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);
+                     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;
+                       }
 
-  disk->id = lv->number;
-  disk->data = lv;
-  disk->total_sectors = lv->size;
 
-  return 0;
-}
+                     seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
+                                               * seg->node_count);
 
-static void
-grub_lvm_close (grub_disk_t disk __attribute ((unused)))
-{
-  return;
-}
+                     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;
 
-static grub_err_t
-read_lv (struct grub_lvm_lv *lv, grub_disk_addr_t sector,
-        grub_size_t size, char *buf);
+                         grub_memcpy (lvname, p, s);
+                         lvname[s] = '\0';
+                         seg->nodes[j].name = lvname;
+                         p = q + 1;
+                       }
+                     if (seg->type == GRUB_DISKFILTER_RAID4)
+                       {
+                         char *tmp;
+                         tmp = seg->nodes[0].name;
+                         grub_memmove (seg->nodes, seg->nodes + 1,
+                                       sizeof (seg->nodes[0])
+                                       * (seg->node_count - 1));
+                         seg->nodes[seg->node_count - 1].name = tmp;
+                       }
+                   }
+                 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;
+                   }
 
-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);
+                 seg++;
 
-    }
-  if (node->lv)
-    return read_lv (node->lv, sector, size, buf);
-  return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown node '%s'", node->name);
-}
+                 continue;
+               lvs_segment_fail2:
+                 grub_free (seg->nodes);
+               lvs_segment_fail:
+                 goto fail4;
+               }
 
-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 (p != NULL)
+               p = grub_strchr (p, '}');
+             if (p == NULL)
+               goto lvs_fail;
+             p += 3;
 
-  if (!lv)
-    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown volume");
+             if (skip_lv)
+               {
+                 grub_free (lv->name);
+                 grub_free (lv);
+                 continue;
+               }
 
-  extent = grub_divmod64 (sector, vg->extent_size, NULL);
+             lv->vg = vg;
+             lv->next = vg->lvs;
+             vg->lvs = lv;
 
-  /* 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;
+             continue;
+           lvs_fail:
+             grub_free (lv->name);
+             grub_free (lv);
+             goto fail4;
+           }
        }
 
-      seg++;
+      /* 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++)
+             {
+               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;
+             }
+       
+      }
+      if (grub_diskfilter_vg_register (vg))
+       goto fail4;
     }
-
-  if (i == lv->segment_count)
-    return grub_error (GRUB_ERR_READ_ERROR, "incorrect segment");
-
-  switch (seg->type)
+  else
     {
-    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;
-       }
+      grub_free (vgname);
     }
-  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);
+  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;
 }
 
-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;
-}
+\f
 
-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
-  };
+static struct grub_diskfilter grub_lvm_dev = {
+  .name = "lvm",
+  .detect = grub_lvm_detect,
+  .next = 0
+};
 
-\f
-GRUB_MOD_INIT(lvm)
+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);
 }
index 19c43f45593568176bd5e286d7a2350e462f31d7..fa4b97b7719bc6df24ba271ac7a4d7f153ccec6b 100644 (file)
@@ -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 @@ struct grub_raid_super_1x
 
 #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 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
 
       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_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
        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 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
 
        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 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
          + 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;
+           return NULL;
          }
 
-       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);
+       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 @@ static struct grub_raid grub_mdraid_dev = {
 
 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);
 }
index 7ee513d26816f25267028c6909ddc68f45078503..1ca76fdfaa289f52b762053133e5a433d808e3db 100644 (file)
@@ -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_super_09
   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 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
   /* 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 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
 
   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");
-
-  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;
+    {
+      grub_error (GRUB_ERR_OUT_OF_RANGE,
+                 "spares aren't implemented");
+      return NULL;
+    }
+
   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 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
 
   *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 @@ static struct grub_raid grub_mdraid_dev = {
 
 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);
 }
diff --git a/grub-core/disk/raid.c b/grub-core/disk/raid.c
deleted file mode 100644 (file)
index 490cfa9..0000000
+++ /dev/null
@@ -1,921 +0,0 @@
-/* raid.c - module to read RAID arrays.  */
-/*
- *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2006,2007,2008,2009,2010  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/raid.h>
-#include <grub/partition.h>
-#ifdef GRUB_UTIL
-#include <grub/util/misc.h>
-#endif
-
-GRUB_MOD_LICENSE ("GPLv3+");
-
-/* Linked list of RAID arrays. */
-static struct grub_raid_array *array_list;
-grub_raid5_recover_func_t grub_raid5_recover_func;
-grub_raid6_recover_func_t grub_raid6_recover_func;
-static grub_raid_t grub_raid_list;
-static int inscnt = 0;
-
-static struct grub_raid_array *
-find_array (const char *name);
-
-\f
-static char
-grub_is_array_readable (struct grub_raid_array *array)
-{
-  switch (array->level)
-    {
-    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;
-      }
-    }
-
-  return 0;
-}
-
-static grub_err_t
-insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
-              grub_disk_addr_t start_sector, const char *scanner_name,
-             grub_raid_t raid __attribute__ ((unused)));
-
-static int scan_depth = 0;
-
-static void
-scan_devices (const char *arname)
-{
-  grub_raid_t raid;
-
-  auto int hook (const char *name);
-  int hook (const char *name)
-    {
-      grub_disk_t disk;
-      struct grub_raid_array array;
-      struct grub_raid_array *arr;
-      grub_disk_addr_t start_sector;
-
-      grub_dprintf ("raid", "Scanning for %s RAID devices on disk %s\n",
-                   raid->name, name);
-#ifdef GRUB_UTIL
-      grub_util_info ("Scanning for %s RAID devices on disk %s",
-                     raid->name, name);
-#endif
-
-      disk = grub_disk_open (name);
-      if (!disk)
-        return 0;
-      
-      for (arr = array_list; arr != NULL; arr = arr->next)
-       {
-         struct grub_raid_member *m;
-         for (m = arr->members; m < arr->members + arr->nr_devs; m++)
-           if (m->device && m->device->id == disk->id
-               && m->device->dev->id == 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 ();
-
-      grub_errno = GRUB_ERR_NONE;
-
-      grub_disk_close (disk);
-
-      if (arname && find_array (arname))
-       return 1;
-
-      return 0;
-    }
-
-  if (scan_depth)
-    return;
-
-  scan_depth++;
-  for (raid = grub_raid_list; raid; raid = raid->next)
-    grub_device_iterate (&hook);
-  scan_depth--;
-}
-
-static int
-grub_raid_iterate (int (*hook) (const char *name),
-                  grub_disk_pull_t pull)
-{
-  struct grub_raid_array *array;
-  int islcnt = 0;
-
-  if (pull == GRUB_DISK_PULL_RESCAN)
-    {
-      islcnt = inscnt;
-      scan_devices (NULL);
-    }
-
-  if (pull != GRUB_DISK_PULL_NONE && pull != GRUB_DISK_PULL_RESCAN)
-    return 0;
-
-  for (array = array_list; array != NULL; array = array->next)
-    {
-      if (grub_is_array_readable (array) && array->became_readable_at >= islcnt)
-       if (hook (array->name))
-         return 1;
-    }
-
-  return 0;
-}
-
-#ifdef GRUB_UTIL
-static grub_disk_memberlist_t
-grub_raid_memberlist (grub_disk_t disk)
-{
-  struct grub_raid_array *array = disk->data;
-  grub_disk_memberlist_t list = NULL, tmp;
-  unsigned int i;
-
-  for (i = 0; i < array->total_devs; i++)
-    if (array->members[i].device)
-      {
-        tmp = grub_malloc (sizeof (*tmp));
-        tmp->disk = array->members[i].device;
-        tmp->next = list;
-        list = tmp;
-      }
-
-  return list;
-}
-
-static const char *
-grub_raid_getname (struct grub_disk *disk)
-{
-  struct grub_raid_array *array = disk->data;
-
-  return array->driver->name;
-}
-#endif
-
-static inline int
-ascii2hex (char c)
-{
-  if (c >= '0' && c <= '9')
-    return c - '0';
-  if (c >= 'a' && c <= 'f')
-    return c - 'a' + 10;
-  if (c >= 'A' && c <= 'F')
-    return c - 'A' + 10;
-  return 0;
-}
-
-static struct grub_raid_array *
-find_array (const char *name)
-{
-  struct grub_raid_array *array;
-
-  if (grub_memcmp (name, "mduuid/", sizeof ("mduuid/") - 1) == 0)
-    {
-      const char *uuidstr = name + sizeof ("mduuid/") - 1;
-      grub_size_t uuid_len = grub_strlen (uuidstr) / 2;
-      grub_uint8_t uuidbin[uuid_len];
-      unsigned i;
-      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)
-       {
-         if (uuid_len == (unsigned) array->uuid_len
-             && grub_memcmp (uuidbin, array->uuid, uuid_len) == 0)
-           if (grub_is_array_readable (array))
-             return array;
-       }
-    }
-  else
-    for (array = array_list; array != NULL; array = array->next)
-      {
-       if (!grub_strcmp (array->name, name))
-         if (grub_is_array_readable (array))
-           return array;
-      }
-  return NULL;
-}
-
-static grub_err_t
-grub_raid_open (const char *name, grub_disk_t disk)
-{
-  struct grub_raid_array *array;
-  unsigned n;
-
-  if (grub_memcmp (name, "md", sizeof ("md") - 1) != 0)
-     return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
-                       name);
-
-  array = find_array (name);
-
-  if (! array)
-    {
-      scan_devices (name);
-      if (grub_errno)
-       {
-         grub_print_error ();
-         grub_errno = GRUB_ERR_NONE;
-       }
-      array = find_array (name);
-    }
-
-  if (!array)
-    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
-                       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);
-
-  return 0;
-}
-
-static void
-grub_raid_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:
-      {
-        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;
-           size -= read_size;
-           if (! size)
-             break;
-
-            b = 0;
-            disknr += (near - i);
-            while (disknr >= array->total_devs)
-              {
-                disknr -= array->total_devs;
-                read_sector += ofs;
-              }
-          }
-        break;
-      }
-
-    case 4:
-    case 5:
-    case 6:
-      {
-       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;
-
-       /* 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;
-
-       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;
-
-           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;
-              }
-
-           buf += read_size << GRUB_DISK_SECTOR_BITS;
-           size -= read_size;
-           if (! size)
-             break;
-
-            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;
-              }
-         }
-      }
-      break;
-    }
-
-  return err;
-}
-
-static grub_err_t
-grub_raid_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 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_raid_array *array = 0, *p;
-  int was_readable = 0;
-
-  /* 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)
-    {
-      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)
-             {
-               need_new_name = 1;
-               continue;
-             }
-           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;
-
-      /* 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++;
-
-  return 0;
-}
-
-static void
-free_array (void)
-{
-  struct grub_raid_array *array;
-
-  array = array_list;
-  while (array)
-    {
-      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);
-    }
-
-  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)
-      {
-       *p = q->next;
-       break;
-      }
-}
-
-static struct grub_disk_dev grub_raid_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,
-#ifdef GRUB_UTIL
-    .memberlist = grub_raid_memberlist,
-    .raidname = grub_raid_getname,
-#endif
-    .next = 0
-  };
-
-\f
-GRUB_MOD_INIT(raid)
-{
-  grub_disk_dev_register (&grub_raid_dev);
-}
-
-GRUB_MOD_FINI(raid)
-{
-  grub_disk_dev_unregister (&grub_raid_dev);
-  free_array ();
-}
index dfc89a71d55c942267531f76132141f8a2d4fdbe..62d76d1dfebeece04340295746af4783cd17316a 100644 (file)
 #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_raid5_recover (struct grub_raid_array *array, int disknr,
 
   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 @@ grub_raid5_recover (struct grub_raid_array *array, int disknr,
           return err;
         }
 
-      grub_crypto_xor (buf, buf2, buf2, size);
+      grub_crypto_xor (buf, buf, buf2, size);
     }
 
   grub_free (buf2);
index 05d8511c55bbe8a470e3e2f90d081b2d150e43f2..779a39eaa97b68d238b8e9a6163b8b951907b7ad 100644 (file)
@@ -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 @@ grub_raid6_init_table (void)
 }
 
 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,26 +81,29 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
     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++)
     {
+      int c;
+      if (array->layout & GRUB_RAID_LAYOUT_MUL_FROM_POS)
+       c = pos;
+      else
+       c = i;
       if (pos == disknr)
-        bad1 = i;
+        bad1 = c;
       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);
+              grub_raid_block_mulx (c, buf, size);
               grub_crypto_xor (qbuf, qbuf, buf, size);
             }
           else
@@ -109,13 +112,13 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
               if (bad2 >= 0)
                 goto quit;
 
-              bad2 = i;
+              bad2 = c;
               grub_errno = GRUB_ERR_NONE;
             }
         }
 
       pos++;
-      if (pos == (int) array->total_devs)
+      if (pos == (int) array->node_count)
         pos = 0;
     }
 
@@ -126,24 +129,16 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
   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 +150,14 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
       /* 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);
index fb9782ff9dd59229c1d5ba07eaa42822ca3b8481..df772d53114623a6da6b8b50c4a442e5fdbcfdff 100644 (file)
@@ -177,7 +177,7 @@ grub_disk_cache_store (unsigned long dev_id, unsigned long disk_id,
 
 \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 @@ grub_disk_dev_unregister (grub_disk_dev_t dev)
       }
 }
 
-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 *
index 87317c9168b9253aabd0b382625662cc626ba4d3..1ecd34f7d8e7776f811ac4bc6cd7acd3cf405b78 100644 (file)
@@ -72,8 +72,8 @@ grub_emu_post_init (void)
   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 ();
index 81e601f0bc19a8b9ba6c130bc241ce73ecdccb39..470bdcd16eb39866f6a2586f3b5843cdb3baae8a 100644 (file)
@@ -68,26 +68,12 @@ struct hd_geometry
 # 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 @@ struct hd_geometry
 # 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 @@ struct hd_geometry
 #  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 @@ grub_util_follow_gpart_up (const char *name, grub_disk_addr_t *off_out, char **n
     *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 @@ find_partition_start (const char *dev)
 }
 
 #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 @@ linux_find_partition (char *dev, grub_disk_addr_t sector)
       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 @@ grub_util_fd_seek (int fd, const char *name, grub_uint64_t off)
 }
 #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_util_biosdisk_fini (void)
   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, &params);
-  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 @@ grub_util_biosdisk_get_compatibility_hint (grub_disk_t disk)
 const char *
 grub_util_biosdisk_get_osdev (grub_disk_t disk)
 {
-  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;
+  return map[disk->id].device;
 }
index 049fda850283dc65335742f50e04a769d85151aa..dd123aac45270c9a5be382281d1f4a234784b27f 100644 (file)
@@ -45,10 +45,10 @@ static struct grub_partition_map grub_gpt_partition_map;
 
 \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 @@ gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors,
     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 @@ gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors,
 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
index d9afd5b7b6544dfc251c0cf381118bd6ea10f89c..a8cbe46b523a997c027ddb0226e64105442d2389 100644 (file)
@@ -32,8 +32,7 @@ enum grub_disk_dev_id
     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 @@ struct grub_disk_dev
 };
 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 grub_disk_cache_invalidate_all (void);
 
 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 @@ extern int EXPORT_VAR(grub_disk_firmware_is_tainted);
 
 #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 */
diff --git a/include/grub/diskfilter.h b/include/grub/diskfilter.h
new file mode 100644 (file)
index 0000000..ed2ac28
--- /dev/null
@@ -0,0 +1,191 @@
+/* diskfilter.h - On disk structures for RAID. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007,2008,2010  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_DISKFILTER_H
+#define GRUB_DISKFILTER_H      1
+
+#include <grub/types.h>
+#include <grub/list.h>
+
+enum
+  {
+    GRUB_RAID_LAYOUT_RIGHT_MASK        = 1,
+    GRUB_RAID_LAYOUT_SYMMETRIC_MASK = 2,
+    GRUB_RAID_LAYOUT_MUL_FROM_POS = 4,
+
+    GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC = 0,
+    GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC = GRUB_RAID_LAYOUT_RIGHT_MASK,
+    GRUB_RAID_LAYOUT_LEFT_SYMMETRIC = GRUB_RAID_LAYOUT_SYMMETRIC_MASK,
+    GRUB_RAID_LAYOUT_RIGHT_SYMMETRIC = (GRUB_RAID_LAYOUT_RIGHT_MASK
+                                       | GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
+  };
+
+
+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 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;
+
+  struct grub_diskfilter_vg * (*detect) (grub_disk_t disk,
+                                        struct grub_diskfilter_pv_id *id,
+                                        grub_disk_addr_t *start_sector);
+};
+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_diskfilter_segment *array,
+                                                 int disknr, int p, char *buf,
+                                                 grub_disk_addr_t sector,
+                                                 int size);
+
+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 */
index b8c072761bb5ec93073654b6cfc1c04fa397953c..8f97dce6df5861cb71e510e0c98003a9c64bd09f 100644 (file)
@@ -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 @@ ssize_t grub_util_fd_read (int fd, char *buf, size_t len);
 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);
index 5f8ddead731cd3db63455566316e7ab6c3ebb61b..83e3b3192d77b4c57882b96fc6a8f1f154533669 100644 (file)
@@ -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 @@ typedef struct grub_gpt_part_type grub_gpt_part_type_t;
   }
 
 #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 @@ struct grub_gpt_partentry
   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 */
index d77b88ff5ddd0557d8ac7c869e99f59977c3fc0a..2d4ab6ff394b1a059c9a005123a2d8693050a47e 100644 (file)
 #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
 
diff --git a/include/grub/raid.h b/include/grub/raid.h
deleted file mode 100644 (file)
index 1eb4372..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/* raid.h - On disk structures for RAID. */
-/*
- *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2006,2007,2008,2010  Free Software Foundation, Inc.
- *
- *  GRUB is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  GRUB is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef GRUB_RAID_H
-#define GRUB_RAID_H    1
-
-#include <grub/types.h>
-
-#define GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC       0
-#define GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC      1
-#define GRUB_RAID_LAYOUT_LEFT_SYMMETRIC                2
-#define GRUB_RAID_LAYOUT_RIGHT_SYMMETRIC       3
-
-#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. */
-  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
-{
-  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;
-};
-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,
-                                                 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,
-                                                 int disknr, int p, char *buf,
-                                                 grub_disk_addr_t sector,
-                                                 int size);
-
-extern grub_raid5_recover_func_t grub_raid5_recover_func;
-extern grub_raid6_recover_func_t grub_raid6_recover_func;
-
-#endif /* ! GRUB_RAID_H */
index 967e4b62b06357dea9e977da441c2df4d6fe23fb..6b773767c892b2fb7e87b9af542aa9b53f6d3400 100644 (file)
 #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 @@ grub_util_pull_device (const char *os_dev)
     }
 }
 
+#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, &params);
+  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)
 {
index 886155fe2bce2229cb84c83ef7fd2a06eb651a34..c81314e77da6b3b0f64315dc0a06450c44956014 100644 (file)
@@ -344,14 +344,16 @@ fstest (int n, char **args)
       }
   }
 
+  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)
     {
index da7d604a29b7efdce355926c1f3746738e60c149..e5a3b9f8e86a77d20c34fb56cea62beb58b58ea3 100644 (file)
@@ -364,8 +364,8 @@ fuse_init (void)
   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 ();
index 3750ce640fa68b74098dfbd280754e599338ab2e..bb75d938ccf11de7ce6e632d4121eb846fa610e5 100644 (file)
@@ -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 @@ probe_raid_level (grub_disk_t disk)
   if (!disk)
     return -1;
 
-  if (disk->dev->id != GRUB_DISK_DEVICE_RAID_ID)
+  if (disk->dev->id != GRUB_DISK_DEVICE_DISKFILTER_ID)
     return -1;
 
-  return ((struct grub_raid_array *) disk->data)->level;
+  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 @@ probe_abstraction (grub_disk_t disk)
       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 @@ main (int argc, char *argv[])
   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 ();
index 9618d1a5d269cddb7fa80bf25b694e247718be73..3db3d1f969a0ad8ed93a5ed57dcbaf25c5990ebf 100644 (file)
@@ -133,7 +133,7 @@ write_rootdev (char *core_img, grub_device_t root_dev,
 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 @@ setup (const char *dir,
     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 @@ setup (const char *dir,
     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 @@ setup (const char *dir,
                             "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 @@ setup (const char *dir,
 
     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 @@ setup (const char *dir,
       }
 
     nsec = core_sectors;
-    if (dest_partmap)
+    if (is_ldm)
+      err = grub_util_ldm_embed (dest_dev->disk, &nsec,
+                                GRUB_EMBED_PCBIOS, &sectors);
+    else if (dest_partmap)
       err = dest_partmap->embed (dest_dev->disk, &nsec,
                                 GRUB_EMBED_PCBIOS, &sectors);
     else
@@ -485,14 +502,16 @@ setup (const char *dir,
 
 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"));
+                      "cross-disk, RAID and LVM install"));
+#else
+  if (dest_dev->disk->dev->id != root_dev->disk->dev->id)
+    grub_util_error (_("embedding is not possible, but this is required for "
+                      "RAID and LVM install"));
+
 #endif
 
   grub_util_warn (_("Embedding is not possible.  GRUB can only be installed in this "
@@ -853,7 +872,6 @@ main (int argc, char *argv[])
 {
   char *root_dev = NULL;
   char *dest_dev = NULL;
-  int must_embed = 0;
   struct arguments arguments;
 
   set_program_name (argv[0]);
@@ -888,8 +906,8 @@ main (int argc, char *argv[])
   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 +962,12 @@ main (int argc, char *argv[])
                       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 ();