* Couple changes for Linux raid metadata 1.x support
@ 2010-07-23 21:02 Doug Nazar
0 siblings, 0 replies; only message in thread
From: Doug Nazar @ 2010-07-23 21:02 UTC (permalink / raw)
To: grub-devel
[-- Attachment #1: Type: text/plain, Size: 495 bytes --]
Strange timing. I ran into needing support for 1.2 metadata a few days
ago. Wrote the code yesterday and when I pulled to check for conflicts
before I submitted someone else had also just written the code.
Here are a few changes I had that are not in the tree:
- Don't use disks with outdated superblocks
- Don't use disks that are being rebuilt/transfomed
- Check superblock checksums
- Check superblock is in the correct location
- Update the recovery code to use the start_sector
Doug
[-- Attachment #2: grub-update-raid-metadata-1x-support.diff --]
[-- Type: text/plain, Size: 8713 bytes --]
=== modified file 'disk/dmraid_nvidia.c'
--- disk/dmraid_nvidia.c 2010-07-18 17:31:10 +0000
+++ disk/dmraid_nvidia.c 2010-07-23 03:23:14 +0000
@@ -137,6 +137,7 @@
array->number = 0;
array->total_devs = sb.array.total_volumes;
array->chunk_size = sb.array.stripe_block_size;
+ array->freshness = 0;
array->index = sb.unit_number;
array->uuid_len = sizeof (sb.array.signature);
array->uuid = grub_malloc (sizeof (sb.array.signature));
=== modified file 'disk/mdraid_linux.c'
--- disk/mdraid_linux.c 2010-07-20 10:10:49 +0000
+++ disk/mdraid_linux.c 2010-07-23 05:22:12 +0000
@@ -229,6 +229,10 @@
are already appropriately aligned, we can omit this and avoid suboptimal
assembly in some cases. */
+#define MD_FEATURE_BITMAP_OFFSET 1
+#define MD_FEATURE_RECOVERY_OFFSET 2
+#define MD_FEATURE_RESHAPE_ACTIVE 4
+
#define WriteMostly1 1 /* Mask for writemostly flag in above devflags. */
static grub_err_t
@@ -262,6 +266,7 @@
array->total_devs = sb->raid_disks;
array->disk_size = (sb->size) ? sb->size * 2 : sector;
array->chunk_size = sb->chunk_size >> 9;
+ array->freshness = sb->events;
array->index = sb->this_disk.number;
array->uuid_len = 16;
array->uuid = grub_malloc (16);
@@ -279,6 +284,31 @@
return 0;
}
+static grub_uint32_t
+grub_mdraid_calc_csum(struct grub_raid_super_1x * sb)
+{
+ grub_uint32_t disk_csum;
+ grub_uint32_t csum;
+ grub_uint64_t newcsum;
+ int size = 256 + sb->max_dev*2;
+ grub_uint32_t *isuper = (grub_uint32_t*)sb;
+ int i;
+
+ disk_csum = sb->sb_csum;
+ sb->sb_csum = 0;
+ newcsum = 0;
+ for (i=0; size>=4; size -= 4 )
+ newcsum += *isuper++;
+
+ if (size == 2)
+ newcsum += *(grub_uint16_t*) isuper;
+
+ csum = (newcsum & 0xffffffff) + (newcsum >> 32);
+ sb->sb_csum = disk_csum;
+
+ return csum;
+}
+
static grub_err_t
grub_mdraid_detect_1x (grub_disk_t disk, grub_disk_addr_t sector,
struct grub_raid_super_1x *sb,
@@ -293,6 +323,18 @@
"Unsupported RAID version: %d",
sb->major_version);
+ if (sb->super_offset != sector)
+ /* We're not where we're supposed to be. Usually caused by a 1.0
+ superblock at the end of a disk with a single large partition. */
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "wrong superblock location");
+
+ if (sb->feature_map & MD_FEATURE_RECOVERY_OFFSET)
+ /* Disk is currently being recovered. Silently ignore it. */
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "recovery in progress");
+
+ if (sb->feature_map & MD_FEATURE_RESHAPE_ACTIVE)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "reshape active");
+
/* Multipath. */
if ((int) sb->level == -4)
sb->level = 1;
@@ -315,6 +357,12 @@
return grub_errno;
}
+ if (grub_mdraid_calc_csum(real_sb) != real_sb->sb_csum)
+ {
+ grub_free (real_sb);
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "csum invalid");
+ }
+
array->name = grub_strdup (real_sb->set_name);
if (! array->name)
{
@@ -328,6 +376,7 @@
array->total_devs = grub_le_to_cpu32 (real_sb->raid_disks);
array->disk_size = grub_le_to_cpu64 (real_sb->size);
array->chunk_size = grub_le_to_cpu32 (real_sb->chunksize);
+ array->freshness = grub_le_to_cpu32(real_sb->events);
if (grub_le_to_cpu32 (real_sb->dev_number) <
grub_le_to_cpu32 (real_sb->max_dev))
array->index = grub_le_to_cpu16
=== modified file 'disk/raid.c'
--- disk/raid.c 2010-07-22 08:38:06 +0000
+++ disk/raid.c 2010-07-23 05:22:34 +0000
@@ -130,8 +130,8 @@
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);
+ grub_dprintf ("raid", "%s: total_devs=%d, nr_devs=%d, disk_size=%lld\n", name,
+ array->total_devs, array->nr_devs, (unsigned long long) array->disk_size);
switch (array->level)
{
@@ -495,21 +495,48 @@
/* FIXME: Check whether the update time of the superblocks are
the same. */
+ if (new_array->freshness < array->freshness)
+ {
+ /* This disk is outdated. Don't add it to the array. */
+ grub_dprintf ("raid", "member '%s' is not fresh: disk: %llu, array: %llu\n",
+ disk->name, new_array->freshness, array->freshness);
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "disk not fresh");
+ }
+
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. */
- grub_dprintf ("raid", "array->nr_devs > array->total_devs (%d)?!?",
+ grub_dprintf ("raid", "array->nr_devs > array->total_devs (%d)?!?\n",
array->total_devs);
if (array->device[new_array->index] != NULL)
/* We found multiple devices with the same number. Again,
this shouldn't happen. */
- grub_dprintf ("raid", "Found two disks with the number %d?!?",
+ grub_dprintf ("raid", "Found two disks with the number %d?!?\n",
new_array->number);
if (new_array->disk_size < array->disk_size)
array->disk_size = new_array->disk_size;
+
+ if (new_array->freshness > array->freshness)
+ {
+ int i;
+
+ /* Kick out all already found array members that are outdated */
+ for (i = 0; i < GRUB_RAID_MAX_DEVICES; i++)
+ if (array->device[i])
+ {
+ grub_dprintf ("raid", "member '%s' is not fresh: disk: %llu, array: %llu\n",
+ array->device[i]->name, array->freshness, new_array->freshness);
+ grub_disk_close (array->device[i]);
+ array->device[i] = 0;
+ array->nr_devs--;
+ }
+
+ array->freshness = new_array->freshness;
+ }
+
break;
}
=== modified file 'disk/raid5_recover.c'
--- disk/raid5_recover.c 2009-07-31 04:38:20 +0000
+++ disk/raid5_recover.c 2010-07-23 05:22:46 +0000
@@ -45,7 +45,8 @@
if (i == disknr)
continue;
- err = grub_disk_read (array->device[i], sector, 0, size, buf2);
+ err = grub_disk_read (array->device[i],
+ array->start_sector[i] + sector, 0, size, buf2);
if (err)
{
=== modified file 'disk/raid6_recover.c'
--- disk/raid6_recover.c 2010-01-03 22:05:07 +0000
+++ disk/raid6_recover.c 2010-07-23 05:23:13 +0000
@@ -119,7 +119,9 @@
else
{
if ((array->device[pos]) &&
- (! grub_disk_read (array->device[pos], sector, 0, size, buf)))
+ (! grub_disk_read (array->device[pos],
+ array->start_sector[pos] + sector,
+ 0, size, buf)))
{
grub_raid_block_xor (pbuf, buf, size);
grub_raid_block_mul (raid6_table2[i][i], buf, size);
@@ -149,7 +151,8 @@
{
/* One bad device */
if ((array->device[p]) &&
- (! grub_disk_read (array->device[p], sector, 0, size, buf)))
+ (! grub_disk_read (array->device[p],
+ array->start_sector[p] + sector, 0, size, buf)))
{
grub_raid_block_xor (buf, pbuf, size);
goto quit;
@@ -162,7 +165,8 @@
}
grub_errno = GRUB_ERR_NONE;
- if (grub_disk_read (array->device[q], sector, 0, size, buf))
+ if (grub_disk_read (array->device[q], array->start_sector[q] + sector,
+ 0, size, buf))
goto quit;
grub_raid_block_xor (buf, qbuf, size);
@@ -180,12 +184,14 @@
goto quit;
}
- if (grub_disk_read (array->device[p], sector, 0, size, buf))
+ if (grub_disk_read (array->device[p], array->start_sector[p] + sector,
+ 0, size, buf))
goto quit;
grub_raid_block_xor (pbuf, buf, size);
- if (grub_disk_read (array->device[q], sector, 0, size, buf))
+ if (grub_disk_read (array->device[q], array->start_sector[q] + sector,
+ 0, size, buf))
goto quit;
grub_raid_block_xor (qbuf, buf, size);
=== modified file 'include/grub/raid.h'
--- include/grub/raid.h 2010-07-20 10:10:49 +0000
+++ include/grub/raid.h 2010-07-23 04:31:24 +0000
@@ -43,6 +43,8 @@
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_uint64_t freshness; /* Indicator of freshness of disk. All valid
+ devices will have the same highest number */
int index; /* Index of current device. */
int uuid_len; /* The length of uuid. */
char *uuid; /* The UUID of the device. */
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2010-07-25 13:57 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-07-23 21:02 Couple changes for Linux raid metadata 1.x support Doug Nazar
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.