Hi,
This patch seperate the scan code from raid.c, and move it to
mdraid.c. raid.c only contain generic raid handling code now. This
make it much easier to extend to other raid layout, like various
fakeraids.
I also extend the function of grub-fstest so that it can be used to
debug raid, for example, you can run it like this:
grub-fstest -c 2 /dev/hdb1 /dev/hdd1 ls
--
Bean
diff --git a/conf/common.rmk b/conf/common.rmk
index 3d674a6..dee5d54 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -35,6 +35,7 @@ grub_fstest_SOURCES = util/grub-fstest.c util/hostfs.c util/misc.c \
\
kern/partition.c partmap/pc.c partmap/apple.c partmap/gpt.c \
kern/fs.c kern/env.c fs/fshelp.c disk/lvm.c disk/raid.c \
+ disk/mdraid.c \
grub_fstest_init.c
# For the parser.
@@ -257,7 +258,7 @@ gpt_mod_LDFLAGS = $(COMMON_LDFLAGS)
# Special disk structures
-pkglib_MODULES += raid.mod lvm.mod
+pkglib_MODULES += raid.mod lvm.mod mdraid.mod
# For raid.mod
raid_mod_SOURCES = disk/raid.c
@@ -269,6 +270,11 @@ lvm_mod_SOURCES = disk/lvm.c
lvm_mod_CFLAGS = $(COMMON_CFLAGS)
lvm_mod_LDFLAGS = $(COMMON_LDFLAGS)
+# For mdraid.mod
+mdraid_mod_SOURCES = disk/mdraid.c
+mdraid_mod_CFLAGS = $(COMMON_CFLAGS)
+mdraid_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
# Commands.
pkglib_MODULES += hello.mod boot.mod terminal.mod ls.mod \
cmp.mod cat.mod help.mod font.mod search.mod \
diff --git a/disk/i386/pc/biosdisk.c b/disk/i386/pc/biosdisk.c
index c8fd142..b40bb13 100644
--- a/disk/i386/pc/biosdisk.c
+++ b/disk/i386/pc/biosdisk.c
@@ -121,6 +121,7 @@ grub_biosdisk_open (const char *name, grub_disk_t disk)
data->flags = GRUB_BIOSDISK_FLAG_LBA | GRUB_BIOSDISK_FLAG_CDROM;
data->sectors = 32;
total_sectors = 9000000; /* TODO: get the correct size. */
+ disk->size_invalid = 1;
}
else if (drive & 0x80)
{
diff --git a/disk/mdraid.c b/disk/mdraid.c
new file mode 100644
index 0000000..0552436
--- /dev/null
+++ b/disk/mdraid.c
@@ -0,0 +1,245 @@
+/* mdraid.c - module to handle mdraid. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2008 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>
+
+/* Linux RAID on disk structures and constants,
+ copied from include/linux/raid/md_p.h. */
+
+#define GRUB_RAID_RESERVED_BYTES (64 * 1024)
+#define GRUB_RAID_RESERVED_SECTORS (GRUB_RAID_RESERVED_BYTES / 512)
+
+#define GRUB_RAID_NEW_SIZE_SECTORS(x) ((x & ~(GRUB_RAID_RESERVED_SECTORS - 1)) \
+ - GRUB_RAID_RESERVED_SECTORS)
+
+#define GRUB_RAID_SB_BYTES 4096
+#define GRUB_RAID_SB_WORDS (GRUB_RAID_SB_BYTES / 4)
+#define GRUB_RAID_SB_SECTORS (GRUB_RAID_SB_BYTES / 512)
+
+/*
+ * The following are counted in 32-bit words
+ */
+#define GRUB_RAID_SB_GENERIC_OFFSET 0
+
+#define GRUB_RAID_SB_PERSONALITY_OFFSET 64
+#define GRUB_RAID_SB_DISKS_OFFSET 128
+#define GRUB_RAID_SB_DESCRIPTOR_OFFSET 992
+
+#define GRUB_RAID_SB_GENERIC_CONSTANT_WORDS 32
+#define GRUB_RAID_SB_GENERIC_STATE_WORDS 32
+#define GRUB_RAID_SB_GENERIC_WORDS (GRUB_RAID_SB_GENERIC_CONSTANT_WORDS \
+ + GRUB_RAID_SB_GENERIC_STATE_WORDS)
+#define GRUB_RAID_SB_PERSONALITY_WORDS 64
+#define GRUB_RAID_SB_DESCRIPTOR_WORDS 32
+#define GRUB_RAID_SB_DISKS 27
+#define GRUB_RAID_SB_DISKS_WORDS (GRUB_RAID_SB_DISKS*GRUB_RAID_SB_DESCRIPTOR_WORDS)
+#define GRUB_RAID_SB_RESERVED_WORDS (1024 - GRUB_RAID_SB_GENERIC_WORDS \
+ - GRUB_RAID_SB_PERSONALITY_WORDS \
+ - GRUB_RAID_SB_DISKS_WORDS \
+ - GRUB_RAID_SB_DESCRIPTOR_WORDS)
+#define GRUB_RAID_SB_EQUAL_WORDS (GRUB_RAID_SB_GENERIC_WORDS \
+ + GRUB_RAID_SB_PERSONALITY_WORDS \
+ + GRUB_RAID_SB_DISKS_WORDS)
+
+/*
+ * Device "operational" state bits
+ */
+#define GRUB_RAID_DISK_FAULTY 0 /* disk is faulty / operational */
+#define GRUB_RAID_DISK_ACTIVE 1 /* disk is running or spare disk */
+#define GRUB_RAID_DISK_SYNC 2 /* disk is in sync with the raid set */
+#define GRUB_RAID_DISK_REMOVED 3 /* disk is in sync with the raid set */
+
+#define GRUB_RAID_DISK_WRITEMOSTLY 9 /* disk is "write-mostly" is RAID1 config.
+ * read requests will only be sent here in
+ * dire need
+ */
+
+
+#define GRUB_RAID_SB_MAGIC 0xa92b4efc
+
+/*
+ * Superblock state bits
+ */
+#define GRUB_RAID_SB_CLEAN 0
+#define GRUB_RAID_SB_ERRORS 1
+
+#define GRUB_RAID_SB_BITMAP_PRESENT 8 /* bitmap may be present nearby */
+
+struct grub_raid_disk_09 {
+ grub_uint32_t number; /* 0 Device number in the entire set */
+ grub_uint32_t major; /* 1 Device major number */
+ grub_uint32_t minor; /* 2 Device minor number */
+ grub_uint32_t raid_disk; /* 3 The role of the device in the raid set */
+ grub_uint32_t state; /* 4 Operational state */
+ grub_uint32_t reserved[GRUB_RAID_SB_DESCRIPTOR_WORDS - 5];
+};
+
+struct grub_raid_super_09 {
+ /*
+ * Constant generic information
+ */
+ grub_uint32_t md_magic; /* 0 MD identifier */
+ grub_uint32_t major_version; /* 1 major version to which the set conforms */
+ grub_uint32_t minor_version; /* 2 minor version ... */
+ grub_uint32_t patch_version; /* 3 patchlevel version ... */
+ grub_uint32_t gvalid_words; /* 4 Number of used words in this section */
+ grub_uint32_t set_uuid0; /* 5 Raid set identifier */
+ grub_uint32_t ctime; /* 6 Creation time */
+ grub_uint32_t level; /* 7 Raid personality */
+ grub_uint32_t size; /* 8 Apparent size of each individual disk */
+ grub_uint32_t nr_disks; /* 9 total disks in the raid set */
+ grub_uint32_t raid_disks; /* 10 disks in a fully functional raid set */
+ grub_uint32_t md_minor; /* 11 preferred MD minor device number */
+ grub_uint32_t not_persistent; /* 12 does it have a persistent superblock */
+ grub_uint32_t set_uuid1; /* 13 Raid set identifier #2 */
+ grub_uint32_t set_uuid2; /* 14 Raid set identifier #3 */
+ grub_uint32_t set_uuid3; /* 15 Raid set identifier #4 */
+ grub_uint32_t gstate_creserved[GRUB_RAID_SB_GENERIC_CONSTANT_WORDS - 16];
+
+ /*
+ * Generic state information
+ */
+ grub_uint32_t utime; /* 0 Superblock update time */
+ grub_uint32_t state; /* 1 State bits (clean, ...) */
+ grub_uint32_t active_disks; /* 2 Number of currently active disks */
+ grub_uint32_t working_disks; /* 3 Number of working disks */
+ grub_uint32_t failed_disks; /* 4 Number of failed disks */
+ grub_uint32_t spare_disks; /* 5 Number of spare disks */
+ grub_uint32_t sb_csum; /* 6 checksum of the whole superblock */
+#ifdef GRUB_HOST_WORDS_BIGENDIAN
+ grub_uint32_t events_hi; /* 7 high-order of superblock update count */
+ grub_uint32_t events_lo; /* 8 low-order of superblock update count */
+ grub_uint32_t cp_events_hi; /* 9 high-order of checkpoint update count */
+ grub_uint32_t cp_events_lo; /* 10 low-order of checkpoint update count */
+#else
+ grub_uint32_t events_lo; /* 7 low-order of superblock update count */
+ grub_uint32_t events_hi; /* 8 high-order of superblock update count */
+ grub_uint32_t cp_events_lo; /* 9 low-order of checkpoint update count */
+ grub_uint32_t cp_events_hi; /* 10 high-order of checkpoint update count */
+#endif
+ grub_uint32_t recovery_cp; /* 11 recovery checkpoint sector count */
+ grub_uint32_t gstate_sreserved[GRUB_RAID_SB_GENERIC_STATE_WORDS - 12];
+
+ /*
+ * Personality information
+ */
+ grub_uint32_t layout; /* 0 the array's physical layout */
+ grub_uint32_t chunk_size; /* 1 chunk size in bytes */
+ grub_uint32_t root_pv; /* 2 LV root PV */
+ grub_uint32_t root_block; /* 3 LV root block */
+ grub_uint32_t pstate_reserved[GRUB_RAID_SB_PERSONALITY_WORDS - 4];
+
+ /*
+ * Disks information
+ */
+ struct grub_raid_disk_09 disks[GRUB_RAID_SB_DISKS];
+
+ /*
+ * Reserved
+ */
+ grub_uint32_t reserved[GRUB_RAID_SB_RESERVED_WORDS];
+
+ /*
+ * Active descriptor
+ */
+ struct grub_raid_disk_09 this_disk;
+};
+
+static grub_err_t
+grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array)
+{
+ grub_disk_addr_t sector;
+ grub_uint64_t size;
+ struct grub_raid_super_09 sb;
+ grub_uint32_t *uuid;
+
+ /* The sector where the RAID superblock is stored, if available. */
+ size = grub_disk_get_size (disk);
+ sector = GRUB_RAID_NEW_SIZE_SECTORS(size);
+
+ if (grub_disk_read (disk, sector, 0, GRUB_RAID_SB_BYTES, (char *) &sb))
+ return grub_errno;
+
+ /* Look whether there is a RAID superblock. */
+ if (sb.md_magic != GRUB_RAID_SB_MAGIC)
+ return grub_error (GRUB_ERR_BAD_FS, "not raid");
+
+ /* FIXME: Also support version 1.0. */
+ if (sb.major_version != 0 || sb.minor_version != 90)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "Unsupported RAID version: %d.%d",
+ sb.major_version, sb.minor_version);
+
+ /* FIXME: Check the checksum. */
+
+ /* FIXME: Support all RAID levels. */
+ if (sb.level != 0 && sb.level != 1 && sb.level != 5)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "Unsupported RAID level: %d",
+ sb.level);
+
+ /* FIXME: Support all layouts. */
+ if (sb.level == 5 && sb.layout != 2)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "Unsupported RAID5 layout: %d",
+ sb.layout);
+
+ array->number = sb.md_minor;
+ array->level = sb.level;
+ array->layout = sb.layout;
+ array->total_devs = sb.nr_disks;
+ array->disk_size = sb.size * 2;
+ array->chunk_size = sb.chunk_size >> 9;
+ array->index = sb.this_disk.number;
+ array->uuid_len = 16;
+ array->uuid = grub_malloc (16);
+ if (! array->uuid)
+ return grub_errno;
+
+ uuid = (grub_uint32_t *) array->uuid;
+ uuid[0] = sb.set_uuid0;
+ uuid[1] = sb.set_uuid1;
+ uuid[2] = sb.set_uuid2;
+ uuid[3] = sb.set_uuid3;
+
+ return 0;
+}
+
+static struct grub_raid grub_mdraid_dev =
+{
+ .name = "md",
+ .detect = grub_mdraid_detect,
+ .next = 0
+};
+
+GRUB_MOD_INIT(mdraid)
+{
+ grub_raid_register (&grub_mdraid_dev);
+ grub_raid_rescan ();
+}
+
+GRUB_MOD_FINI(mdraid)
+{
+ grub_raid_register (&grub_mdraid_dev);
+}
diff --git a/disk/raid.c b/disk/raid.c
index 731bf1f..bdfb03d 100644
--- a/disk/raid.c
+++ b/disk/raid.c
@@ -113,7 +113,17 @@ grub_raid_open (const char *name, grub_disk_t disk)
{
case 0:
/* FIXME: RAID0 disks can have different sizes! */
- disk->total_sectors = array->total_devs * array->disk_size;
+ if (array->disk_size)
+ disk->total_sectors = array->total_devs * array->disk_size;
+ else
+ {
+ unsigned i;
+
+ disk->total_sectors = 0;
+ for (i = 0; i < array->total_devs; i++)
+ disk->total_sectors += array->device[i]->total_sectors;
+ }
+
break;
case 1:
@@ -348,167 +358,122 @@ grub_raid_write (grub_disk_t disk __attribute ((unused)),
return GRUB_ERR_NOT_IMPLEMENTED_YET;
}
-static int
-grub_raid_scan_device (const char *name)
-{
- grub_err_t err;
- grub_disk_t disk;
- grub_disk_addr_t sector;
- grub_uint64_t size;
- struct grub_raid_super_09 sb;
- struct grub_raid_array *p, *array = NULL;
-
- grub_dprintf ("raid", "Scanning for RAID devices\n");
-
- disk = grub_disk_open (name);
- if (!disk)
- return 0;
-
- /* The sector where the RAID superblock is stored, if available. */
- size = grub_disk_get_size (disk);
- sector = GRUB_RAID_NEW_SIZE_SECTORS(size);
+static grub_raid_t grub_raid_list;
- err = grub_disk_read (disk, sector, 0, GRUB_RAID_SB_BYTES, (char *) &sb);
- grub_disk_close (disk);
- if (err)
- {
- grub_errno = GRUB_ERR_NONE;
- return 0;
- }
-
- /* Look whether there is a RAID superblock. */
- if (sb.md_magic != GRUB_RAID_SB_MAGIC)
- return 0;
-
- /* FIXME: Also support version 1.0. */
- if (sb.major_version != 0 || sb.minor_version != 90)
- {
- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "Unsupported RAID version: %d.%d",
- sb.major_version, sb.minor_version);
- return 0;
- }
+void
+grub_raid_register (grub_raid_t raid)
+{
+ raid->next = grub_raid_list;
+ grub_raid_list = raid;
+}
- /* FIXME: Check the checksum. */
+void
+grub_raid_unregister (grub_raid_t raid)
+{
+ grub_raid_t *p, q;
- /* FIXME: Support all RAID levels. */
- if (sb.level != 0 && sb.level != 1 && sb.level != 5)
- {
- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "Unsupported RAID level: %d",
- sb.level);
- return 0;
- }
+ for (p = &grub_raid_list, q = *p; q; p = &(q->next), q = q->next)
+ if (q == raid)
+ {
+ *p = q->next;
+ break;
+ }
+}
- /* FIXME: Support all layouts. */
- if (sb.level == 5 && sb.layout != 2)
- {
- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "Unsupported RAID5 layout: %d",
- sb.layout);
- return 0;
- }
+static grub_err_t
+insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
+ const char *device_name)
+{
+ struct grub_raid_array *array = 0, *p;
/* See whether the device is part of an array we have already seen a
device from. */
for (p = array_list; p != NULL; p = p->next)
- {
- if (p->uuid[0] == sb.set_uuid0 && p->uuid[1] == sb.set_uuid1
- && p->uuid[2] == sb.set_uuid2 && p->uuid[3] == sb.set_uuid3)
- {
- array = p;
- break;
- }
- }
-
- /* Do some checks before adding the device to the array. */
- if (array)
- {
- /* 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, but what is the sanest things to do in such
- a case? */
-
- grub_error (GRUB_ERR_BAD_NUMBER,
- "array->nr_devs > array->total_devs (%d)?!?",
- array->total_devs);
-
- return 0;
- }
-
- if (array->device[sb.this_disk.number] != NULL)
- /* We found multiple devices with the same number. Again,
- this shouldn't happen.*/
- grub_dprintf ("raid", "Found two disks with the number %d?!?",
- sb.this_disk.number);
- }
+ 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;
+
+ /* Do some checks before adding the device to the array. */
+
+ /* 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, but what is the sanest things to do in such
+ a case? */
+ return grub_error (GRUB_ERR_BAD_NUMBER,
+ "array->nr_devs > array->total_devs (%d)?!?",
+ array->total_devs);
+
+ if (array->device[new_array->index] != NULL)
+ /* We found multiple devices with the same number. Again,
+ this shouldn't happen.*/
+ return grub_error (GRUB_ERR_BAD_NUMBER,
+ "Found two disks with the number %d?!?",
+ new_array->number);
+
+ break;
+ }
/* Add an array to the list if we didn't find any. */
if (!array)
{
array = grub_malloc (sizeof (*array));
if (!array)
- return 0;
- grub_memset (array, 0, sizeof (*array));
- array->number = sb.md_minor;
- array->version = sb.major_version;
- array->level = sb.level;
- array->layout = sb.layout;
- array->total_devs = sb.nr_disks;
+ {
+ grub_free (new_array->uuid);
+ return grub_errno;
+ }
+
+ *array = *new_array;
array->nr_devs = 0;
- array->uuid[0] = sb.set_uuid0;
- array->uuid[1] = sb.set_uuid1;
- array->uuid[2] = sb.set_uuid2;
- array->uuid[3] = sb.set_uuid3;
- /* The superblock specifies the size in 1024-byte sectors. */
- array->disk_size = sb.size * 2;
- array->chunk_size = sb.chunk_size / 512;
+ grub_memset (&array->device, 0, sizeof (array->device));
/* Check whether we don't have multiple arrays with the same number. */
for (p = array_list; p != NULL; p = p->next)
- {
- if (p->number == array->number)
- break;
- }
+ {
+ if (p->number == array->number)
+ break;
+ }
if (p)
- {
- /* The number is already in use, so we need to find an new number. */
- int i = 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++;
- }
- }
-
- array->name = grub_malloc (13);
+ {
+ /* The number is already in use, so we need to find an new number. */
+ int i = 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++;
+ }
+ }
+
+ array->name = grub_malloc (grub_strlen (device_name) + 6);
if (! array->name)
- {
- grub_free (array);
+ {
+ grub_free (array->uuid);
+ grub_free (array);
- return 0;
- }
+ return grub_errno;
+ }
- grub_sprintf (array->name, "md%d", array->number);
+ grub_sprintf (array->name, "%s%d", device_name, array->number);
grub_dprintf ("raid", "Found array: %s\n", array->name);
@@ -518,49 +483,85 @@ grub_raid_scan_device (const char *name)
}
/* Add the device to the array. */
- array->device[sb.this_disk.number] = grub_disk_open (name);
+ array->device[new_array->index] = disk;
+ array->nr_devs++;
+
+ return 0;
+}
+
+static int
+grub_raid_scan_device (const char *name)
+{
+ grub_disk_t disk;
+ struct grub_raid_array array;
+ struct grub_raid *p;
+
+ grub_dprintf ("raid", "Scanning for RAID devices\n");
- if (array->disk_size != array->device[sb.this_disk.number]->total_sectors)
+ disk = grub_disk_open (name);
+ if (!disk)
+ return 0;
+
+ if (disk->size_invalid)
{
- if (array->total_devs == 1)
- {
- grub_dprintf ("raid", "Array contains only one disk, but its size (0x%llx) "
- "doesn't match with size indicated by superblock (0x%llx). "
- "Assuming superblock is wrong.\n",
- (unsigned long long) array->device[sb.this_disk.number]->total_sectors,
- (unsigned long long) array->disk_size);
- array->disk_size = array->device[sb.this_disk.number]->total_sectors;
- }
- else if (array->level == 1)
- {
- grub_dprintf ("raid", "Array is RAID level 1, but the size of disk %d (0x%llx) "
- "doesn't match with size indicated by superblock (0x%llx). "
- "Assuming superblock is wrong.\n",
- sb.this_disk.number,
- (unsigned long long) array->device[sb.this_disk.number]->total_sectors,
- (unsigned long long) array->disk_size);
- array->disk_size = array->device[sb.this_disk.number]->total_sectors;
- }
+ grub_disk_close (disk);
+ return 0;
}
- if (! array->device[sb.this_disk.number])
+ for (p = grub_raid_list; p; p = p->next)
{
- /* Remove array from the list if we have just added it. */
- if (array->nr_devs == 0)
- {
- array_list = array->next;
- grub_free (array->name);
- grub_free (array);
- }
+ if (! p->detect (disk, &array))
+ {
+ if (! insert_array (disk, &array, p->name))
+ return 0;
- return 0;
+ break;
+ }
+
+ grub_errno = GRUB_ERR_NONE;
}
- array->nr_devs++;
+ grub_disk_close (disk);
return 0;
}
+static void
+free_array (void)
+{
+ struct grub_raid_array *array;
+
+ array = array_list;
+ while (array)
+ {
+ struct grub_raid_array *p;
+ int i;
+
+ p = array;
+ array = array->next;
+
+ for (i = 0; i < GRUB_RAID_MAX_DEVICES; i++)
+ if (p->device[i])
+ grub_disk_close (p->device[i]);
+
+ grub_free (p->uuid);
+ grub_free (p->name);
+ grub_free (p);
+ }
+
+ array_list = 0;
+}
+
+void
+grub_raid_rescan (void)
+{
+ if (grub_raid_list)
+ {
+ free_array ();
+ grub_device_iterate (&grub_raid_scan_device);
+ }
+}
+
static struct grub_disk_dev grub_raid_dev =
{
.name = "raid",
@@ -579,12 +580,11 @@ static struct grub_disk_dev grub_raid_dev =
GRUB_MOD_INIT(raid)
{
- grub_device_iterate (&grub_raid_scan_device);
grub_disk_dev_register (&grub_raid_dev);
}
GRUB_MOD_FINI(raid)
{
grub_disk_dev_unregister (&grub_raid_dev);
- /* FIXME: free the array list. */
+ free_array ();
}
diff --git a/include/grub/disk.h b/include/grub/disk.h
index 049cc91..758cdda 100644
--- a/include/grub/disk.h
+++ b/include/grub/disk.h
@@ -93,6 +93,9 @@ struct grub_disk
/* The underlying disk device. */
grub_disk_dev_t dev;
+ /* If total_sectors is invalid. */
+ int size_invalid;
+
/* The total number of sectors. */
grub_uint64_t total_sectors;
diff --git a/include/grub/raid.h b/include/grub/raid.h
index 4af97f1..ca2edb7 100644
--- a/include/grub/raid.h
+++ b/include/grub/raid.h
@@ -22,165 +22,43 @@
#include <grub/types.h>
+#define GRUB_RAID_MAX_DEVICES 32
+
struct grub_raid_array
{
int number; /* The device number, taken from md_minor so we
are consistent with the device name in
Linux. */
- int version; /* 0 = 0.90, 1 = 1.0 */
int level; /* RAID levels, only 0, 1 or 5 at the moment. */
int layout; /* Only for RAID 5. */
unsigned int total_devs; /* Total number of devices in the array. */
- unsigned int nr_devs; /* The number of devices we've found so far. */
- grub_size_t chunk_size; /* The size of a chunk, in 512 byte sectors. */
- grub_uint32_t uuid[4]; /* The UUID of the device. */
- char *name; /* That will be "md<number>". */
+ 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. */
- grub_disk_t device[32]; /* Array of total_devs devices. */
+ 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. */
+ grub_disk_t device[GRUB_RAID_MAX_DEVICES]; /* Array of total_devs devices. */
struct grub_raid_array *next;
};
-/* Linux RAID on disk structures and constants,
- copied from include/linux/raid/md_p.h. */
-
-#define GRUB_RAID_RESERVED_BYTES (64 * 1024)
-#define GRUB_RAID_RESERVED_SECTORS (GRUB_RAID_RESERVED_BYTES / 512)
-
-#define GRUB_RAID_NEW_SIZE_SECTORS(x) ((x & ~(GRUB_RAID_RESERVED_SECTORS - 1)) \
- - GRUB_RAID_RESERVED_SECTORS)
-
-#define GRUB_RAID_SB_BYTES 4096
-#define GRUB_RAID_SB_WORDS (GRUB_RAID_SB_BYTES / 4)
-#define GRUB_RAID_SB_SECTORS (GRUB_RAID_SB_BYTES / 512)
-
-/*
- * The following are counted in 32-bit words
- */
-#define GRUB_RAID_SB_GENERIC_OFFSET 0
-
-#define GRUB_RAID_SB_PERSONALITY_OFFSET 64
-#define GRUB_RAID_SB_DISKS_OFFSET 128
-#define GRUB_RAID_SB_DESCRIPTOR_OFFSET 992
-
-#define GRUB_RAID_SB_GENERIC_CONSTANT_WORDS 32
-#define GRUB_RAID_SB_GENERIC_STATE_WORDS 32
-#define GRUB_RAID_SB_GENERIC_WORDS (GRUB_RAID_SB_GENERIC_CONSTANT_WORDS \
- + GRUB_RAID_SB_GENERIC_STATE_WORDS)
-#define GRUB_RAID_SB_PERSONALITY_WORDS 64
-#define GRUB_RAID_SB_DESCRIPTOR_WORDS 32
-#define GRUB_RAID_SB_DISKS 27
-#define GRUB_RAID_SB_DISKS_WORDS (GRUB_RAID_SB_DISKS*GRUB_RAID_SB_DESCRIPTOR_WORDS)
-#define GRUB_RAID_SB_RESERVED_WORDS (1024 - GRUB_RAID_SB_GENERIC_WORDS \
- - GRUB_RAID_SB_PERSONALITY_WORDS \
- - GRUB_RAID_SB_DISKS_WORDS \
- - GRUB_RAID_SB_DESCRIPTOR_WORDS)
-#define GRUB_RAID_SB_EQUAL_WORDS (GRUB_RAID_SB_GENERIC_WORDS \
- + GRUB_RAID_SB_PERSONALITY_WORDS \
- + GRUB_RAID_SB_DISKS_WORDS)
-
-/*
- * Device "operational" state bits
- */
-#define GRUB_RAID_DISK_FAULTY 0 /* disk is faulty / operational */
-#define GRUB_RAID_DISK_ACTIVE 1 /* disk is running or spare disk */
-#define GRUB_RAID_DISK_SYNC 2 /* disk is in sync with the raid set */
-#define GRUB_RAID_DISK_REMOVED 3 /* disk is in sync with the raid set */
-
-#define GRUB_RAID_DISK_WRITEMOSTLY 9 /* disk is "write-mostly" is RAID1 config.
- * read requests will only be sent here in
- * dire need
- */
-
-
-#define GRUB_RAID_SB_MAGIC 0xa92b4efc
-
-/*
- * Superblock state bits
- */
-#define GRUB_RAID_SB_CLEAN 0
-#define GRUB_RAID_SB_ERRORS 1
+struct grub_raid
+{
+ const char *name;
-#define GRUB_RAID_SB_BITMAP_PRESENT 8 /* bitmap may be present nearby */
+ grub_err_t (*detect) (grub_disk_t disk, struct grub_raid_array *array);
-struct grub_raid_disk_09 {
- grub_uint32_t number; /* 0 Device number in the entire set */
- grub_uint32_t major; /* 1 Device major number */
- grub_uint32_t minor; /* 2 Device minor number */
- grub_uint32_t raid_disk; /* 3 The role of the device in the raid set */
- grub_uint32_t state; /* 4 Operational state */
- grub_uint32_t reserved[GRUB_RAID_SB_DESCRIPTOR_WORDS - 5];
+ struct grub_raid *next;
};
+typedef struct grub_raid *grub_raid_t;
-struct grub_raid_super_09 {
- /*
- * Constant generic information
- */
- grub_uint32_t md_magic; /* 0 MD identifier */
- grub_uint32_t major_version; /* 1 major version to which the set conforms */
- grub_uint32_t minor_version; /* 2 minor version ... */
- grub_uint32_t patch_version; /* 3 patchlevel version ... */
- grub_uint32_t gvalid_words; /* 4 Number of used words in this section */
- grub_uint32_t set_uuid0; /* 5 Raid set identifier */
- grub_uint32_t ctime; /* 6 Creation time */
- grub_uint32_t level; /* 7 Raid personality */
- grub_uint32_t size; /* 8 Apparent size of each individual disk */
- grub_uint32_t nr_disks; /* 9 total disks in the raid set */
- grub_uint32_t raid_disks; /* 10 disks in a fully functional raid set */
- grub_uint32_t md_minor; /* 11 preferred MD minor device number */
- grub_uint32_t not_persistent; /* 12 does it have a persistent superblock */
- grub_uint32_t set_uuid1; /* 13 Raid set identifier #2 */
- grub_uint32_t set_uuid2; /* 14 Raid set identifier #3 */
- grub_uint32_t set_uuid3; /* 15 Raid set identifier #4 */
- grub_uint32_t gstate_creserved[GRUB_RAID_SB_GENERIC_CONSTANT_WORDS - 16];
-
- /*
- * Generic state information
- */
- grub_uint32_t utime; /* 0 Superblock update time */
- grub_uint32_t state; /* 1 State bits (clean, ...) */
- grub_uint32_t active_disks; /* 2 Number of currently active disks */
- grub_uint32_t working_disks; /* 3 Number of working disks */
- grub_uint32_t failed_disks; /* 4 Number of failed disks */
- grub_uint32_t spare_disks; /* 5 Number of spare disks */
- grub_uint32_t sb_csum; /* 6 checksum of the whole superblock */
-#ifdef GRUB_HOST_WORDS_BIGENDIAN
- grub_uint32_t events_hi; /* 7 high-order of superblock update count */
- grub_uint32_t events_lo; /* 8 low-order of superblock update count */
- grub_uint32_t cp_events_hi; /* 9 high-order of checkpoint update count */
- grub_uint32_t cp_events_lo; /* 10 low-order of checkpoint update count */
-#else
- grub_uint32_t events_lo; /* 7 low-order of superblock update count */
- grub_uint32_t events_hi; /* 8 high-order of superblock update count */
- grub_uint32_t cp_events_lo; /* 9 low-order of checkpoint update count */
- grub_uint32_t cp_events_hi; /* 10 high-order of checkpoint update count */
-#endif
- grub_uint32_t recovery_cp; /* 11 recovery checkpoint sector count */
- grub_uint32_t gstate_sreserved[GRUB_RAID_SB_GENERIC_STATE_WORDS - 12];
-
- /*
- * Personality information
- */
- grub_uint32_t layout; /* 0 the array's physical layout */
- grub_uint32_t chunk_size; /* 1 chunk size in bytes */
- grub_uint32_t root_pv; /* 2 LV root PV */
- grub_uint32_t root_block; /* 3 LV root block */
- grub_uint32_t pstate_reserved[GRUB_RAID_SB_PERSONALITY_WORDS - 4];
+void grub_raid_register (grub_raid_t raid);
+void grub_raid_unregister (grub_raid_t raid);
- /*
- * Disks information
- */
- struct grub_raid_disk_09 disks[GRUB_RAID_SB_DISKS];
-
- /*
- * Reserved
- */
- grub_uint32_t reserved[GRUB_RAID_SB_RESERVED_WORDS];
-
- /*
- * Active descriptor
- */
- struct grub_raid_disk_09 this_disk;
-};
+void grub_raid_rescan (void);
#endif /* ! GRUB_RAID_H */
diff --git a/kern/disk.c b/kern/disk.c
index ed82506..804ba5f 100644
--- a/kern/disk.c
+++ b/kern/disk.c
@@ -227,6 +227,7 @@ grub_disk_open (const char *name)
disk->read_hook = 0;
disk->partition = 0;
disk->data = 0;
+ disk->size_invalid = 0;
disk->name = grub_strdup (name);
if (! disk->name)
goto fail;
diff --git a/util/grub-fstest.c b/util/grub-fstest.c
index 35af6a5..29234ac 100644
--- a/util/grub-fstest.c
+++ b/util/grub-fstest.c
@@ -29,6 +29,7 @@
#include <grub/term.h>
#include <grub/mm.h>
#include <grub/normal.h>
+#include <grub/raid.h>
#include <grub/lib/hexdump.h>
#include <grub_fstest_init.h>
@@ -141,7 +142,6 @@ grub_unregister_command (const char *name __attribute__ ((unused)))
#define BUF_SIZE 32256
static grub_off_t skip, leng;
-static char *part;
static void
read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len))
@@ -273,32 +273,61 @@ cmd_hex (char *pathname)
return 0;
}
- read_file (pathname, hex_hook);
+ if (pathname)
+ read_file (pathname, hex_hook);
+ else
+ {
+ char buf[BUF_SIZE];
+ grub_device_t dev;
+
+ dev = grub_device_open (0);
+ if ((! dev) || (! dev->disk))
+ grub_util_error ("Can\'t open device");
+
+ if (! leng)
+ leng = GRUB_DISK_SECTOR_SIZE;
+
+ while (leng)
+ {
+ grub_size_t len;
+
+ len = (leng > BUF_SIZE) ? BUF_SIZE : leng;
+
+ if (grub_disk_read (dev->disk, 0, skip, len, buf))
+ grub_util_error ("Disk read fails at offset %lld, length %d\n",
+ skip, len);
+
+ hexdump (skip, buf, len);
+
+ skip += len;
+ leng -= len;
+ }
+
+ grub_device_close (dev);
+ }
}
static void
-fstest (char *image_path, int cmd, int n, char **args)
+fstest (char **images, int num_disks, int cmd, int n, char **args)
{
- char host_file[7 + grub_strlen (image_path) + 1];
- char device_name[(part) ? (6 + grub_strlen (part)) : 5];
- char *argv[3] = { "-p", "loop", host_file };
-
-
- grub_sprintf (host_file, "(host)/%s", image_path);
+ char host_file[128];
+ char loop_name[8];
+ char *argv[3] = { "-p", loop_name, host_file};
+ int i;
- if (execute_command (&cmd_loopback, 3, argv))
+ for (i = 0; i < num_disks; i++)
{
- grub_util_error ("loopback command fails.\n");
- goto fail;
- }
+ if (grub_strlen (images[i]) + 7 > sizeof (host_file))
+ grub_util_error ("Pathname %s too long", images[i]);
- if (part)
- grub_sprintf (device_name, "loop,%s", part);
- else
- grub_strcpy (device_name, "loop");
+ grub_sprintf (loop_name, "loop%d", i);
+ grub_sprintf (host_file, "(host)%s", images[i]);
- grub_env_set ("root", device_name);
+ if (execute_command (&cmd_loopback, 3, argv))
+ grub_util_error ("loopback command fails.\n");
+ }
+ grub_raid_rescan ();
switch (cmd)
{
case CMD_LS:
@@ -311,31 +340,31 @@ fstest (char *image_path, int cmd, int n, char **args)
cmd_cmp (args[0], args[1]);
break;
case CMD_HEX:
- cmd_hex (args[0]);
+ cmd_hex ((n == 0) ? 0 : args[0]);
break;
case CMD_BLOCKLIST:
execute_command (&cmd_blocklist, n, args);
grub_printf ("\n");
}
-fail:
-
argv[0] = "-d";
- execute_command (&cmd_loopback, 2, argv);
+ for (i = 0; i < num_disks; i++)
+ {
+ grub_sprintf (loop_name, "loop%d", i);
+ execute_command (&cmd_loopback, 2, argv);
+ }
}
static struct option options[] = {
- {"part", required_argument, 0, 'p'},
+ {"root", required_argument, 0, 'r'},
{"skip", required_argument, 0, 's'},
{"length", required_argument, 0, 'n'},
+ {"diskcount", required_argument, 0, 'c'},
{"debug", required_argument, 0, 'd'},
- {"raw", no_argument, 0, 'r'},
- {"long", no_argument, 0, 'l'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{"verbose", no_argument, 0, 'v'},
-
{0, 0, 0, 0}
};
@@ -353,15 +382,14 @@ Debug tool for filesystem driver.\n\
ls PATH list files in PATH\n\
cp SRC DEST copy file to local system\n\
cmp SRC DEST compare files\n\
- hex FILE hex dump FILE\n\
+ hex [FILE] Hex dump FILE\n\
blocklist FILE display blocklist of FILE\n\
\nOptions:\n\
- -p, --part=NUM select partition NUM\n\
+ -r, --root=DEVICE_NAME set root device\n\
-s, --skip=N skip N bytes from output file\n\
-n, --length=N handle N bytes in output file\n\
+ -c, --diskcount=N N input files\n\
-d, --debug=S Set debug environment variable\n\
- -r, --raw disable auto decompression\n\
- -l, --long show long directory list\n\
-h, --help display this message and exit\n\
-V, --version print version information and exit\n\
-v, --verbose print verbose messages\n\
@@ -374,45 +402,66 @@ Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
int
main (int argc, char *argv[])
{
- char *image_path, *debug_str = 0;
- int cmd, is_raw = 0, is_long = 0;
+ char *debug_str = 0, *root = 0, *default_root, *alloc_root;
+ int i, cmd, num_opts, image_index, num_disks = 1;
progname = "grub-fstest";
+ /* Find the first non option entry. */
+ for (num_opts = 1; num_opts < argc; num_opts++)
+ if (argv[num_opts][0] == '-')
+ {
+ if ((argv[num_opts][2] == 0) && (num_opts < argc - 1) &&
+ ((argv[num_opts][1] == 'r') ||
+ (argv[num_opts][1] == 's') ||
+ (argv[num_opts][1] == 'n') ||
+ (argv[num_opts][1] == 'c') ||
+ (argv[num_opts][1] == 'd')))
+ num_opts++;
+ }
+ else
+ break;
+
/* Check for options. */
while (1)
{
- int c = getopt_long (argc, argv, "p:s:n:d:rlhVv", options, 0);
+ int c = getopt_long (num_opts, argv, "r:s:n:c:d:hVv", options, 0);
+ char *p;
if (c == -1)
break;
else
switch (c)
{
- case 'p':
- part = optarg;
+ case 'r':
+ root = optarg;
break;
case 's':
- skip = grub_strtoul (optarg, NULL, 0);
+ skip = grub_strtoul (optarg, &p, 0);
+ if (*p == 's')
+ skip <<= GRUB_DISK_SECTOR_BITS;
break;
case 'n':
- leng = grub_strtoul (optarg, NULL, 0);
+ leng = grub_strtoul (optarg, &p, 0);
+ if (*p == 's')
+ leng <<= GRUB_DISK_SECTOR_BITS;
break;
+ case 'c':
+ num_disks = grub_strtoul (optarg, NULL, 0);
+ if (num_disks < 1)
+ {
+ fprintf (stderr, "Invalid disk count.\n");
+ usage (1);
+ }
+ break;
+
case 'd':
debug_str = optarg;
break;
- case 'r':
- is_raw = 1;
- break;
-
- case 'l':
- is_long = 1;
- break;
-
case 'h':
usage (0);
break;
@@ -432,35 +481,29 @@ main (int argc, char *argv[])
}
/* Obtain PATH. */
- if (optind >= argc)
- {
- fprintf (stderr, "No path is specified.\n");
- usage (1);
- }
-
- image_path = argv[optind];
-
- if (*image_path != '/')
+ if (optind + num_disks - 1 >= argc)
{
- fprintf (stderr, "Must use absolute path.\n");
+ fprintf (stderr, "Not enough pathname.\n");
usage (1);
}
- optind++;
+ image_index = optind;
+ for (i = 0; i < num_disks; i++, optind++)
+ if (argv[optind][0] != '/')
+ {
+ fprintf (stderr, "Must use absolute path.\n");
+ usage (1);
+ }
cmd = 0;
if (optind < argc)
{
- int nparm = 1;
+ int nparm = 0;
if (!grub_strcmp (argv[optind], "ls"))
- {
- cmd = CMD_LS;
- if (is_long)
- argv[optind--] = "-l";
- else
- nparm = 0;
- }
+ {
+ cmd = CMD_LS;
+ }
else if (!grub_strcmp (argv[optind], "cp"))
{
cmd = CMD_CP;
@@ -478,6 +521,7 @@ main (int argc, char *argv[])
else if (!grub_strcmp (argv[optind], "blocklist"))
{
cmd = CMD_BLOCKLIST;
+ nparm = 1;
}
else
{
@@ -503,14 +547,31 @@ main (int argc, char *argv[])
/* Initialize all modules. */
grub_init_all ();
- if (is_raw)
- grub_env_set ("filehook", "0");
-
if (debug_str)
grub_env_set ("debug", debug_str);
+ default_root = (num_disks == 1) ? "loop0" : "md0";
+ alloc_root = 0;
+ if (root)
+ {
+ if ((*root >= '0') && (*root <= '9'))
+ {
+ alloc_root = xmalloc (strlen (default_root) + strlen (root) + 2);
+
+ sprintf (alloc_root, "%s,%s", default_root, root);
+ root = alloc_root;
+ }
+ }
+ else
+ root = default_root;
+
+ grub_env_set ("root", root);
+
+ if (alloc_root)
+ free (alloc_root);
+
/* Do it. */
- fstest (image_path + 1, cmd, argc - optind, argv + optind);
+ fstest (argv + image_index, num_disks, cmd, argc - optind, argv + optind);
/* Free resources. */
grub_fini_all ();
_______________________________________________
Grub-devel mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/grub-devel