All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marco Gerards <mgerards@xs4all.nl>
To: The development of GRUB 2 <grub-devel@gnu.org>
Subject: Re: [PATCH] Split of raid scan code
Date: Wed, 13 Aug 2008 12:05:19 +0200	[thread overview]
Message-ID: <87skt99qn4.fsf@xs4all.nl> (raw)
In-Reply-To: <ca0f59980808120449s61abd11iefb197cd3b1672d5@mail.gmail.com> (bean123ch@gmail.com's message of "Tue, 12 Aug 2008 19:49:19 +0800")

Bean <bean123ch@gmail.com> writes:

> On Tue, Aug 12, 2008 at 4:30 AM, Robert Millan <rmh@aybabtu.com> wrote:
>> On Tue, Aug 12, 2008 at 04:24:26AM +0800, Bean wrote:
>>> -     disk/lvm.c disk/raid.c grub_probe_init.c
>>> +     disk/lvm.c disk/raid.c disk/mdraid_linux.c grub_probe_init.c
>>
>> Hi,
>>
>> I haven't tried, but I think this module split would break grub-install &
>> update-grub.  Please check those out before committing!
>
> Hi,
>
> Ok, I make some adjustment, now grub-install & update-grub works for
> raid device.

Great

> If no one objects, I'd commit this soon.
>
> 2008-08-12  Bean  <bean123ch@gmail.com>
>
> 	* conf/common.rmk (grub_probe_SOURCES): Add disk/mdraid_linux.c.
> 	(grub_fstest_SOURCES): Add disk/mdraid_linux.c and disk/dmraid_nvidia.c.
> 	(pkglib_MODULES): Add mdraid.mod and dm_nv.mod.
> 	(mdraid_mod_SOURCES): New macro.
> 	(mdraid_mod_CFLAGS): Likewise.
> 	(mdraid_mod_LDFLAGS): Likewise.
> 	(dm_nv_mod_SOURCES): Likewise.
> 	(dm_nv_mod_CFLAGS): Likewise.
> 	(dm_nv_mod_LDFLAGS): Likewise.
>
> 	* conf/i386-pc.rmk (grub_setup_SOURCES): Add disk/mdraid_linux.c.
> 	(grub_emu_SOURCES):  Add disk/mdraid_linux.c and disk/dmraid_nvidia.c.
>
> 	* conf/i386-coreboot.rmk (grub_emu_SOURCES): Add disk/mdraid_linux.c
> 	and disk/dmraid_nvidia.c.
>
> 	* conf/i386-efi.rmk (grub_emu_SOURCES): Likewise.
>
> 	* conf/x86_64-efi.rmk (grub_emu_SOURCES): Likewise.
>
> 	* conf/i386-ieee1275.rmk (grub_emu_SOURCES): Likewise.
>
> 	* conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): Likewise.
>
> 	* disk/mdraid_linux.c: New file.
>
> 	* disk/dmraid_nvidia.c: New file.
>
> 	* disk/i386/pc/biosdisk.c: Set total_sectors of cdrom device to
> 	ULONG_MAX.

For which function?

> 	* disk/raid.c (grub_raid_open): Calculate total_sectors of raid0
> 	by adding the size of individual disk (they can have different size).
> 	(grub_raid_read): Simply raid0 code, also fix a serious bug.
> 	(grub_raid_scan_device): Remove code specific to mdraid.
> 	(grub_raid_list): New variable.
> 	(free_array): New function.
> 	(grub_raid_register): Likewise.
> 	(grub_raid_unregister): Likewise.
> 	(grub_raid_rescan): Likewise.
> 	(GRUB_MOD_INIT): Don't iterate device here.
> 	(GRUB_MOD_FINI): Use free_array to release resource.
>
> 	* include/grub/raid.h: Remove macro and structure specific to mdraid.
>
> 	* util/grub-fstest.c: Add #include <grub/raid.h>.
> 	(part): Removed.
> 	(cmd_hex): Handle partition as well.
> 	(fstest): Handle multiple disks.
> 	(options): Remove part, raw and long, add root and diskcount.
> 	(usage): Change hex, remove -p, -r, -l, add -r and -c.
> 	(main): Find the first non option entry and ignore subsequence options,
> 	add handling for the new options, support multiple disks.
>
> 	* util/grub-probe.c (probe): Add mdraid to abstraction_name.
>
> -- 
> Bean
>
> diff --git a/conf/common.rmk b/conf/common.rmk
> index 95859f7..3876ce4 100644
> --- a/conf/common.rmk
> +++ b/conf/common.rmk
> @@ -15,7 +15,7 @@ grub_probe_SOURCES = util/grub-probe.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 grub_probe_init.c
> +	disk/lvm.c disk/raid.c disk/mdraid_linux.c grub_probe_init.c
>  
>  ifeq ($(enable_grub_fstest), yes)
>  bin_UTILITIES += grub-fstest
> @@ -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_linux.c disk/dmraid_nvidia.c \
>  	grub_fstest_init.c
>  
>  # For the parser.
> @@ -264,7 +265,7 @@ gpt_mod_LDFLAGS = $(COMMON_LDFLAGS)
>  
>  # Special disk structures
>  
> -pkglib_MODULES += raid.mod lvm.mod
> +pkglib_MODULES += raid.mod lvm.mod mdraid.mod dm_nv.mod
>  
>  # For raid.mod
>  raid_mod_SOURCES = disk/raid.c
> @@ -276,6 +277,16 @@ lvm_mod_SOURCES = disk/lvm.c
>  lvm_mod_CFLAGS = $(COMMON_CFLAGS)
>  lvm_mod_LDFLAGS = $(COMMON_LDFLAGS)
>  
> +# For mdraid.mod
> +mdraid_mod_SOURCES = disk/mdraid_linux.c
> +mdraid_mod_CFLAGS = $(COMMON_CFLAGS)
> +mdraid_mod_LDFLAGS = $(COMMON_LDFLAGS)
> +
> +# For dm_nv.mod
> +dm_nv_mod_SOURCES = disk/dmraid_nvidia.c
> +dm_nv_mod_CFLAGS = $(COMMON_CFLAGS)
> +dm_nv_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/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk
> index 606b99c..74808ca 100644
> --- a/conf/i386-coreboot.rmk
> +++ b/conf/i386-coreboot.rmk
> @@ -92,7 +92,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c	\
>  	util/biosdisk.c util/getroot.c					\
>  	util/i386/pc/misc.c 						\
>  	\
> -	disk/raid.c disk/lvm.c						\
> +	disk/raid.c disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c	\
>  	grub_emu_init.c
>  
>  grub_emu_LDFLAGS = $(LIBCURSES)
> diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk
> index 2ce21b1..705e4ef 100644
> --- a/conf/i386-efi.rmk
> +++ b/conf/i386-efi.rmk
> @@ -62,7 +62,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c 	\
>  	util/biosdisk.c util/getroot.c					\
>  	util/i386/pc/misc.c						\
>  	\
> -	disk/raid.c disk/lvm.c						\
> +	disk/raid.c disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c	\
>  	grub_emu_init.c
>  
>  grub_emu_LDFLAGS = $(LIBCURSES)
> diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk
> index a93845e..e996865 100644
> --- a/conf/i386-ieee1275.rmk
> +++ b/conf/i386-ieee1275.rmk
> @@ -90,7 +90,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c	\
>  	util/biosdisk.c util/getroot.c					\
>  	util/i386/pc/misc.c						\
>  	\
> -	disk/raid.c disk/lvm.c						\
> +	disk/raid.c disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c	\
>  	grub_emu_init.c
>  
>  grub_emu_LDFLAGS = $(LIBCURSES)
> diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
> index c1e4ac4..f3142e4 100644
> --- a/conf/i386-pc.rmk
> +++ b/conf/i386-pc.rmk
> @@ -102,7 +102,7 @@ grub_setup_SOURCES = util/i386/pc/grub-setup.c util/biosdisk.c	\
>  	\
>  	partmap/pc.c partmap/gpt.c				\
>  	\
> -	disk/raid.c disk/lvm.c					\
> +	disk/raid.c disk/mdraid_linux.c disk/lvm.c		\
>  	util/raid.c util/lvm.c					\
>  	grub_setup_init.c
>  
> @@ -142,7 +142,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c	\
>  	util/biosdisk.c util/getroot.c					\
>  	util/i386/pc/misc.c						\
>  	\
> -	disk/raid.c disk/lvm.c						\
> +	disk/raid.c disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c	\
>  	grub_emu_init.c
>  
>  grub_emu_LDFLAGS = $(LIBCURSES)
> diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk
> index 0ed75f3..15e2fae 100644
> --- a/conf/powerpc-ieee1275.rmk
> +++ b/conf/powerpc-ieee1275.rmk
> @@ -73,7 +73,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c 	\
>  	util/biosdisk.c util/getroot.c					\
>  	util/powerpc/ieee1275/misc.c					\
>  	\
> -	disk/raid.c disk/lvm.c						\
> +	disk/raid.c disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c	\
>  	grub_script.tab.c grub_emu_init.c
>  
>  grub_emu_LDFLAGS = $(LIBCURSES)
> diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk
> index 4f8abba..8553226 100644
> --- a/conf/x86_64-efi.rmk
> +++ b/conf/x86_64-efi.rmk
> @@ -64,7 +64,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c 	\
>  	util/biosdisk.c util/getroot.c					\
>  	util/i386/pc/misc.c						\
>  	\
> -	disk/raid.c disk/lvm.c						\
> +	disk/raid.c disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c	\
>  	grub_emu_init.c
>  
>  grub_emu_LDFLAGS = $(LIBCURSES)
> diff --git a/disk/dmraid_nvidia.c b/disk/dmraid_nvidia.c
> new file mode 100644
> index 0000000..82eb26a
> --- /dev/null
> +++ b/disk/dmraid_nvidia.c
> @@ -0,0 +1,165 @@
> +/* dmraid_nvidia.c - module to handle Nvidia fakeraid.  */
> +/*
> + *  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>
> +
> +#define NV_SIGNATURES		4
> +
> +#define NV_IDLE			0
> +#define NV_SCDB_INIT_RAID	2
> +#define NV_SCDB_REBUILD_RAID	3
> +#define NV_SCDB_UPGRADE_RAID	4
> +#define NV_SCDB_SYNC_RAID	5
> +
> +#define NV_LEVEL_UNKNOWN	0x00
> +#define NV_LEVEL_JBOD		0xFF
> +#define NV_LEVEL_0		0x80
> +#define NV_LEVEL_1		0x81
> +#define NV_LEVEL_3		0x83
> +#define NV_LEVEL_5		0x85
> +#define NV_LEVEL_10		0x8a
> +#define NV_LEVEL_1_0		0x8180
> +
> +#define NV_ARRAY_FLAG_BOOT		1 /* BIOS use only.  */
> +#define NV_ARRAY_FLAG_ERROR		2 /* Degraded or offling.  */
> +#define NV_ARRAY_FLAG_PARITY_VALID	4 /* RAID-3/5 parity valid.  */
> +
> +struct grub_raid_nv_array
> +{
> +  grub_uint32_t version;
> +  grub_uint32_t signature[NV_SIGNATURES];
> +  grub_uint8_t raid_job_code;
> +  grub_uint8_t stripe_width;
> +  grub_uint8_t total_volumes;
> +  grub_uint8_t original_width;
> +  grub_uint32_t raid_level;
> +  grub_uint32_t stripe_block_size;
> +  grub_uint32_t stripe_block_size_bytes;
> +  grub_uint32_t stripe_block_size_log2;
> +  grub_uint32_t stripe_mask;
> +  grub_uint32_t stripe_size;
> +  grub_uint32_t stripe_size_bytes;
> +  grub_uint32_t raid_job_mask;
> +  grub_uint32_t original_capacity;
> +  grub_uint32_t flags;
> +};
> +
> +#define NV_ID_LENGTH		8
> +#define NV_ID_STRING		"NVIDIA"
> +#define NV_VERSION		100
> +
> +#define	NV_PRODUCTIDS		16
> +#define	NV_PRODUCTREVISIONS	4
> +
> +struct grub_raid_nv_super
> +{
> +  grub_uint8_t vendor[NV_ID_LENGTH]; /* 0x00 - 0x07 ID string.  */
> +  grub_uint32_t size;		/* 0x08 - 0x0B Size of metadata in dwords.  */
> +  grub_uint32_t chksum;		/* 0x0C - 0x0F Checksum of this struct.  */
> +  grub_uint16_t version;	/* 0x10 - 0x11 NV version.  */
> +  grub_uint8_t unit_number;	/* 0x12 Disk index in array.  */
> +  grub_uint8_t reserved;	/* 0x13.  */
> +  grub_uint32_t capacity;	/* 0x14 - 0x17 Array capacity in sectors.  */
> +  grub_uint32_t sector_size;	/* 0x18 - 0x1B Sector size.  */
> +  grub_uint8_t product_id[NV_PRODUCTIDS]; /* 0x1C - 0x2B Array product ID.  */
> +  grub_uint8_t product_rev[NV_PRODUCTREVISIONS]; /* 0x2C - 0x2F Array product revision */
> +  grub_uint32_t unit_flags;	/* 0x30 - 0x33 Flags for this disk */
> +  struct grub_raid_nv_array array; /* Array information */
> +} __attribute__ ((packed));


These lines get very long (too long?).  In general I prefer comments
on the line before the code.

> +static grub_err_t
> +grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array)
> +{
> +  grub_disk_addr_t sector;
> +  struct grub_raid_nv_super sb;
> +  grub_uint32_t *uuid;
> +
> +  if (disk->partition)
> +    return grub_error (GRUB_ERR_OUT_OF_RANGE, "skip partition");
> +
> +  sector = grub_disk_get_size (disk) - 2;
> +
> +  if (grub_disk_read (disk, sector, 0, sizeof (sb), (char *) &sb))
> +    return grub_errno;
> +
> +  if (grub_memcmp (sb.vendor, NV_ID_STRING, 6))
> +    return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
> +
> +  if (sb.version != NV_VERSION)
> +    return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
> +                       "Unknown version: %d.%d", sb.version);
> +
> +  switch (sb.array.raid_level)
> +    {
> +    case NV_LEVEL_0:
> +      array->level = 0;
> +      array->disk_size = sb.capacity / sb.array.total_volumes;
> +      break;
> +
> +    case NV_LEVEL_1:
> +      array->level = 1;
> +      array->disk_size = sb.capacity;
> +      break;
> +
> +    case NV_LEVEL_5:
> +      array->level = 5;
> +      array->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);
> +    }
> +
> +  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,
> +               sizeof (sb.array.signature));
> +
> +  return 0;
> +}
> +
> +static struct grub_raid grub_dmraid_nv_dev =
> +{
> +  .name = "dmraid_nv",
> +  .detect = grub_dmraid_nv_detect,
> +  .next = 0
> +};
> +
> +GRUB_MOD_INIT(dm_nv)
> +{
> +  grub_raid_register (&grub_dmraid_nv_dev);
> +}
> +
> +GRUB_MOD_FINI(dm_nv)
> +{
> +  grub_raid_register (&grub_dmraid_nv_dev);
> +}
> diff --git a/disk/i386/pc/biosdisk.c b/disk/i386/pc/biosdisk.c
> index c8fd142..8b7f5ed 100644
> --- a/disk/i386/pc/biosdisk.c
> +++ b/disk/i386/pc/biosdisk.c
> @@ -120,7 +120,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.  */
> +      total_sectors = ULONG_MAX;  /* TODO: get the correct size.  */

You are cheating here! :-)

>    else if (drive & 0x80)
>      {
> diff --git a/disk/mdraid_linux.c b/disk/mdraid_linux.c
> new file mode 100644
> index 0000000..c77f2e2
> --- /dev/null
> +++ b/disk/mdraid_linux.c
> @@ -0,0 +1,243 @@
> +/* mdraid_linux.c - module to handle linux softraid.  */
> +/*
> + *  GRUB  --  GRand Unified Bootloader
> + *  Copyright (C) 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)


The lines above are way too long

> +/*
> + * 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
> +					   */

Can you correctly format comments?  Placing the comments before the
#define makes the lines shorter.  Perhaps they are too long (I didn't check)

The same applies for code below


> +
> +#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

Why?  We have macros for this :-)

> +  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
> +   */

/* Disks information.  */

> +  struct grub_raid_disk_09 disks[GRUB_RAID_SB_DISKS];
> +
> +  /*
> +   * Reserved
> +   */

/* Reserved.  */

(I do not like this comment style)

> +  grub_uint32_t reserved[GRUB_RAID_SB_RESERVED_WORDS];
> +
> +  /*
> +   * Active descriptor
> +   */

Same here.

> +  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_OUT_OF_RANGE, "not raid");

It looks like the comment is misaligned.

> +  /* 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->total_devs = sb.nr_disks;
> +  array->disk_size = (sb.size) ? sb.size * 2 : sector;
> +  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 = "mdraid",
> +  .detect = grub_mdraid_detect,
> +  .next = 0
> +};
> +
> +GRUB_MOD_INIT(mdraid)
> +{
> +  grub_raid_register (&grub_mdraid_dev);
> +}
> +
> +GRUB_MOD_FINI(mdraid)
> +{
> +  grub_raid_register (&grub_mdraid_dev);
> +}
> diff --git a/disk/raid.c b/disk/raid.c
> index 731bf1f..3333f4b 100644
> --- a/disk/raid.c
> +++ b/disk/raid.c
> @@ -112,9 +112,15 @@ grub_raid_open (const char *name, grub_disk_t disk)
>    switch (array->level)
>      {
>      case 0:
> -      /* FIXME: RAID0 disks can have different sizes! */
> -      disk->total_sectors = array->total_devs * array->disk_size;
> -      break;
> +      {
> +        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:
>        disk->total_sectors = array->disk_size;
> @@ -152,56 +158,39 @@ grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector,
>  	grub_uint32_t b;
>  	unsigned int disknr;
>  	grub_disk_addr_t read_sector;
> -	grub_size_t read_size;
>  
>  	/* Find the first sector to read. */
> -	a = grub_divmod64 (sector, array->chunk_size, NULL);
> -	grub_divmod64 (a, array->total_devs, &disknr);
> -
> -	a = grub_divmod64 (sector, array->chunk_size * array->total_devs, NULL);
> -	grub_divmod64 (sector, array->chunk_size, &b);
> -	read_sector = a * array->chunk_size + b;
> -
> -	grub_divmod64 (read_sector, array->chunk_size, &b);
> -	read_size = array->chunk_size - b;
> -	
> -	if (read_size > size)
> -	  read_size = size;
> +	a = grub_divmod64 (sector, array->chunk_size, &b);
> +	a = grub_divmod64 (a, array->total_devs, &disknr);
> +	read_sector = a * array->chunk_size;
>  	
>  	while (1)
>  	  {
> -	    grub_uint32_t i;
> +            grub_size_t read_size;
>  
> -	    err = grub_disk_read (array->device[disknr], read_sector, 0,
> +            read_size = array->chunk_size - b;
> +            if (read_size > size)
> +              read_size = size;
> +
> +	    err = grub_disk_read (array->device[disknr], read_sector + b, 0,
>  				  read_size << GRUB_DISK_SECTOR_BITS, buf);
>  	    if (err)
>  	      break;
>  
> -	    buf += read_size;
> +	    buf += read_size << GRUB_DISK_SECTOR_BITS;
>  	    size -= read_size;
>  	    if (! size)
>  	      break;
>  
> -	    if (size > array->chunk_size)
> -	      read_size = array->chunk_size;
> -	    else
> -	      read_size = size;
> -
> -	    /* Check whether the sector was aligned on a chunk size
> -	       boundary. If this isn't the case, it's the first read
> -	       and the next read should be set back to start of the
> -	       boundary.  */
> -	    grub_divmod64 (read_sector, array->chunk_size, &i);
> -	    read_sector -= i;
> -
> +            b = 0;
>  	    disknr++;
>  	    /* See whether the disk was the last disk, and start
>  	       reading from the first disk in that case. */
>  	    if (disknr == array->total_devs)
> -	      {
> -		disknr = 0;
> -		read_sector += array->chunk_size;
> -	      }
> +              {
> +                read_sector += array->chunk_size;
> +                disknr = 0;
> +              }
>  	  }
>        }
>        break;
> @@ -348,169 +337,103 @@ grub_raid_write (grub_disk_t disk __attribute ((unused)),
>    return GRUB_ERR_NOT_IMPLEMENTED_YET;
>  }
>  
> -static int
> -grub_raid_scan_device (const char *name)
> +static grub_err_t
> +insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
> +              const char *scanner_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);
> -
> -  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;
> -    }
> -
> -  /* FIXME: Check the checksum. */
> -
> -  /* 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;
> -    }
> -
> -  /* 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;
> -    }
> +  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++;
> -	    }
> -	}
> +        {
> +          /* 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);
>        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_dprintf ("raid", "Found array: %s\n", array->name);
> +      grub_dprintf ("raid", "Found array %s (%s)\n", array->name,
> +                    scanner_name);
>  
>        /* Add our new array to the list.  */
>        array->next = array_list;
> @@ -518,47 +441,117 @@ 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++;
>  
> -  if (array->disk_size != array->device[sb.this_disk.number]->total_sectors)
> +  return 0;
> +}
> +
> +
> +static grub_raid_t grub_raid_list;
> +
> +static void
> +grub_raid_scan_device (int head_only)
> +{
> +  auto int hook (const char *name);
> +  int hook (const char *name)
>      {
> -      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_t disk;
> +      struct grub_raid_array array;
> +      struct grub_raid *p;
> +
> +      grub_dprintf ("raid", "Scanning for RAID devices\n");
> +
> +      disk = grub_disk_open (name);
> +      if (!disk)
> +        return 0;
> +
> +      if (disk->total_sectors == ULONG_MAX)

Urgh, can you do this cleaner?

Actually, why do you do this?

> +        {
> +          grub_disk_close (disk);
> +          return 0;
> +        }
> +
> +      for (p = grub_raid_list; p; p = p->next)
> +        {
> +          if (! p->detect (disk, &array))
> +            {
> +              if (! insert_array (disk, &array, p->name))
> +                return 0;
> +
> +              break;
> +            }
> +
> +          /* 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;
> +          if (head_only)
> +            break;
> +        }
> +
> +      grub_disk_close (disk);
> +
> +      return 0;
>      }
>    
> -  if (! array->device[sb.this_disk.number])
> +  grub_device_iterate (&hook);
> +}
> +
> +static void
> +free_array (void)
> +{
> +  struct grub_raid_array *array;
> +
> +  array = array_list;
> +  while (array)
>      {
> -      /* 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);
> -	}
> +      struct grub_raid_array *p;
> +      int i;
>  	  
> -      return 0;
> +      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->nr_devs++;
> +  array_list = 0;
> +}
>    
> -  return 0;
> +void
> +grub_raid_register (grub_raid_t raid)
> +{
> +  raid->next = grub_raid_list;
> +  grub_raid_list = raid;
> +  grub_raid_scan_device (1);
> +}
> +
> +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;
> +      }
> +}
> +
> +void
> +grub_raid_rescan (void)
> +{
> +  free_array ();
> +  grub_raid_scan_device (0);
>  }
>  
>  static struct grub_disk_dev grub_raid_dev =
> @@ -579,12 +572,11 @@ static struct grub_disk_dev grub_raid_dev =
>  \f
>  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/raid.h b/include/grub/raid.h
> index 4af97f1..0920f0f 100644
> --- a/include/grub/raid.h
> +++ b/include/grub/raid.h
> @@ -22,165 +22,42 @@
>  
>  #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/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 ();
> diff --git a/util/grub-probe.c b/util/grub-probe.c
> index a4f51e2..ce9cbff 100644
> --- a/util/grub-probe.c
> +++ b/util/grub-probe.c
> @@ -142,7 +142,7 @@ probe (const char *path, char *device_name)
>  	  abstraction_name = "lvm";
>  	  break;
>  	case GRUB_DEV_ABSTRACTION_RAID:
> -	  abstraction_name = "raid";
> +	  abstraction_name = "raid mdraid";
>  	  break;
>  	default:
>  	  grub_util_info ("did not find LVM/RAID in %s, assuming raw device", device_name);
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel




  parent reply	other threads:[~2008-08-13 10:01 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-08-10 11:52 [PATCH] Split of raid scan code Bean
2008-08-10 12:13 ` Felix Zielcke
2008-08-10 14:29 ` Robert Millan
2008-08-10 14:45   ` Bean
2008-08-10 15:49     ` Bean
2008-08-11 18:45       ` Bean
2008-08-11 20:13         ` Bean
2008-08-11 20:24           ` Bean
2008-08-11 20:30             ` Robert Millan
2008-08-12 11:49               ` Bean
2008-08-12 12:24                 ` Felix Zielcke
2008-08-12 13:32                 ` Robert Millan
2008-08-13 10:05                 ` Marco Gerards [this message]
2008-08-13 18:43                   ` Bean
2008-08-13 20:01                     ` Bean
2008-08-16  9:07                       ` Bean
2008-08-16 12:16                         ` Robert Millan
2008-08-16 15:20                           ` Bean
2008-08-17 14:19                             ` Bean
2008-08-17 14:52                             ` Robert Millan
2008-08-17 15:08                               ` Bean
2008-08-17 15:23                                 ` Robert Millan
2008-08-18 17:20                                   ` Bean
2008-08-23 14:51                                     ` Bean

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87skt99qn4.fsf@xs4all.nl \
    --to=mgerards@xs4all.nl \
    --cc=grub-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.