summaryrefslogtreecommitdiffstats
path: root/sys/geom/raid
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2012-05-06 11:32:36 +0000
committermav <mav@FreeBSD.org>2012-05-06 11:32:36 +0000
commit3d44dd0fea21a2108201e4e627a1ebb119cebdd4 (patch)
treeed63d20aa23c227e8285daf4feea70a2afa5a6d7 /sys/geom/raid
parentfd59ebc4f06a04b79a039c0d4b908b07693f886e (diff)
downloadFreeBSD-src-3d44dd0fea21a2108201e4e627a1ebb119cebdd4.zip
FreeBSD-src-3d44dd0fea21a2108201e4e627a1ebb119cebdd4.tar.gz
Add support for RAID5R. Slightly improve support for RAIDMDF.
Diffstat (limited to 'sys/geom/raid')
-rw-r--r--sys/geom/raid/g_raid.c1
-rw-r--r--sys/geom/raid/g_raid.h6
-rw-r--r--sys/geom/raid/md_ddf.c36
-rw-r--r--sys/geom/raid/tr_raid5.c38
4 files changed, 60 insertions, 21 deletions
diff --git a/sys/geom/raid/g_raid.c b/sys/geom/raid/g_raid.c
index 646a48c..c3b627f 100644
--- a/sys/geom/raid/g_raid.c
+++ b/sys/geom/raid/g_raid.c
@@ -1856,6 +1856,7 @@ g_raid_create_volume(struct g_raid_softc *sc, const char *name, int id)
vol->v_state = G_RAID_VOLUME_S_STARTING;
vol->v_raid_level = G_RAID_VOLUME_RL_UNKNOWN;
vol->v_raid_level_qualifier = G_RAID_VOLUME_RLQ_UNKNOWN;
+ vol->v_rotate_parity = 1;
bioq_init(&vol->v_inflight);
bioq_init(&vol->v_locked);
LIST_INIT(&vol->v_locks);
diff --git a/sys/geom/raid/g_raid.h b/sys/geom/raid/g_raid.h
index 9def96d..a981f2a 100644
--- a/sys/geom/raid/g_raid.h
+++ b/sys/geom/raid/g_raid.h
@@ -278,7 +278,13 @@ struct g_raid_volume {
u_int v_raid_level; /* Array RAID level. */
u_int v_raid_level_qualifier; /* RAID level det. */
u_int v_disks_count; /* Number of disks in array. */
+ u_int v_mdf_pdisks; /* Number of parity disks
+ in RAIDMDF array. */
+ uint16_t v_mdf_polynomial; /* Polynomial for RAIDMDF. */
+ uint8_t v_mdf_method; /* Generation method for RAIDMDF. */
u_int v_strip_size; /* Array strip size. */
+ u_int v_rotate_parity; /* Rotate RAID5R parity
+ after numer of stripes. */
u_int v_sectorsize; /* Volume sector size. */
off_t v_mediasize; /* Volume media size. */
struct bio_queue_head v_inflight; /* In-flight write requests. */
diff --git a/sys/geom/raid/md_ddf.c b/sys/geom/raid/md_ddf.c
index c9eb705..7d3bdae 100644
--- a/sys/geom/raid/md_ddf.c
+++ b/sys/geom/raid/md_ddf.c
@@ -1517,7 +1517,7 @@ g_raid_md_ddf_supported(int level, int qual, int disks, int force)
qual != G_RAID_VOLUME_RLQ_RMDFLA &&
qual != G_RAID_VOLUME_RLQ_RMDFLS)
return (0);
- if (disks < 5)
+ if (disks < 4)
return (0);
break;
case G_RAID_VOLUME_RL_RAID1E:
@@ -1850,6 +1850,13 @@ g_raid_md_ddf_start(struct g_raid_volume *vol)
vol->v_strip_size = vol->v_sectorsize << GET8(vmeta, vdc->Stripe_Size);
vol->v_disks_count = GET16(vmeta, vdc->Primary_Element_Count) *
GET8(vmeta, vdc->Secondary_Element_Count);
+ vol->v_mdf_pdisks = GET8(vmeta, vdc->MDF_Parity_Disks);
+ vol->v_mdf_polynomial = GET16(vmeta, vdc->MDF_Parity_Generator_Polynomial);
+ vol->v_mdf_method = GET8(vmeta, vdc->MDF_Constant_Generation_Method);
+ if (GET8(vmeta, vdc->Rotate_Parity_count) > 31)
+ vol->v_rotate_parity = 1;
+ else
+ vol->v_rotate_parity = 1 << GET8(vmeta, vdc->Rotate_Parity_count);
vol->v_mediasize = GET64(vmeta, vdc->VD_Size) * vol->v_sectorsize;
for (i = 0, j = 0, bvd = 0; i < vol->v_disks_count; i++, j++) {
if (j == GET16(vmeta, vdc->Primary_Element_Count)) {
@@ -2430,16 +2437,24 @@ g_raid_md_ctl_ddf(struct g_raid_md_object *md,
vol->v_mediasize = size;
else if (level == G_RAID_VOLUME_RL_RAID3 ||
level == G_RAID_VOLUME_RL_RAID4 ||
- level == G_RAID_VOLUME_RL_RAID5 ||
- level == G_RAID_VOLUME_RL_RAID5R)
+ level == G_RAID_VOLUME_RL_RAID5)
vol->v_mediasize = size * (numdisks - 1);
- else if (level == G_RAID_VOLUME_RL_RAID6 ||
+ else if (level == G_RAID_VOLUME_RL_RAID5R) {
+ vol->v_mediasize = size * (numdisks - 1);
+ vol->v_rotate_parity = 1024;
+ } else if (level == G_RAID_VOLUME_RL_RAID6 ||
level == G_RAID_VOLUME_RL_RAID5E ||
level == G_RAID_VOLUME_RL_RAID5EE)
vol->v_mediasize = size * (numdisks - 2);
- else if (level == G_RAID_VOLUME_RL_RAIDMDF)
- vol->v_mediasize = size * (numdisks - 3);
- else { /* RAID1E */
+ else if (level == G_RAID_VOLUME_RL_RAIDMDF) {
+ if (numdisks < 5)
+ vol->v_mdf_pdisks = 2;
+ else
+ vol->v_mdf_pdisks = 3;
+ vol->v_mdf_polynomial = 0x11d;
+ vol->v_mdf_method = 0x00;
+ vol->v_mediasize = size * (numdisks - vol->v_mdf_pdisks);
+ } else { /* RAID1E */
vol->v_mediasize = ((size * numdisks) / strip / 2) *
strip;
}
@@ -2761,6 +2776,13 @@ g_raid_md_write_ddf(struct g_raid_md_object *md, struct g_raid_volume *tvol,
SET64(vmeta, vdc->Block_Count, 0);
SET64(vmeta, vdc->VD_Size, vol->v_mediasize / vol->v_sectorsize);
SET16(vmeta, vdc->Block_Size, vol->v_sectorsize);
+ SET8(vmeta, vdc->Rotate_Parity_count,
+ fls(vol->v_rotate_parity) - 1);
+ SET8(vmeta, vdc->MDF_Parity_Disks, vol->v_mdf_pdisks);
+ SET16(vmeta, vdc->MDF_Parity_Generator_Polynomial,
+ vol->v_mdf_polynomial);
+ SET8(vmeta, vdc->MDF_Constant_Generation_Method,
+ vol->v_mdf_method);
SET16(vmeta, vde->VD_Number, vol->v_global_id);
if (vol->v_state <= G_RAID_VOLUME_S_BROKEN)
diff --git a/sys/geom/raid/tr_raid5.c b/sys/geom/raid/tr_raid5.c
index 19b2943..a8f946b 100644
--- a/sys/geom/raid/tr_raid5.c
+++ b/sys/geom/raid/tr_raid5.c
@@ -112,10 +112,11 @@ g_raid_tr_taste_raid5(struct g_raid_tr_object *tr, struct g_raid_volume *vol)
} else if ((tr->tro_volume->v_raid_level == G_RAID_VOLUME_RL_RAID5 ||
tr->tro_volume->v_raid_level == G_RAID_VOLUME_RL_RAID5E ||
tr->tro_volume->v_raid_level == G_RAID_VOLUME_RL_RAID5EE ||
+ tr->tro_volume->v_raid_level == G_RAID_VOLUME_RL_RAID5R ||
tr->tro_volume->v_raid_level == G_RAID_VOLUME_RL_RAID6 ||
tr->tro_volume->v_raid_level == G_RAID_VOLUME_RL_RAIDMDF) &&
qual >= 0 && qual <= 3) {
- /* RAID5/5E/5EE/6/MDF */
+ /* RAID5/5E/5EE/5R/6/MDF */
} else
return (G_RAID_TR_TASTE_FAIL);
trs->trso_starting = 1;
@@ -210,7 +211,7 @@ g_raid_tr_iostart_raid5_read(struct g_raid_tr_object *tr, struct bio *bp)
struct bio *cbp;
char *addr;
off_t offset, start, length, nstripe, remain;
- int no, pno, ddisks, pdisks;
+ int no, pno, ddisks, pdisks, protate, pleft;
u_int strip_size, lvl, qual;
vol = tr->tro_volume;
@@ -218,6 +219,7 @@ g_raid_tr_iostart_raid5_read(struct g_raid_tr_object *tr, struct bio *bp)
strip_size = vol->v_strip_size;
lvl = tr->tro_volume->v_raid_level;
qual = tr->tro_volume->v_raid_level_qualifier;
+ protate = tr->tro_volume->v_rotate_parity;
/* Stripe number. */
nstripe = bp->bio_offset / strip_size;
@@ -225,7 +227,7 @@ g_raid_tr_iostart_raid5_read(struct g_raid_tr_object *tr, struct bio *bp)
start = bp->bio_offset % strip_size;
/* Number of data and parity disks. */
if (lvl == G_RAID_VOLUME_RL_RAIDMDF)
- pdisks = 3;
+ pdisks = tr->tro_volume->v_mdf_pdisks;
else if (lvl == G_RAID_VOLUME_RL_RAID5EE ||
lvl == G_RAID_VOLUME_RL_RAID6)
pdisks = 2;
@@ -238,8 +240,10 @@ g_raid_tr_iostart_raid5_read(struct g_raid_tr_object *tr, struct bio *bp)
pno = 0;
else /* PN */
pno = ddisks;
+ pleft = -1;
} else {
- pno = (nstripe / ddisks) % vol->v_disks_count;
+ pno = (nstripe / (ddisks * protate)) % vol->v_disks_count;
+ pleft = protate - (nstripe / ddisks) % protate;
if (qual >= 2) { /* PN/Left */
pno = ddisks - pno;
if (pno < 0)
@@ -281,11 +285,14 @@ g_raid_tr_iostart_raid5_read(struct g_raid_tr_object *tr, struct bio *bp)
} else if (qual & 1) { /* Continuation/Symmetric */
no %= vol->v_disks_count;
if (no == pno) {
- if (qual < 2) /* P0/Right */
- pno++;
- else /* PN/Left */
- pno += vol->v_disks_count - 1;
- pno %= vol->v_disks_count;
+ if ((--pleft) <= 0) {
+ pleft += protate;
+ if (qual < 2) /* P0/Right */
+ pno++;
+ else /* PN/Left */
+ pno += vol->v_disks_count - 1;
+ pno %= vol->v_disks_count;
+ }
no = (pno + pdisks) % vol->v_disks_count;
offset += strip_size;
}
@@ -294,11 +301,14 @@ g_raid_tr_iostart_raid5_read(struct g_raid_tr_object *tr, struct bio *bp)
no += pdisks;
if (no >= vol->v_disks_count) {
no -= vol->v_disks_count;
- if (qual < 2) /* P0/Right */
- pno++;
- else /* PN/Left */
- pno += vol->v_disks_count - 1;
- pno %= vol->v_disks_count;
+ if ((--pleft) <= 0) {
+ pleft += protate;
+ if (qual < 2) /* P0/Right */
+ pno++;
+ else /* PN/Left */
+ pno += vol->v_disks_count - 1;
+ pno %= vol->v_disks_count;
+ }
if (no == pno)
no += pdisks;
else
OpenPOWER on IntegriCloud