DDF: use existing locations for primary and secondary DDF structure

Some RAID BIOSes apparently use hard-coded LBA offsets (presumably
from the end of the disk) for the primary and secondary DDF
structure, ignoring the values given in the DDF anchor. This is
broken BIOS behavior, but it will cause any changes made by MD
(e.g. setting the init_state flag after a full initialization)
to be "forgotten" after the next reboot.

This patch fixes this by using the exiting LBA locations if
available. Verified that this fixes MD+LSI Mega Software RAID
BIOS.

Signed-off-by: Martin Wilck <mwilck@arcor.de>
Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
mwilck@arcor.de 2013-03-01 23:28:23 +01:00 committed by NeilBrown
parent 7f798aca5b
commit 097bcf0057
1 changed files with 25 additions and 3 deletions

View File

@ -421,6 +421,9 @@ struct ddf_super {
char *devname;
int fd;
unsigned long long size; /* sectors */
unsigned long long primary_lba; /* sectors */
unsigned long long secondary_lba; /* sectors */
unsigned long long workspace_lba; /* sectors */
int pdnum; /* index in ->phys */
struct spare_assign *spare;
void *mdupdate; /* hold metadata update */
@ -668,6 +671,13 @@ static int load_ddf_local(int fd, struct ddf_super *super,
dl->size = 0;
if (get_dev_size(fd, devname, &dsize))
dl->size = dsize >> 9;
/* If the disks have different sizes, the LBAs will differ
* between phys disks.
* At this point here, the values in super->active must be valid
* for this phys disk. */
dl->primary_lba = super->active->primary_lba;
dl->secondary_lba = super->active->secondary_lba;
dl->workspace_lba = super->active->workspace_lba;
dl->spare = NULL;
for (i = 0 ; i < super->max_part ; i++)
dl->vlist[i] = NULL;
@ -2422,9 +2432,21 @@ static int __write_init_super_ddf(struct supertype *st)
*/
get_dev_size(fd, NULL, &size);
size /= 512;
ddf->anchor.workspace_lba = __cpu_to_be64(size - 32*1024*2);
ddf->anchor.primary_lba = __cpu_to_be64(size - 16*1024*2);
ddf->anchor.secondary_lba = __cpu_to_be64(size - 31*1024*2);
if (d->workspace_lba != 0)
ddf->anchor.workspace_lba = d->workspace_lba;
else
ddf->anchor.workspace_lba =
__cpu_to_be64(size - 32*1024*2);
if (d->primary_lba != 0)
ddf->anchor.primary_lba = d->primary_lba;
else
ddf->anchor.primary_lba =
__cpu_to_be64(size - 16*1024*2);
if (d->secondary_lba != 0)
ddf->anchor.secondary_lba = d->secondary_lba;
else
ddf->anchor.secondary_lba =
__cpu_to_be64(size - 32*1024*2);
ddf->anchor.seq = __cpu_to_be32(1);
memcpy(&ddf->primary, &ddf->anchor, 512);
memcpy(&ddf->secondary, &ddf->anchor, 512);