DDF: layout_md2ddf: new md->DDF layout conversion

Support for RAID 10 makes it necessary to rewrite the algorithm
for deriving DDF layout from MD layout. The functions level_to_prl
and layout_to_rlq are combined in a single function that takes
md layout parameters and converts them to DDF.

Signed-off-by: Martin Wilck <mwilck@arcor.de>
Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
mwilck@arcor.de 2013-07-03 22:27:52 +02:00 committed by NeilBrown
parent 8a2848a700
commit a3163bf069
1 changed files with 117 additions and 82 deletions

View File

@ -484,6 +484,110 @@ static unsigned int calc_crc(void *buf, int len)
return __cpu_to_be32(newcrc);
}
#define DDF_INVALID_LEVEL 0xff
#define DDF_NO_SECONDARY 0xff
static int err_bad_md_layout(const mdu_array_info_t *array)
{
pr_err("RAID%d layout %x with %d disks is unsupported for DDF\n",
array->level, array->layout, array->raid_disks);
return DDF_INVALID_LEVEL;
}
static int layout_md2ddf(const mdu_array_info_t *array,
struct vd_config *conf)
{
__u16 prim_elmnt_count = __cpu_to_be16(array->raid_disks);
__u8 prl = DDF_INVALID_LEVEL, rlq = 0;
__u8 sec_elmnt_count = 1;
__u8 srl = DDF_NO_SECONDARY;
switch (array->level) {
case LEVEL_LINEAR:
prl = DDF_CONCAT;
break;
case 0:
rlq = DDF_RAID0_SIMPLE;
prl = DDF_RAID0;
break;
case 1:
switch (array->raid_disks) {
case 2:
rlq = DDF_RAID1_SIMPLE;
break;
case 3:
rlq = DDF_RAID1_MULTI;
break;
default:
return err_bad_md_layout(array);
}
prl = DDF_RAID1;
break;
case 4:
if (array->layout != 0)
return err_bad_md_layout(array);
rlq = DDF_RAID4_N;
prl = DDF_RAID4;
break;
case 5:
switch (array->layout) {
case ALGORITHM_LEFT_ASYMMETRIC:
rlq = DDF_RAID5_N_RESTART;
break;
case ALGORITHM_RIGHT_ASYMMETRIC:
rlq = DDF_RAID5_0_RESTART;
break;
case ALGORITHM_LEFT_SYMMETRIC:
rlq = DDF_RAID5_N_CONTINUE;
break;
case ALGORITHM_RIGHT_SYMMETRIC:
/* not mentioned in standard */
default:
return err_bad_md_layout(array);
}
prl = DDF_RAID5;
break;
case 6:
switch (array->layout) {
case ALGORITHM_ROTATING_N_RESTART:
rlq = DDF_RAID5_N_RESTART;
break;
case ALGORITHM_ROTATING_ZERO_RESTART:
rlq = DDF_RAID6_0_RESTART;
break;
case ALGORITHM_ROTATING_N_CONTINUE:
rlq = DDF_RAID5_N_CONTINUE;
break;
default:
return err_bad_md_layout(array);
}
prl = DDF_RAID6;
break;
case 10:
if (array->raid_disks % 2 == 0 && array->layout == 0x102) {
rlq = DDF_RAID1_SIMPLE;
prim_elmnt_count = __cpu_to_be16(2);
sec_elmnt_count = array->raid_disks / 2;
} else if (array->raid_disks % 3 == 0
&& array->layout == 0x103) {
rlq = DDF_RAID1_MULTI;
prim_elmnt_count = __cpu_to_be16(3);
sec_elmnt_count = array->raid_disks / 3;
} else
return err_bad_md_layout(array);
srl = DDF_2SPANNED;
prl = DDF_RAID1;
break;
default:
return err_bad_md_layout(array);
}
conf->prl = prl;
conf->prim_elmnt_count = prim_elmnt_count;
conf->rlq = rlq;
conf->srl = srl;
conf->sec_elmnt_count = sec_elmnt_count;
return 0;
}
static int err_bad_ddf_layout(const struct vd_config *conf)
{
pr_err("DDF RAID %u qualifier %u with %u disks is unsupported\n",
@ -1128,24 +1232,6 @@ static mapping_t ddf_sec_level[] = {
};
#endif
struct num_mapping {
int num1, num2;
};
static struct num_mapping ddf_level_num[] = {
{ DDF_RAID0, 0 },
{ DDF_RAID1, 1 },
{ DDF_RAID3, LEVEL_UNSUPPORTED },
{ DDF_RAID4, 4 },
{ DDF_RAID5, 5 },
{ DDF_RAID1E, LEVEL_UNSUPPORTED },
{ DDF_JBOD, LEVEL_UNSUPPORTED },
{ DDF_CONCAT, LEVEL_LINEAR },
{ DDF_RAID5E, LEVEL_UNSUPPORTED },
{ DDF_RAID5EE, LEVEL_UNSUPPORTED },
{ DDF_RAID6, 6},
{ MAXINT, MAXINT }
};
static int all_ff(const char *guid)
{
int i;
@ -2168,59 +2254,6 @@ static int chunk_to_shift(int chunksize)
return ffs(chunksize/512)-1;
}
static int level_to_prl(int level)
{
switch (level) {
case LEVEL_LINEAR: return DDF_CONCAT;
case 0: return DDF_RAID0;
case 1: return DDF_RAID1;
case 4: return DDF_RAID4;
case 5: return DDF_RAID5;
case 6: return DDF_RAID6;
default: return -1;
}
}
static int layout_to_rlq(int level, int layout, int raiddisks)
{
switch(level) {
case 0:
return DDF_RAID0_SIMPLE;
case 1:
switch(raiddisks) {
case 2: return DDF_RAID1_SIMPLE;
case 3: return DDF_RAID1_MULTI;
default: return -1;
}
case 4:
switch(layout) {
case 0: return DDF_RAID4_N;
}
break;
case 5:
switch(layout) {
case ALGORITHM_LEFT_ASYMMETRIC:
return DDF_RAID5_N_RESTART;
case ALGORITHM_RIGHT_ASYMMETRIC:
return DDF_RAID5_0_RESTART;
case ALGORITHM_LEFT_SYMMETRIC:
return DDF_RAID5_N_CONTINUE;
case ALGORITHM_RIGHT_SYMMETRIC:
return -1; /* not mentioned in standard */
}
case 6:
switch(layout) {
case ALGORITHM_ROTATING_N_RESTART:
return DDF_RAID5_N_RESTART;
case ALGORITHM_ROTATING_ZERO_RESTART:
return DDF_RAID6_0_RESTART;
case ALGORITHM_ROTATING_N_CONTINUE:
return DDF_RAID5_N_CONTINUE;
}
}
return -1;
}
#ifndef MDASSEMBLE
struct extent {
unsigned long long start, size;
@ -2338,13 +2371,15 @@ static int init_super_ddf_bvd(struct supertype *st,
vc->timestamp = __cpu_to_be32(time(0)-DECADE);
vc->seqnum = __cpu_to_be32(1);
memset(vc->pad0, 0xff, 24);
vc->prim_elmnt_count = __cpu_to_be16(info->raid_disks);
vc->chunk_shift = chunk_to_shift(info->chunk_size);
vc->prl = level_to_prl(info->level);
vc->rlq = layout_to_rlq(info->level, info->layout, info->raid_disks);
vc->sec_elmnt_count = 1;
if (layout_md2ddf(info, vc) == -1 ||
__be16_to_cpu(vc->prim_elmnt_count) > ddf->mppe) {
pr_err("%s: unsupported RAID level/layout %d/%d with %d disks\n",
__func__, info->level, info->layout, info->raid_disks);
free(vcl);
return 0;
}
vc->sec_elmnt_seq = 0;
vc->srl = 0;
vc->blocks = __cpu_to_be64(info->size * 2);
vc->array_blocks = __cpu_to_be64(
calc_array_size(info->level, info->raid_disks, info->layout,
@ -3008,12 +3043,12 @@ static int validate_geometry_ddf(struct supertype *st,
}
if (!dev) {
/* Initial sanity check. Exclude illegal levels. */
int i;
for (i=0; ddf_level_num[i].num1 != MAXINT; i++)
if (ddf_level_num[i].num2 == level)
break;
if (ddf_level_num[i].num1 == MAXINT) {
mdu_array_info_t array = {
.level = level, .layout = layout,
.raid_disks = raiddisks
};
struct vd_config conf;
if (layout_md2ddf(&array, &conf) == -1) {
if (verbose)
pr_err("DDF does not support level %d arrays\n",
level);