Merge common RAID and LVM logic to an abstract diskfilter.

Add LDM support using the same framework.

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

1081
grub-core/disk/diskfilter.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -22,7 +22,7 @@
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/raid.h>
#include <grub/diskfilter.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -90,72 +90,91 @@ struct grub_nv_super
struct grub_nv_array array; /* Array information */
} __attribute__ ((packed));
static grub_err_t
grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array,
grub_disk_addr_t *start_sector)
static struct grub_diskfilter_vg *
grub_dmraid_nv_detect (grub_disk_t disk,
struct grub_diskfilter_pv_id *id,
grub_disk_addr_t *start_sector)
{
grub_disk_addr_t sector;
struct grub_nv_super sb;
int level;
int layout;
grub_uint64_t disk_size;
char *uuid;
if (disk->partition)
return grub_error (GRUB_ERR_OUT_OF_RANGE, "skip partition");
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "skip partition");
return NULL;
}
sector = grub_disk_get_size (disk);
if (sector == GRUB_DISK_SIZE_UNKNOWN)
return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
return NULL;
}
sector -= 2;
if (grub_disk_read (disk, sector, 0, sizeof (sb), &sb))
return grub_errno;
return NULL;
if (grub_memcmp (sb.vendor, NV_ID_STRING, 6))
return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
return NULL;
}
if (sb.version != NV_VERSION)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unknown version: %d.%d", sb.version);
{
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unknown version: %d.%d", sb.version);
return NULL;
}
switch (sb.array.raid_level)
{
case NV_LEVEL_0:
array->level = 0;
array->disk_size = sb.capacity / sb.array.total_volumes;
level = 0;
disk_size = sb.capacity / sb.array.total_volumes;
break;
case NV_LEVEL_1:
array->level = 1;
array->disk_size = sb.capacity;
level = 1;
disk_size = sb.capacity;
break;
case NV_LEVEL_5:
array->level = 5;
array->layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC;
array->disk_size = sb.capacity / (sb.array.total_volumes - 1);
level = 5;
layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC;
disk_size = sb.capacity / (sb.array.total_volumes - 1);
break;
default:
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unsupported RAID level: %d", sb.array.raid_level);
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unsupported RAID level: %d", sb.array.raid_level);
return NULL;
}
array->name = NULL;
array->number = 0;
array->total_devs = sb.array.total_volumes;
array->chunk_size = sb.array.stripe_block_size;
array->index = sb.unit_number;
array->uuid_len = sizeof (sb.array.signature);
array->uuid = grub_malloc (sizeof (sb.array.signature));
if (! array->uuid)
return grub_errno;
uuid = grub_malloc (sizeof (sb.array.signature));
if (! uuid)
return NULL;
grub_memcpy (array->uuid, (char *) &sb.array.signature,
grub_memcpy (uuid, (char *) &sb.array.signature,
sizeof (sb.array.signature));
id->uuidlen = 0;
id->id = sb.unit_number;
*start_sector = 0;
return 0;
return grub_diskfilter_make_raid (sizeof (sb.array.signature),
uuid, sb.array.total_volumes,
NULL, disk_size,
sb.array.stripe_block_size, layout,
level);
}
static struct grub_raid grub_dmraid_nv_dev =
static struct grub_diskfilter grub_dmraid_nv_dev =
{
.name = "dmraid_nv",
.detect = grub_dmraid_nv_detect,
@ -164,10 +183,10 @@ static struct grub_raid grub_dmraid_nv_dev =
GRUB_MOD_INIT(dm_nv)
{
grub_raid_register (&grub_dmraid_nv_dev);
grub_diskfilter_register (&grub_dmraid_nv_dev);
}
GRUB_MOD_FINI(dm_nv)
{
grub_raid_unregister (&grub_dmraid_nv_dev);
grub_diskfilter_unregister (&grub_dmraid_nv_dev);
}

997
grub-core/disk/ldm.c Normal file
View file

@ -0,0 +1,997 @@
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2006,2007,2008,2009,2011 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/dl.h>
#include <grub/disk.h>
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/diskfilter.h>
#include <grub/gpt_partition.h>
#ifdef GRUB_UTIL
#include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
#endif
GRUB_MOD_LICENSE ("GPLv3+");
#define LDM_GUID_STRLEN 64
#define LDM_NAME_STRLEN 32
typedef grub_uint8_t *grub_ldm_id_t;
enum { STRIPE = 1, SPANNED = 2, RAID5 = 3 };
#define LDM_LABEL_SECTOR 6
struct grub_ldm_vblk {
char magic[4];
grub_uint8_t unused1[12];
grub_uint16_t update_status;
grub_uint8_t flags;
grub_uint8_t type;
grub_uint32_t unused2;
grub_uint8_t dynamic[104];
} __attribute__ ((packed));
#define LDM_VBLK_MAGIC "VBLK"
enum
{
STATUS_CONSISTENT = 0,
STATUS_STILL_ACTIVE = 1,
STATUS_NOT_ACTIVE_YET = 2
};
enum
{
ENTRY_COMPONENT = 0x32,
ENTRY_PARTITION = 0x33,
ENTRY_DISK = 0x34,
ENTRY_VOLUME = 0x51,
};
struct grub_ldm_label
{
char magic[8];
grub_uint32_t unused1;
grub_uint16_t ver_major;
grub_uint16_t ver_minor;
grub_uint8_t unused2[32];
char disk_guid[LDM_GUID_STRLEN];
char host_guid[LDM_GUID_STRLEN];
char group_guid[LDM_GUID_STRLEN];
char group_name[LDM_NAME_STRLEN];
grub_uint8_t unused3[11];
grub_uint64_t pv_start;
grub_uint64_t pv_size;
grub_uint64_t config_start;
grub_uint64_t config_size;
} __attribute__ ((packed));
#define LDM_MAGIC "PRIVHEAD"
static inline grub_uint64_t
read_int (grub_uint8_t *in, grub_size_t s)
{
grub_uint8_t *ptr2;
grub_uint64_t ret;
ret = 0;
for (ptr2 = in; ptr2 < in + s; ptr2++)
{
ret <<= 8;
ret |= *ptr2;
}
return ret;
}
static const grub_gpt_part_type_t ldm_type = GRUB_GPT_PARTITION_TYPE_LDM;
static grub_disk_addr_t
gpt_ldm_sector (grub_disk_t dsk)
{
grub_disk_addr_t sector = 0;
grub_err_t err;
auto int hook (grub_disk_t disk, const grub_partition_t p);
int hook (grub_disk_t disk, const grub_partition_t p)
{
struct grub_gpt_partentry gptdata;
grub_partition_t p2;
p2 = disk->partition;
disk->partition = p->parent;
if (grub_disk_read (disk, p->offset, p->index,
sizeof (gptdata), &gptdata))
{
disk->partition = p2;
return 0;
}
disk->partition = p2;
if (! grub_memcmp (&gptdata.type, &ldm_type, 16))
{
sector = p->start + p->len - 1;
return 1;
}
return 0;
}
err = grub_gpt_partition_map_iterate (dsk, hook);
if (err)
{
grub_errno = GRUB_ERR_NONE;
return 0;
}
return sector;
}
static struct grub_diskfilter_vg *
make_vg (grub_disk_t disk,
const struct grub_ldm_label *label)
{
grub_disk_addr_t startsec, endsec, cursec;
struct grub_diskfilter_vg *vg;
grub_err_t err;
/* First time we see this volume group. We've to create the
whole volume group structure. */
vg = grub_malloc (sizeof (*vg));
if (! vg)
return NULL;
vg->extent_size = 1;
vg->name = grub_malloc (LDM_NAME_STRLEN + 1);
vg->uuid = grub_malloc (LDM_GUID_STRLEN + 1);
if (! vg->uuid || !vg->name)
{
grub_free (vg->uuid);
grub_free (vg->name);
return NULL;
}
grub_memcpy (vg->uuid, label->group_guid, LDM_GUID_STRLEN);
grub_memcpy (vg->name, label->group_name, LDM_NAME_STRLEN);
vg->name[LDM_NAME_STRLEN] = 0;
vg->uuid[LDM_GUID_STRLEN] = 0;
vg->uuid_len = grub_strlen (vg->uuid);
vg->lvs = NULL;
vg->pvs = NULL;
startsec = grub_be_to_cpu64 (label->config_start);
endsec = startsec + grub_be_to_cpu64 (label->config_size);
/* First find disks. */
for (cursec = startsec + 0x12; cursec < endsec; cursec++)
{
struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
/ sizeof (struct grub_ldm_vblk)];
unsigned i;
err = grub_disk_read (disk, cursec, 0,
sizeof(vblk), &vblk);
if (err)
goto fail2;
for (i = 0; i < ARRAY_SIZE (vblk); i++)
{
struct grub_diskfilter_pv *pv;
grub_uint8_t *ptr;
if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
sizeof (vblk[i].magic)) != 0)
continue;
if (grub_be_to_cpu16 (vblk[i].update_status)
!= STATUS_CONSISTENT
&& grub_be_to_cpu16 (vblk[i].update_status)
!= STATUS_STILL_ACTIVE)
continue;
if (vblk[i].type != ENTRY_DISK)
continue;
pv = grub_zalloc (sizeof (*pv));
if (!pv)
goto fail2;
pv->disk = 0;
ptr = vblk[i].dynamic;
if (ptr + *ptr + 1 >= vblk[i].dynamic
+ sizeof (vblk[i].dynamic))
{
grub_free (pv);
goto fail2;
}
pv->internal_id = grub_malloc (ptr[0] + 2);
if (!pv->internal_id)
{
grub_free (pv);
goto fail2;
}
grub_memcpy (pv->internal_id, ptr, (grub_size_t) ptr[0] + 1);
pv->internal_id[(grub_size_t) ptr[0] + 1] = 0;
ptr += *ptr + 1;
if (ptr + *ptr + 1 >= vblk[i].dynamic
+ sizeof (vblk[i].dynamic))
{
grub_free (pv);
goto fail2;
}
/* ptr = name. */
ptr += *ptr + 1;
if (ptr + *ptr + 1
>= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
grub_free (pv);
goto fail2;
}
pv->id.uuidlen = *ptr;
pv->id.uuid = grub_malloc (pv->id.uuidlen + 1);
grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen);
pv->id.uuid[pv->id.uuidlen] = 0;
pv->next = vg->pvs;
vg->pvs = pv;
}
}
/* Then find LVs. */
for (cursec = startsec + 0x12; cursec < endsec; cursec++)
{
struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
/ sizeof (struct grub_ldm_vblk)];
unsigned i;
err = grub_disk_read (disk, cursec, 0,
sizeof(vblk), &vblk);
if (err)
goto fail2;
for (i = 0; i < ARRAY_SIZE (vblk); i++)
{
struct grub_diskfilter_lv *lv;
grub_uint8_t *ptr;
if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
sizeof (vblk[i].magic)) != 0)
continue;
if (grub_be_to_cpu16 (vblk[i].update_status)
!= STATUS_CONSISTENT
&& grub_be_to_cpu16 (vblk[i].update_status)
!= STATUS_STILL_ACTIVE)
continue;
if (vblk[i].type != ENTRY_VOLUME)
continue;
lv = grub_zalloc (sizeof (*lv));
if (!lv)
goto fail2;
lv->vg = vg;
lv->segment_count = 1;
lv->segment_alloc = 1;
lv->visible = 1;
lv->segments = grub_zalloc (sizeof (*lv->segments));
if (!lv->segments)
goto fail2;
lv->segments->start_extent = 0;
lv->segments->type = GRUB_DISKFILTER_MIRROR;
lv->segments->node_count = 0;
lv->segments->node_alloc = 8;
lv->segments->nodes = grub_zalloc (sizeof (*lv->segments->nodes)
* lv->segments->node_alloc);
if (!lv->segments->nodes)
goto fail2;
ptr = vblk[i].dynamic;
if (ptr + *ptr + 1 >= vblk[i].dynamic
+ sizeof (vblk[i].dynamic))
{
grub_free (lv);
goto fail2;
}
lv->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2);
if (!lv->internal_id)
{
grub_free (lv);
goto fail2;
}
grub_memcpy (lv->internal_id, ptr, ptr[0] + 1);
lv->internal_id[ptr[0] + 1] = 0;
ptr += *ptr + 1;
if (ptr + *ptr + 1 >= vblk[i].dynamic
+ sizeof (vblk[i].dynamic))
{
grub_free (lv);
goto fail2;
}
lv->name = grub_malloc (*ptr + 1);
if (!lv->name)
{
grub_free (lv->internal_id);
grub_free (lv);
goto fail2;
}
grub_memcpy (lv->name, ptr + 1, *ptr);
lv->name[*ptr] = 0;
lv->fullname = grub_xasprintf ("ldm/%s/%s",
vg->uuid, lv->name);
if (!lv->fullname)
{
grub_free (lv->internal_id);
grub_free (lv->name);
grub_free (lv);
goto fail2;
}
ptr += *ptr + 1;
if (ptr + *ptr + 1
>= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
grub_free (lv->internal_id);
grub_free (lv->name);
grub_free (lv);
goto fail2;
}
/* ptr = volume type. */
ptr += *ptr + 1;
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
grub_free (lv->internal_id);
grub_free (lv->name);
grub_free (lv);
goto fail2;
}
/* ptr = flags. */
ptr += *ptr + 1;
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
grub_free (lv->internal_id);
grub_free (lv->name);
grub_free (lv);
goto fail2;
}
/* Skip state, type, unknown, volume number, zeros, flags. */
ptr += 14 + 1 + 1 + 1 + 3 + 1;
/* ptr = number of children. */
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
grub_free (lv->internal_id);
grub_free (lv->name);
grub_free (lv);
goto fail2;
}
ptr += *ptr + 1;
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
grub_free (lv->internal_id);
grub_free (lv->name);
grub_free (lv);
goto fail2;
}
/* Skip 2 more fields. */
ptr += 8 + 8;
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
|| ptr + *ptr + 1>= vblk[i].dynamic
+ sizeof (vblk[i].dynamic))
{
grub_free (lv->internal_id);
grub_free (lv->name);
grub_free (lv);
goto fail2;
}
lv->size = read_int (ptr + 1, *ptr);
lv->segments->extent_count = lv->size;
lv->next = vg->lvs;
vg->lvs = lv;
}
}
/* Now the components. */
for (cursec = startsec + 0x12; cursec < endsec; cursec++)
{
struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
/ sizeof (struct grub_ldm_vblk)];
unsigned i;
err = grub_disk_read (disk, cursec, 0,
sizeof(vblk), &vblk);
if (err)
goto fail2;
for (i = 0; i < ARRAY_SIZE (vblk); i++)
{
struct grub_diskfilter_lv *comp;
struct grub_diskfilter_lv *lv;
grub_uint8_t type;
grub_uint8_t *ptr;
if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
sizeof (vblk[i].magic)) != 0)
continue;
if (grub_be_to_cpu16 (vblk[i].update_status)
!= STATUS_CONSISTENT
&& grub_be_to_cpu16 (vblk[i].update_status)
!= STATUS_STILL_ACTIVE)
continue;
if (vblk[i].type != ENTRY_COMPONENT)
continue;
comp = grub_zalloc (sizeof (*comp));
if (!comp)
goto fail2;
comp->visible = 0;
comp->name = 0;
comp->fullname = 0;
ptr = vblk[i].dynamic;
if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
goto fail2;
}
comp->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2);
if (!comp->internal_id)
{
grub_free (comp);
goto fail2;
}
grub_memcpy (comp->internal_id, ptr, ptr[0] + 1);
comp->internal_id[ptr[0] + 1] = 0;
ptr += *ptr + 1;
if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
grub_free (comp->internal_id);
grub_free (comp);
goto fail2;
}
/* ptr = name. */
ptr += *ptr + 1;
if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
grub_free (comp->internal_id);
grub_free (comp);
goto fail2;
}
/* ptr = state. */
ptr += *ptr + 1;
type = *ptr++;
/* skip zeros. */
ptr += 4;
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
grub_free (comp->internal_id);
grub_free (comp);
goto fail2;
}
/* ptr = number of children. */
ptr += *ptr + 1;
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
grub_free (comp->internal_id);
grub_free (comp);
goto fail2;
}
ptr += 8 + 8;
if (ptr + *ptr + 1 >= vblk[i].dynamic
+ sizeof (vblk[i].dynamic))
{
grub_free (comp->internal_id);
grub_free (comp);
goto fail2;
}
for (lv = vg->lvs; lv; lv = lv->next)
{
if (lv->internal_id[0] == ptr[0]
&& grub_memcmp (lv->internal_id + 1, ptr + 1, ptr[0]) == 0)
break;
}
if (!lv)
{
grub_free (comp->internal_id);
grub_free (comp);
continue;
}
comp->size = lv->size;
if (type == SPANNED)
{
comp->segment_alloc = 8;
comp->segment_count = 0;
comp->segments = grub_malloc (sizeof (*comp->segments)
* comp->segment_alloc);
if (!comp->segments)
goto fail2;
}
else
{
comp->segment_alloc = 1;
comp->segment_count = 1;
comp->segments = grub_malloc (sizeof (*comp->segments));
if (!comp->segments)
goto fail2;
comp->segments->start_extent = 0;
comp->segments->extent_count = lv->size;
comp->segments->layout = 0;
if (type == STRIPE)
comp->segments->type = GRUB_DISKFILTER_STRIPED;
else if (type == RAID5)
{
comp->segments->type = GRUB_DISKFILTER_RAID5;
comp->segments->layout = GRUB_RAID_LAYOUT_SYMMETRIC_MASK;
}
else
goto fail2;
ptr += *ptr + 1;
ptr++;
if (!(vblk[i].flags & 0x10))
goto fail2;
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
|| ptr + *ptr + 1 >= vblk[i].dynamic
+ sizeof (vblk[i].dynamic))
{
grub_free (comp->internal_id);
grub_free (comp);
goto fail2;
}
comp->segments->stripe_size = read_int (ptr + 1, *ptr);
ptr += *ptr + 1;
if (ptr + *ptr + 1 >= vblk[i].dynamic
+ sizeof (vblk[i].dynamic))
{
grub_free (comp->internal_id);
grub_free (comp);
goto fail2;
}
comp->segments->node_count = read_int (ptr + 1, *ptr);
comp->segments->node_alloc = comp->segments->node_count;
comp->segments->nodes = grub_zalloc (sizeof (*comp->segments->nodes)
* comp->segments->node_alloc);
if (!lv->segments->nodes)
goto fail2;
}
if (lv->segments->node_alloc == lv->segments->node_count)
{
void *t;
lv->segments->node_alloc *= 2;
t = grub_realloc (lv->segments->nodes,
sizeof (*lv->segments->nodes)
* lv->segments->node_alloc);
if (!t)
goto fail2;
lv->segments->nodes = t;
}
lv->segments->nodes[lv->segments->node_count].pv = 0;
lv->segments->nodes[lv->segments->node_count].start = 0;
lv->segments->nodes[lv->segments->node_count++].lv = comp;
comp->next = vg->lvs;
vg->lvs = comp;
}
}
/* Partitions. */
for (cursec = startsec + 0x12; cursec < endsec; cursec++)
{
struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
/ sizeof (struct grub_ldm_vblk)];
unsigned i;
err = grub_disk_read (disk, cursec, 0,
sizeof(vblk), &vblk);
if (err)
goto fail2;
for (i = 0; i < ARRAY_SIZE (vblk); i++)
{
struct grub_diskfilter_lv *comp;
struct grub_diskfilter_node part;
grub_disk_addr_t start, size;
grub_uint8_t *ptr;
if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
sizeof (vblk[i].magic)) != 0)
continue;
if (grub_be_to_cpu16 (vblk[i].update_status)
!= STATUS_CONSISTENT
&& grub_be_to_cpu16 (vblk[i].update_status)
!= STATUS_STILL_ACTIVE)
continue;
if (vblk[i].type != ENTRY_PARTITION)
continue;
part.lv = 0;
part.pv = 0;
ptr = vblk[i].dynamic;
if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
goto fail2;
}
/* ID */
ptr += *ptr + 1;
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
goto fail2;
}
/* ptr = name. */
ptr += *ptr + 1;
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
goto fail2;
}
/* skip zeros and logcommit id. */
ptr += 4 + 8;
if (ptr + 16 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
goto fail2;
}
part.start = read_int (ptr, 8);
start = read_int (ptr + 8, 8);
ptr += 16;
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
|| ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
goto fail2;
}
size = read_int (ptr + 1, *ptr);
ptr += *ptr + 1;
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
|| ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
goto fail2;
}
for (comp = vg->lvs; comp; comp = comp->next)
if (comp->internal_id[0] == ptr[0]
&& grub_memcmp (ptr + 1, comp->internal_id + 1,
comp->internal_id[0]) == 0)
goto out;
continue;
out:
if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
|| ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
{
goto fail2;
}
ptr += *ptr + 1;
struct grub_diskfilter_pv *pv;
for (pv = vg->pvs; pv; pv = pv->next)
if (pv->internal_id[0] == ptr[0]
&& grub_memcmp (pv->internal_id + 1, ptr + 1, ptr[0]) == 0)
part.pv = pv;
if (comp->segment_alloc == 1)
{
unsigned index;
ptr += *ptr + 1;
if (ptr + *ptr + 1 >= vblk[i].dynamic
+ sizeof (vblk[i].dynamic))
{
goto fail2;
}
index = read_int (ptr + 1, *ptr);
if (index < comp->segments->node_count)
comp->segments->nodes[index] = part;
}
else
{
if (comp->segment_alloc == comp->segment_count)
{
void *t;
comp->segment_alloc *= 2;
t = grub_realloc (comp->segments,
comp->segment_alloc
* sizeof (*comp->segments));
if (!t)
goto fail2;
comp->segments = t;
}
comp->segments[comp->segment_count].start_extent = start;
comp->segments[comp->segment_count].extent_count = size;
comp->segments[comp->segment_count].type = GRUB_DISKFILTER_STRIPED;
comp->segments[comp->segment_count].node_count = 1;
comp->segments[comp->segment_count].node_alloc = 1;
comp->segments[comp->segment_count].nodes
= grub_malloc (sizeof (*comp->segments[comp->segment_count].nodes));
if (!comp->segments[comp->segment_count].nodes)
goto fail2;
comp->segments[comp->segment_count].nodes[0] = part;
comp->segment_count++;
}
}
}
if (grub_diskfilter_vg_register (vg))
goto fail2;
return vg;
fail2:
{
struct grub_diskfilter_lv *lv, *next_lv;
struct grub_diskfilter_pv *pv, *next_pv;
for (lv = vg->lvs; lv; lv = next_lv)
{
unsigned i;
for (i = 0; i < lv->segment_count; i++)
grub_free (lv->segments[i].nodes);
next_lv = lv->next;
grub_free (lv->segments);
grub_free (lv->internal_id);
grub_free (lv->name);
grub_free (lv->fullname);
grub_free (lv);
}
for (pv = vg->pvs; pv; pv = next_pv)
{
next_pv = pv->next;
grub_free (pv->id.uuid);
grub_free (pv);
}
}
grub_free (vg->uuid);
grub_free (vg);
return NULL;
}
static struct grub_diskfilter_vg *
grub_ldm_detect (grub_disk_t disk,
struct grub_diskfilter_pv_id *id,
grub_disk_addr_t *start_sector)
{
grub_err_t err;
struct grub_ldm_label label;
struct grub_diskfilter_vg *vg;
#ifdef GRUB_UTIL
grub_util_info ("scanning %s for LDM", disk->name);
#endif
{
int i;
for (i = 0; i < 3; i++)
{
grub_disk_addr_t sector;
switch (i)
{
case 0:
sector = LDM_LABEL_SECTOR;
break;
case 1:
/* LDM is never inside a partition. */
if (disk->partition)
continue;
sector = grub_disk_get_size (disk);
if (sector == GRUB_DISK_SIZE_UNKNOWN)
continue;
sector--;
break;
/* FIXME: try the third copy. */
case 2:
sector = gpt_ldm_sector (disk);
if (!sector)
continue;
break;
}
err = grub_disk_read (disk, sector, 0,
sizeof(label), &label);
if (err)
return NULL;
if (grub_memcmp (label.magic, LDM_MAGIC, sizeof (label.magic)) == 0
&& grub_be_to_cpu16 (label.ver_major) == 0x02
&& grub_be_to_cpu16 (label.ver_minor) >= 0x0b
&& grub_be_to_cpu16 (label.ver_minor) <= 0x0c)
break;
}
/* Return if we didn't find a label. */
if (i == 3)
{
#ifdef GRUB_UTIL
grub_util_info ("no LDM signature found");
#endif
return NULL;
}
}
id->uuid = grub_malloc (LDM_GUID_STRLEN + 1);
if (!id->uuid)
return NULL;
grub_memcpy (id->uuid, label.disk_guid, LDM_GUID_STRLEN);
id->uuid[LDM_GUID_STRLEN] = 0;
id->uuidlen = grub_strlen ((char *) id->uuid);
*start_sector = grub_be_to_cpu64 (label.pv_start);
{
grub_size_t s;
for (s = 0; s < LDM_GUID_STRLEN && label.group_guid[s]; s++);
vg = grub_diskfilter_get_vg_by_uuid (s, label.group_guid);
if (! vg)
vg = make_vg (disk, &label);
}
if (!vg)
{
grub_free (id->uuid);
return NULL;
}
return vg;
}
#ifdef GRUB_UTIL
char *
grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start)
{
struct grub_diskfilter_pv *pv = NULL;
struct grub_diskfilter_vg *vg = NULL;
struct grub_diskfilter_lv *res, *lv;
int i;
pv = grub_diskfilter_get_pv_from_disk (disk, &vg);
if (!pv)
return NULL;
for (lv = vg->lvs; lv; lv = lv->next)
if (lv->segment_count == 1 && lv->segments->node_count == 1
&& lv->segments->type == GRUB_DISKFILTER_STRIPED
&& lv->segments->nodes->pv == pv
&& lv->segments->nodes->start + pv->start_sector == start)
{
res = lv;
break;
}
for (lv = vg->lvs; lv; lv = lv->next)
if (lv->segment_count == 1 && lv->segments->node_count == 1
&& lv->segments->type == GRUB_DISKFILTER_MIRROR
&& lv->segments->nodes->lv == lv)
{
res = lv;
break;
}
if (res->fullname)
return grub_strdup (lv->fullname);
return NULL;
}
int
grub_util_is_ldm (grub_disk_t disk)
{
int i;
for (i = 0; i < 3; i++)
{
grub_disk_addr_t sector;
grub_err_t err;
struct grub_ldm_label label;
switch (i)
{
case 0:
sector = LDM_LABEL_SECTOR;
break;
case 1:
/* LDM is never inside a partition. */
if (disk->partition)
continue;
sector = grub_disk_get_size (disk);
if (sector == GRUB_DISK_SIZE_UNKNOWN)
continue;
sector--;
break;
/* FIXME: try the third copy. */
case 2:
sector = gpt_ldm_sector (disk);
if (!sector)
continue;
break;
}
err = grub_disk_read (disk, sector, 0, sizeof(label), &label);
if (err)
{
grub_errno = GRUB_ERR_NONE;
return 0;
}
/* This check is more relaxed on purpose. */
if (grub_memcmp (label.magic, LDM_MAGIC, sizeof (label.magic)) == 0)
return 1;
}
return 0;
}
grub_err_t
grub_util_ldm_embed (struct grub_disk *disk, unsigned int *nsectors,
grub_embed_type_t embed_type,
grub_disk_addr_t **sectors)
{
struct grub_diskfilter_pv *pv = NULL;
struct grub_diskfilter_vg *vg;
struct grub_diskfilter_lv *lv;
unsigned i;
if (embed_type != GRUB_EMBED_PCBIOS)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"GPT curently supports only PC-BIOS embedding");
if (disk->partition)
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "disk isn't LDM");
pv = grub_diskfilter_get_pv_from_disk (disk, &vg);
if (!pv)
return grub_error (GRUB_ERR_FILE_NOT_FOUND, "disk isn't LDM");
for (lv = vg->lvs; lv; lv = lv->next)
{
struct grub_diskfilter_lv *comp;
struct grub_ldm_partition *part;
if (!lv->visible || !lv->fullname)
continue;
if (lv->segment_count != 1)
continue;
if (lv->segments->type != GRUB_DISKFILTER_MIRROR
|| lv->segments->node_count != 1
|| lv->segments->start_extent != 0
|| lv->segments->extent_count != lv->size)
continue;
comp = lv->segments->nodes->lv;
if (!comp)
continue;
if (comp->segment_count != 1 || comp->size != lv->size)
continue;
if (comp->segments->type != GRUB_DISKFILTER_STRIPED
|| comp->segments->node_count != 1
|| comp->segments->start_extent != 0
|| comp->segments->extent_count != lv->size)
continue;
/* How to implement proper check is to be discussed. */
#if 1
if (1)
continue;
#else
if (grub_strcmp (lv->name, "Volume5") != 0)
continue;
#endif
if (lv->size < *nsectors)
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"Your LDM embed Partition is too small;"
" embedding won't be possible!");
*nsectors = lv->size;
*sectors = grub_malloc (*nsectors * sizeof (**sectors));
if (!*sectors)
return grub_errno;
for (i = 0; i < *nsectors; i++)
(*sectors)[i] = (lv->segments->nodes->start
+ comp->segments->nodes->start
+ comp->segments->nodes->pv->start_sector + i);
return GRUB_ERR_NONE;
}
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
"This LDM no Embedding Partition;"
" embedding won't be possible!");
}
#endif
static struct grub_diskfilter grub_ldm_dev = {
.name = "ldm",
.detect = grub_ldm_detect,
.next = 0
};
GRUB_MOD_INIT (ldm)
{
grub_diskfilter_register (&grub_ldm_dev);
}
GRUB_MOD_FINI (ldm)
{
grub_diskfilter_unregister (&grub_ldm_dev);
}

File diff suppressed because it is too large Load diff

View file

@ -22,7 +22,7 @@
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/raid.h>
#include <grub/diskfilter.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -103,8 +103,9 @@ struct grub_raid_super_1x
#define WriteMostly1 1 /* Mask for writemostly flag in above devflags. */
static grub_err_t
grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
static struct grub_diskfilter_vg *
grub_mdraid_detect (grub_disk_t disk,
struct grub_diskfilter_pv_id *id,
grub_disk_addr_t *start_sector)
{
grub_disk_addr_t sector = 0;
@ -142,7 +143,7 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
if (grub_disk_read (disk, sector, 0, sizeof (struct grub_raid_super_1x),
&sb))
return grub_errno;
return NULL;
if (grub_le_to_cpu32 (sb.magic) != SB_MAGIC
|| grub_le_to_cpu64 (sb.super_offset) != sector)
@ -154,9 +155,12 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
grub_uint32_t level;
if (grub_le_to_cpu32 (sb.major_version) != 1)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"Unsupported RAID version: %d",
grub_le_to_cpu32 (sb.major_version));
{
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"Unsupported RAID version: %d",
grub_le_to_cpu32 (sb.major_version));
return NULL;
}
level = grub_le_to_cpu32 (sb.level);
@ -166,8 +170,11 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
if (level != 0 && level != 1 && level != 4 &&
level != 5 && level != 6 && level != 10)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"Unsupported RAID level: %d", sb.level);
{
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"Unsupported RAID level: %d", sb.level);
return NULL;
}
/* 1.x superblocks don't have a fixed size on disk. So we have to
read it again now that we now the max device count. */
@ -175,62 +182,68 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
+ 2 * grub_le_to_cpu32 (sb.max_dev);
real_sb = grub_malloc (sb_size);
if (! real_sb)
return grub_errno;
return NULL;
if (grub_disk_read (disk, sector, 0, sb_size, real_sb))
{
grub_free (real_sb);
return grub_errno;
return NULL;
}
array->name = grub_strdup (real_sb->set_name);
if (! array->name)
{
grub_free (real_sb);
return grub_errno;
}
array->number = 0;
array->level = grub_le_to_cpu32 (real_sb->level);
array->layout = grub_le_to_cpu32 (real_sb->layout);
array->total_devs = grub_le_to_cpu32 (real_sb->raid_disks);
if (real_sb->size)
array->disk_size = grub_le_to_cpu64 (real_sb->size);
else
array->disk_size = grub_le_to_cpu64 (real_sb->data_size);
array->chunk_size = grub_le_to_cpu32 (real_sb->chunksize);
struct grub_diskfilter_vg *array;
char *uuid;
if (grub_le_to_cpu32 (real_sb->dev_number) >=
grub_le_to_cpu32 (real_sb->max_dev))
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"spares aren't implemented");
array->index = grub_le_to_cpu16
(real_sb->dev_roles[grub_le_to_cpu32 (real_sb->dev_number)]);
if (array->index >= array->total_devs)
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"spares aren't implemented");
array->uuid_len = 16;
array->uuid = grub_malloc (16);
if (!array->uuid)
{
grub_free (real_sb);
return grub_errno;
grub_error (GRUB_ERR_OUT_OF_RANGE,
"spares aren't implemented");
return NULL;
}
grub_memcpy (array->uuid, real_sb->set_uuid, 16);
id->uuidlen = 0;
id->id = grub_le_to_cpu16
(real_sb->dev_roles[grub_le_to_cpu32 (real_sb->dev_number)]);
uuid = grub_malloc (16);
if (!uuid)
{
grub_free (real_sb);
return NULL;
}
grub_memcpy (uuid, real_sb->set_uuid, 16);
*start_sector = grub_le_to_cpu64 (real_sb->data_offset);
if (grub_le_to_cpu32 (real_sb->dev_number)
>= grub_le_to_cpu32 (real_sb->raid_disks))
{
grub_error (GRUB_ERR_OUT_OF_RANGE,
"spares aren't implemented");
return NULL;
}
array = grub_diskfilter_make_raid (16, uuid,
grub_le_to_cpu32 (real_sb->raid_disks),
real_sb->set_name,
(real_sb->size)
? grub_le_to_cpu64 (real_sb->size)
: grub_le_to_cpu64 (real_sb->data_size),
grub_le_to_cpu32 (real_sb->chunksize),
grub_le_to_cpu32 (real_sb->layout),
grub_le_to_cpu32 (real_sb->level));
grub_free (real_sb);
return 0;
return array;
}
}
return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 1.x raid");
grub_error (GRUB_ERR_OUT_OF_RANGE, "not 1.x raid");
return NULL;
}
static struct grub_raid grub_mdraid_dev = {
static struct grub_diskfilter grub_mdraid_dev = {
.name = "mdraid1x",
.detect = grub_mdraid_detect,
.next = 0
@ -238,10 +251,10 @@ static struct grub_raid grub_mdraid_dev = {
GRUB_MOD_INIT (mdraid1x)
{
grub_raid_register (&grub_mdraid_dev);
grub_diskfilter_register (&grub_mdraid_dev);
}
GRUB_MOD_FINI (mdraid1x)
{
grub_raid_unregister (&grub_mdraid_dev);
grub_diskfilter_unregister (&grub_mdraid_dev);
}

View file

@ -22,7 +22,7 @@
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/raid.h>
#include <grub/diskfilter.h>
/* Linux RAID on disk structures and constants,
copied from include/linux/raid/md_p.h. */
@ -161,8 +161,9 @@ struct grub_raid_super_09
struct grub_raid_disk_09 this_disk;
} __attribute__ ((packed));
static grub_err_t
grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
static struct grub_diskfilter_vg *
grub_mdraid_detect (grub_disk_t disk,
struct grub_diskfilter_pv_id *id,
grub_disk_addr_t *start_sector)
{
grub_disk_addr_t sector;
@ -174,22 +175,31 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
/* The sector where the mdraid 0.90 superblock is stored, if available. */
size = grub_disk_get_size (disk);
if (size == GRUB_DISK_SIZE_UNKNOWN)
return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
return NULL;
}
sector = NEW_SIZE_SECTORS (size);
if (grub_disk_read (disk, sector, 0, SB_BYTES, &sb))
return grub_errno;
return NULL;
/* Look whether there is a mdraid 0.90 superblock. */
if (grub_le_to_cpu32 (sb.md_magic) != SB_MAGIC)
return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
return NULL;
}
if (grub_le_to_cpu32 (sb.major_version) != 0
|| grub_le_to_cpu32 (sb.minor_version) != 90)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unsupported RAID version: %d.%d",
grub_le_to_cpu32 (sb.major_version),
grub_le_to_cpu32 (sb.minor_version));
{
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unsupported RAID version: %d.%d",
grub_le_to_cpu32 (sb.major_version),
grub_le_to_cpu32 (sb.minor_version));
return NULL;
}
/* FIXME: Check the checksum. */
@ -200,26 +210,22 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
if (level != 0 && level != 1 && level != 4 &&
level != 5 && level != 6 && level != 10)
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unsupported RAID level: %d", level);
{
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unsupported RAID level: %d", level);
return NULL;
}
if (grub_le_to_cpu32 (sb.this_disk.number) == 0xffff
|| grub_le_to_cpu32 (sb.this_disk.number) == 0xfffe)
return grub_error (GRUB_ERR_OUT_OF_RANGE,
"spares aren't implemented");
{
grub_error (GRUB_ERR_OUT_OF_RANGE,
"spares aren't implemented");
return NULL;
}
array->name = NULL;
array->number = grub_le_to_cpu32 (sb.md_minor);
array->level = level;
array->layout = grub_le_to_cpu32 (sb.layout);
array->total_devs = grub_le_to_cpu32 (sb.raid_disks);
array->disk_size = (sb.size) ? grub_le_to_cpu32 (sb.size) * 2 : sector;
array->chunk_size = grub_le_to_cpu32 (sb.chunk_size) >> 9;
array->index = grub_le_to_cpu32 (sb.this_disk.number);
array->uuid_len = 16;
uuid = grub_malloc (16);
array->uuid = (char *) uuid;
if (!array->uuid)
return grub_errno;
if (!uuid)
return NULL;
uuid[0] = grub_swap_bytes32 (sb.set_uuid0);
uuid[1] = grub_swap_bytes32 (sb.set_uuid1);
@ -228,10 +234,21 @@ grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
*start_sector = 0;
return 0;
id->uuidlen = 0;
id->id = grub_le_to_cpu32 (sb.this_disk.number);
char buf[32];
grub_snprintf (buf, sizeof (buf), "md%d", grub_le_to_cpu32 (sb.md_minor));
return grub_diskfilter_make_raid (16, (char *) uuid,
grub_le_to_cpu32 (sb.raid_disks), buf,
(sb.size) ? grub_le_to_cpu32 (sb.size) * 2
: sector,
grub_le_to_cpu32 (sb.chunk_size) >> 9,
grub_le_to_cpu32 (sb.layout),
level);
}
static struct grub_raid grub_mdraid_dev = {
static struct grub_diskfilter grub_mdraid_dev = {
.name = "mdraid09",
.detect = grub_mdraid_detect,
.next = 0
@ -239,10 +256,10 @@ static struct grub_raid grub_mdraid_dev = {
GRUB_MOD_INIT (mdraid09)
{
grub_raid_register (&grub_mdraid_dev);
grub_diskfilter_register (&grub_mdraid_dev);
}
GRUB_MOD_FINI (mdraid09)
{
grub_raid_unregister (&grub_mdraid_dev);
grub_diskfilter_unregister (&grub_mdraid_dev);
}

View file

@ -1,921 +0,0 @@
/* raid.c - module to read RAID arrays. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* GRUB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
#include <grub/dl.h>
#include <grub/disk.h>
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/raid.h>
#include <grub/partition.h>
#ifdef GRUB_UTIL
#include <grub/util/misc.h>
#endif
GRUB_MOD_LICENSE ("GPLv3+");
/* Linked list of RAID arrays. */
static struct grub_raid_array *array_list;
grub_raid5_recover_func_t grub_raid5_recover_func;
grub_raid6_recover_func_t grub_raid6_recover_func;
static grub_raid_t grub_raid_list;
static int inscnt = 0;
static struct grub_raid_array *
find_array (const char *name);
static char
grub_is_array_readable (struct grub_raid_array *array)
{
switch (array->level)
{
case 0:
if (array->nr_devs == array->total_devs)
return 1;
break;
case 1:
if (array->nr_devs >= 1)
return 1;
break;
case 4:
case 5:
case 6:
case 10:
{
unsigned int n;
if (array->level == 10)
{
n = array->layout & 0xFF;
if (n == 1)
n = (array->layout >> 8) & 0xFF;
n--;
}
else
n = array->level / 3;
if (array->nr_devs >= array->total_devs - n)
return 1;
break;
}
}
return 0;
}
static grub_err_t
insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
grub_disk_addr_t start_sector, const char *scanner_name,
grub_raid_t raid __attribute__ ((unused)));
static int scan_depth = 0;
static void
scan_devices (const char *arname)
{
grub_raid_t raid;
auto int hook (const char *name);
int hook (const char *name)
{
grub_disk_t disk;
struct grub_raid_array array;
struct grub_raid_array *arr;
grub_disk_addr_t start_sector;
grub_dprintf ("raid", "Scanning for %s RAID devices on disk %s\n",
raid->name, name);
#ifdef GRUB_UTIL
grub_util_info ("Scanning for %s RAID devices on disk %s",
raid->name, name);
#endif
disk = grub_disk_open (name);
if (!disk)
return 0;
for (arr = array_list; arr != NULL; arr = arr->next)
{
struct grub_raid_member *m;
for (m = arr->members; m < arr->members + arr->nr_devs; m++)
if (m->device && m->device->id == disk->id
&& m->device->dev->id == disk->dev->id
&& grub_partition_get_start (m->device->partition)
== grub_partition_get_start (disk->partition)
&& grub_disk_get_size (m->device)
== grub_disk_get_size (disk))
{
grub_disk_close (disk);
return 0;
}
}
if ((! raid->detect (disk, &array, &start_sector)) &&
(! insert_array (disk, &array, start_sector, raid->name,
raid)))
return 0;
/* This error usually means it's not raid, no need to display
it. */
if (grub_errno != GRUB_ERR_OUT_OF_RANGE)
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
grub_disk_close (disk);
if (arname && find_array (arname))
return 1;
return 0;
}
if (scan_depth)
return;
scan_depth++;
for (raid = grub_raid_list; raid; raid = raid->next)
grub_device_iterate (&hook);
scan_depth--;
}
static int
grub_raid_iterate (int (*hook) (const char *name),
grub_disk_pull_t pull)
{
struct grub_raid_array *array;
int islcnt = 0;
if (pull == GRUB_DISK_PULL_RESCAN)
{
islcnt = inscnt;
scan_devices (NULL);
}
if (pull != GRUB_DISK_PULL_NONE && pull != GRUB_DISK_PULL_RESCAN)
return 0;
for (array = array_list; array != NULL; array = array->next)
{
if (grub_is_array_readable (array) && array->became_readable_at >= islcnt)
if (hook (array->name))
return 1;
}
return 0;
}
#ifdef GRUB_UTIL
static grub_disk_memberlist_t
grub_raid_memberlist (grub_disk_t disk)
{
struct grub_raid_array *array = disk->data;
grub_disk_memberlist_t list = NULL, tmp;
unsigned int i;
for (i = 0; i < array->total_devs; i++)
if (array->members[i].device)
{
tmp = grub_malloc (sizeof (*tmp));
tmp->disk = array->members[i].device;
tmp->next = list;
list = tmp;
}
return list;
}
static const char *
grub_raid_getname (struct grub_disk *disk)
{
struct grub_raid_array *array = disk->data;
return array->driver->name;
}
#endif
static inline int
ascii2hex (char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
return 0;
}
static struct grub_raid_array *
find_array (const char *name)
{
struct grub_raid_array *array;
if (grub_memcmp (name, "mduuid/", sizeof ("mduuid/") - 1) == 0)
{
const char *uuidstr = name + sizeof ("mduuid/") - 1;
grub_size_t uuid_len = grub_strlen (uuidstr) / 2;
grub_uint8_t uuidbin[uuid_len];
unsigned i;
for (i = 0; i < uuid_len; i++)
uuidbin[i] = ascii2hex (uuidstr[2 * i + 1])
| (ascii2hex (uuidstr[2 * i]) << 4);
for (array = array_list; array != NULL; array = array->next)
{
if (uuid_len == (unsigned) array->uuid_len
&& grub_memcmp (uuidbin, array->uuid, uuid_len) == 0)
if (grub_is_array_readable (array))
return array;
}
}
else
for (array = array_list; array != NULL; array = array->next)
{
if (!grub_strcmp (array->name, name))
if (grub_is_array_readable (array))
return array;
}
return NULL;
}
static grub_err_t
grub_raid_open (const char *name, grub_disk_t disk)
{
struct grub_raid_array *array;
unsigned n;
if (grub_memcmp (name, "md", sizeof ("md") - 1) != 0)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
name);
array = find_array (name);
if (! array)
{
scan_devices (name);
if (grub_errno)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
}
array = find_array (name);
}
if (!array)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
name);
disk->id = array->number;
disk->data = array;
grub_dprintf ("raid", "%s: total_devs=%d, disk_size=%lld\n", name,
array->total_devs, (unsigned long long) array->disk_size);
switch (array->level)
{
case 1:
disk->total_sectors = array->disk_size;
break;
case 10:
n = array->layout & 0xFF;
if (n == 1)
n = (array->layout >> 8) & 0xFF;
disk->total_sectors = grub_divmod64 (array->total_devs *
array->disk_size,
n, 0);
break;
case 0:
case 4:
case 5:
case 6:
n = array->level / 3;
disk->total_sectors = (array->total_devs - n) * array->disk_size;
break;
}
grub_dprintf ("raid", "%s: level=%d, total_sectors=%lld\n", name,
array->level, (unsigned long long) disk->total_sectors);
return 0;
}
static void
grub_raid_close (grub_disk_t disk __attribute ((unused)))
{
return;
}
static grub_err_t
grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector,
grub_size_t size, char *buf)
{
struct grub_raid_array *array = disk->data;
grub_err_t err = 0;
switch (array->level)
{
case 0:
case 1:
case 10:
{
grub_disk_addr_t read_sector, far_ofs;
grub_uint64_t disknr, b, near, far, ofs;
read_sector = grub_divmod64 (sector, array->chunk_size, &b);
far = ofs = near = 1;
far_ofs = 0;
if (array->level == 1)
near = array->total_devs;
else if (array->level == 10)
{
near = array->layout & 0xFF;
far = (array->layout >> 8) & 0xFF;
if (array->layout >> 16)
{
ofs = far;
far_ofs = 1;
}
else
far_ofs = grub_divmod64 (array->disk_size,
far * array->chunk_size, 0);
far_ofs *= array->chunk_size;
}
read_sector = grub_divmod64 (read_sector * near, array->total_devs,
&disknr);
ofs *= array->chunk_size;
read_sector *= ofs;
while (1)
{
grub_size_t read_size;
unsigned int i, j;
read_size = array->chunk_size - b;
if (read_size > size)
read_size = size;
for (i = 0; i < near; i++)
{
unsigned int k;
k = disknr;
for (j = 0; j < far; j++)
{
if (array->members[k].device)
{
if (grub_errno == GRUB_ERR_READ_ERROR)
grub_errno = GRUB_ERR_NONE;
err = grub_disk_read (array->members[k].device,
array->members[k].start_sector +
read_sector + j * far_ofs + b,
0,
read_size << GRUB_DISK_SECTOR_BITS,
buf);
if (! err)
break;
else if (err != GRUB_ERR_READ_ERROR)
return err;
}
else
err = grub_error (GRUB_ERR_READ_ERROR,
"disk missing");
k++;
if (k == array->total_devs)
k = 0;
}
if (! err)
break;
disknr++;
if (disknr == array->total_devs)
{
disknr = 0;
read_sector += ofs;
}
}
if (err)
return err;
buf += read_size << GRUB_DISK_SECTOR_BITS;
size -= read_size;
if (! size)
break;
b = 0;
disknr += (near - i);
while (disknr >= array->total_devs)
{
disknr -= array->total_devs;
read_sector += ofs;
}
}
break;
}
case 4:
case 5:
case 6:
{
grub_disk_addr_t read_sector;
grub_uint64_t b, p, n, disknr, e;
/* n = 1 for level 4 and 5, 2 for level 6. */
n = array->level / 3;
/* Find the first sector to read. */
read_sector = grub_divmod64 (sector, array->chunk_size, &b);
read_sector = grub_divmod64 (read_sector, array->total_devs - n,
&disknr);
if (array->level >= 5)
{
grub_divmod64 (read_sector, array->total_devs, &p);
if (! (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK))
p = array->total_devs - 1 - p;
if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
{
disknr += p + n;
}
else
{
grub_uint32_t q;
q = p + (n - 1);
if (q >= array->total_devs)
q -= array->total_devs;
if (disknr >= p)
disknr += n;
else if (disknr >= q)
disknr += q + 1;
}
if (disknr >= array->total_devs)
disknr -= array->total_devs;
}
else
p = array->total_devs - n;
read_sector *= array->chunk_size;
while (1)
{
grub_size_t read_size;
int next_level;
read_size = array->chunk_size - b;
if (read_size > size)
read_size = size;
e = 0;
if (array->members[disknr].device)
{
/* Reset read error. */
if (grub_errno == GRUB_ERR_READ_ERROR)
grub_errno = GRUB_ERR_NONE;
err = grub_disk_read (array->members[disknr].device,
array->members[disknr].start_sector +
read_sector + b, 0,
read_size << GRUB_DISK_SECTOR_BITS,
buf);
if ((err) && (err != GRUB_ERR_READ_ERROR))
break;
e++;
}
else
err = GRUB_ERR_READ_ERROR;
if (err)
{
if (array->nr_devs < array->total_devs - n + e)
break;
grub_errno = GRUB_ERR_NONE;
if (array->level == 6)
{
err = ((grub_raid6_recover_func) ?
(*grub_raid6_recover_func) (array, disknr, p,
buf, read_sector + b,
read_size) :
grub_error (GRUB_ERR_BAD_DEVICE,
"raid6rec is not loaded"));
}
else
{
err = ((grub_raid5_recover_func) ?
(*grub_raid5_recover_func) (array, disknr,
buf, read_sector + b,
read_size) :
grub_error (GRUB_ERR_BAD_DEVICE,
"raid5rec is not loaded"));
}
if (err)
break;
}
buf += read_size << GRUB_DISK_SECTOR_BITS;
size -= read_size;
if (! size)
break;
b = 0;
disknr++;
if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
{
if (disknr == array->total_devs)
disknr = 0;
next_level = (disknr == p);
}
else
{
if (disknr == p)
disknr += n;
next_level = (disknr >= array->total_devs);
}
if (next_level)
{
read_sector += array->chunk_size;
if (array->level >= 5)
{
if (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK)
p = (p == array->total_devs - 1) ? 0 : p + 1;
else
p = (p == 0) ? array->total_devs - 1 : p - 1;
if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
{
disknr = p + n;
if (disknr >= array->total_devs)
disknr -= array->total_devs;
}
else
{
disknr -= array->total_devs;
if (disknr == p)
disknr += n;
}
}
else
disknr = 0;
}
}
}
break;
}
return err;
}
static grub_err_t
grub_raid_write (grub_disk_t disk __attribute ((unused)),
grub_disk_addr_t sector __attribute ((unused)),
grub_size_t size __attribute ((unused)),
const char *buf __attribute ((unused)))
{
return GRUB_ERR_NOT_IMPLEMENTED_YET;
}
static grub_err_t
insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
grub_disk_addr_t start_sector, const char *scanner_name,
grub_raid_t raid __attribute__ ((unused)))
{
struct grub_raid_array *array = 0, *p;
int was_readable = 0;
/* See whether the device is part of an array we have already seen a
device from. */
for (p = array_list; p != NULL; p = p->next)
if ((p->uuid_len == new_array->uuid_len) &&
(! grub_memcmp (p->uuid, new_array->uuid, p->uuid_len)))
{
grub_free (new_array->uuid);
array = p;
was_readable = grub_is_array_readable (array);
/* Do some checks before adding the device to the array. */
if (new_array->index >= array->allocated_devs)
{
void *tmp;
unsigned int newnum = 2 * (new_array->index + 1);
tmp = grub_realloc (array->members, newnum
* sizeof (array->members[0]));
if (!tmp)
return grub_errno;
array->members = tmp;
grub_memset (array->members + array->allocated_devs,
0, (newnum - array->allocated_devs)
* sizeof (array->members[0]));
array->allocated_devs = newnum;
}
/* FIXME: Check whether the update time of the superblocks are
the same. */
if (array->total_devs == array->nr_devs)
/* We found more members of the array than the array
actually has according to its superblock. This shouldn't
happen normally. */
return grub_error (GRUB_ERR_BAD_DEVICE,
"superfluous RAID member (%d found)",
array->total_devs);
if (array->members[new_array->index].device != NULL)
/* We found multiple devices with the same number. Again,
this shouldn't happen. */
return grub_error (GRUB_ERR_BAD_DEVICE,
"found two disks with the index %d for RAID %s",
new_array->index, array->name);
if (new_array->disk_size < array->disk_size)
array->disk_size = new_array->disk_size;
break;
}
/* Add an array to the list if we didn't find any. */
if (!array)
{
array = grub_malloc (sizeof (*array));
if (!array)
{
grub_free (new_array->uuid);
return grub_errno;
}
*array = *new_array;
array->nr_devs = 0;
#ifdef GRUB_UTIL
array->driver = raid;
#endif
array->allocated_devs = 32;
if (new_array->index >= array->allocated_devs)
array->allocated_devs = 2 * (new_array->index + 1);
array->members = grub_zalloc (array->allocated_devs
* sizeof (array->members[0]));
if (!array->members)
{
grub_free (new_array->uuid);
return grub_errno;
}
if (! array->name)
{
for (p = array_list; p != NULL; p = p->next)
{
if (p->number == array->number)
break;
}
}
if (array->name || p)
{
/* The number is already in use, so we need to find a new one.
(Or, in the case of named arrays, the array doesn't have its
own number, but we need one that doesn't clash for use as a key
in the disk cache. */
int i = array->name ? 0x40000000 : 0;
while (1)
{
for (p = array_list; p != NULL; p = p->next)
{
if (p->number == i)
break;
}
if (! p)
{
/* We found an unused number. */
array->number = i;
break;
}
i++;
}
}
/* mdraid 1.x superblocks have only a name stored not a number.
Use it directly as GRUB device. */
if (! array->name)
{
array->name = grub_xasprintf ("md%d", array->number);
if (! array->name)
{
grub_free (array->members);
grub_free (array->uuid);
grub_free (array);
return grub_errno;
}
}
else
{
/* Strip off the homehost if present. */
char *colon = grub_strchr (array->name, ':');
char *new_name = grub_xasprintf ("md/%s",
colon ? colon + 1 : array->name);
if (! new_name)
{
grub_free (array->members);
grub_free (array->uuid);
grub_free (array);
return grub_errno;
}
grub_free (array->name);
array->name = new_name;
}
grub_dprintf ("raid", "Found array %s (%s)\n", array->name,
scanner_name);
#ifdef GRUB_UTIL
grub_util_info ("Found array %s (%s)", array->name,
scanner_name);
#endif
{
int max_used_number = 0, len, need_new_name = 0;
int add_us = 0;
len = grub_strlen (array->name);
if (len && grub_isdigit (array->name[len-1]))
add_us = 1;
for (p = array_list; p != NULL; p = p->next)
{
int cur_num;
char *num, *end;
if (grub_strncmp (p->name, array->name, len) != 0)
continue;
if (p->name[len] == 0)
{
need_new_name = 1;
continue;
}
if (add_us && p->name[len] != '_')
continue;
if (add_us)
num = p->name + len + 1;
else
num = p->name + len;
if (!grub_isdigit (num[0]))
continue;
cur_num = grub_strtoull (num, &end, 10);
if (end[0])
continue;
if (cur_num > max_used_number)
max_used_number = cur_num;
}
if (need_new_name)
{
char *tmp;
tmp = grub_xasprintf ("%s%s%d", array->name, add_us ? "_" : "",
max_used_number + 1);
if (!tmp)
return grub_errno;
grub_free (array->name);
array->name = tmp;
}
}
/* Add our new array to the list. */
array->next = array_list;
array_list = array;
/* RAID 1 doesn't use a chunksize but code assumes one so set
one. */
if (array->level == 1)
array->chunk_size = 64;
}
/* Add the device to the array. */
array->members[new_array->index].device = disk;
array->members[new_array->index].start_sector = start_sector;
array->nr_devs++;
if (!was_readable && grub_is_array_readable (array))
array->became_readable_at = inscnt++;
return 0;
}
static void
free_array (void)
{
struct grub_raid_array *array;
array = array_list;
while (array)
{
struct grub_raid_array *p;
unsigned int i;
p = array;
array = array->next;
for (i = 0; i < p->allocated_devs; i++)
if (p->members[i].device)
grub_disk_close (p->members[i].device);
grub_free (p->members);
grub_free (p->uuid);
grub_free (p->name);
grub_free (p);
}
array_list = 0;
}
void
grub_raid_register (grub_raid_t raid)
{
raid->next = grub_raid_list;
grub_raid_list = raid;
}
void
grub_raid_unregister (grub_raid_t raid)
{
grub_raid_t *p, q;
for (p = &grub_raid_list, q = *p; q; p = &(q->next), q = q->next)
if (q == raid)
{
*p = q->next;
break;
}
}
static struct grub_disk_dev grub_raid_dev =
{
.name = "raid",
.id = GRUB_DISK_DEVICE_RAID_ID,
.iterate = grub_raid_iterate,
.open = grub_raid_open,
.close = grub_raid_close,
.read = grub_raid_read,
.write = grub_raid_write,
#ifdef GRUB_UTIL
.memberlist = grub_raid_memberlist,
.raidname = grub_raid_getname,
#endif
.next = 0
};
GRUB_MOD_INIT(raid)
{
grub_disk_dev_register (&grub_raid_dev);
}
GRUB_MOD_FINI(raid)
{
grub_disk_dev_unregister (&grub_raid_dev);
free_array ();
}

View file

@ -22,13 +22,13 @@
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/raid.h>
#include <grub/diskfilter.h>
#include <grub/crypto.h>
GRUB_MOD_LICENSE ("GPLv3+");
static grub_err_t
grub_raid5_recover (struct grub_raid_array *array, int disknr,
grub_raid5_recover (struct grub_diskfilter_segment *array, int disknr,
char *buf, grub_disk_addr_t sector, int size)
{
char *buf2;
@ -41,16 +41,15 @@ grub_raid5_recover (struct grub_raid_array *array, int disknr,
grub_memset (buf, 0, size);
for (i = 0; i < (int) array->total_devs; i++)
for (i = 0; i < (int) array->node_count; i++)
{
grub_err_t err;
if (i == disknr)
continue;
err = grub_disk_read (array->members[i].device,
array->members[i].start_sector + sector,
0, size, buf2);
err = grub_diskfilter_read_node (&array->nodes[i], sector,
size >> GRUB_DISK_SECTOR_BITS, buf2);
if (err)
{
@ -58,7 +57,7 @@ grub_raid5_recover (struct grub_raid_array *array, int disknr,
return err;
}
grub_crypto_xor (buf, buf2, buf2, size);
grub_crypto_xor (buf, buf, buf2, size);
}
grub_free (buf2);

View file

@ -22,7 +22,7 @@
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
#include <grub/raid.h>
#include <grub/diskfilter.h>
#include <grub/crypto.h>
GRUB_MOD_LICENSE ("GPLv3+");
@ -64,7 +64,7 @@ grub_raid6_init_table (void)
}
static grub_err_t
grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
grub_raid6_recover (struct grub_diskfilter_segment *array, int disknr, int p,
char *buf, grub_disk_addr_t sector, int size)
{
int i, q, pos;
@ -81,26 +81,29 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
goto quit;
q = p + 1;
if (q == (int) array->total_devs)
if (q == (int) array->node_count)
q = 0;
pos = q + 1;
if (pos == (int) array->total_devs)
if (pos == (int) array->node_count)
pos = 0;
for (i = 0; i < (int) array->total_devs - 2; i++)
for (i = 0; i < (int) array->node_count - 2; i++)
{
int c;
if (array->layout & GRUB_RAID_LAYOUT_MUL_FROM_POS)
c = pos;
else
c = i;
if (pos == disknr)
bad1 = i;
bad1 = c;
else
{
if ((array->members[pos].device) &&
(! grub_disk_read (array->members[pos].device,
array->members[pos].start_sector + sector,
0, size, buf)))
if (! grub_diskfilter_read_node (&array->nodes[pos], sector,
size >> GRUB_DISK_SECTOR_BITS, buf))
{
grub_crypto_xor (pbuf, pbuf, buf, size);
grub_raid_block_mulx (i, buf, size);
grub_raid_block_mulx (c, buf, size);
grub_crypto_xor (qbuf, qbuf, buf, size);
}
else
@ -109,13 +112,13 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
if (bad2 >= 0)
goto quit;
bad2 = i;
bad2 = c;
grub_errno = GRUB_ERR_NONE;
}
}
pos++;
if (pos == (int) array->total_devs)
if (pos == (int) array->node_count)
pos = 0;
}
@ -126,24 +129,16 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
if (bad2 < 0)
{
/* One bad device */
if ((array->members[p].device) &&
(! grub_disk_read (array->members[p].device,
array->members[p].start_sector + sector,
0, size, buf)))
if ((! grub_diskfilter_read_node (&array->nodes[p], sector,
size >> GRUB_DISK_SECTOR_BITS, buf)))
{
grub_crypto_xor (buf, buf, pbuf, size);
goto quit;
}
if (! array->members[q].device)
{
grub_error (GRUB_ERR_READ_ERROR, "not enough disk to restore");
goto quit;
}
grub_errno = GRUB_ERR_NONE;
if (grub_disk_read (array->members[q].device,
array->members[q].start_sector + sector, 0, size, buf))
if (grub_diskfilter_read_node (&array->nodes[q], sector,
size >> GRUB_DISK_SECTOR_BITS, buf))
goto quit;
grub_crypto_xor (buf, buf, qbuf, size);
@ -155,22 +150,14 @@ grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
/* Two bad devices */
int c;
if ((! array->members[p].device) || (! array->members[q].device))
{
grub_error (GRUB_ERR_READ_ERROR, "not enough disk to restore");
goto quit;
}
if (grub_disk_read (array->members[p].device,
array->members[p].start_sector + sector,
0, size, buf))
if (grub_diskfilter_read_node (&array->nodes[p], sector,
size >> GRUB_DISK_SECTOR_BITS, buf))
goto quit;
grub_crypto_xor (pbuf, pbuf, buf, size);
if (grub_disk_read (array->members[q].device,
array->members[q].start_sector + sector,
0, size, buf))
if (grub_diskfilter_read_node (&array->nodes[q], sector,
size >> GRUB_DISK_SECTOR_BITS, buf))
goto quit;
grub_crypto_xor (qbuf, qbuf, buf, size);