]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.fixes/0013-md-raid5-Add-support-for-new-layouts-for-raid5-and-r.patch
Reenabled linux-xen, added patches for Xen Kernel Version 2.6.27.31,
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.fixes / 0013-md-raid5-Add-support-for-new-layouts-for-raid5-and-r.patch
diff --git a/src/patches/suse-2.6.27.31/patches.fixes/0013-md-raid5-Add-support-for-new-layouts-for-raid5-and-r.patch b/src/patches/suse-2.6.27.31/patches.fixes/0013-md-raid5-Add-support-for-new-layouts-for-raid5-and-r.patch
new file mode 100644 (file)
index 0000000..5d2c7aa
--- /dev/null
@@ -0,0 +1,351 @@
+From 99c0fb5f92828ae96909d390f2df137b89093b37 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb@suse.de>
+Date: Tue, 31 Mar 2009 14:39:38 +1100
+Subject: [PATCH] md/raid5: Add support for new layouts for raid5 and raid6.
+
+DDF uses different layouts for P and Q blocks than current md/raid6
+so add those that are missing.
+Also add support for RAID6 layouts that are identical to various
+raid5 layouts with the simple addition of one device to hold all of
+the 'Q' blocks.
+Finally add 'raid5' layouts to match raid4.
+These last to will allow online level conversion.
+
+Note that this does not provide correct support for DDF/raid6 yet
+as the order in which data blocks are summed to produce the Q block
+is significant and different between current md code and DDF
+requirements.
+
+Signed-off-by: NeilBrown <neilb@suse.de>
+---
+ drivers/md/raid5.c         |  151 ++++++++++++++++++++++++++++++++++++++++-----
+ include/linux/raid/raid5.h |   61 ++++++++++++++++--
+ 2 files changed, 193 insertions(+), 19 deletions(-)
+
+--- linux-2.6.27-SLE11_BRANCH.orig/drivers/md/raid5.c
++++ linux-2.6.27-SLE11_BRANCH/drivers/md/raid5.c
+@@ -1100,7 +1100,7 @@ static void shrink_stripes(raid5_conf_t 
+ static void raid5_end_read_request(struct bio * bi, int error)
+ {
+-      struct stripe_head *sh = bi->bi_private;
++      struct stripe_head *sh = bi->bi_private;
+       raid5_conf_t *conf = sh->raid_conf;
+       int disks = sh->disks, i;
+       int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
+@@ -1182,7 +1182,7 @@ static void raid5_end_read_request(struc
+ static void raid5_end_write_request (struct bio *bi, int error)
+ {
+-      struct stripe_head *sh = bi->bi_private;
++      struct stripe_head *sh = bi->bi_private;
+       raid5_conf_t *conf = sh->raid_conf;
+       int disks = sh->disks, i;
+       int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
+@@ -1322,20 +1322,27 @@ static sector_t raid5_compute_sector(rai
+                       pd_idx = stripe % raid_disks;
+                       *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks;
+                       break;
++              case ALGORITHM_PARITY_0:
++                      pd_idx = 0;
++                      (*dd_idx)++;
++                      break;
++              case ALGORITHM_PARITY_N:
++                      pd_idx = data_disks;
++                      break;
+               default:
+                       printk(KERN_ERR "raid5: unsupported algorithm %d\n",
+                               conf->algorithm);
++                      BUG();
+               }
+               break;
+       case 6:
+-              /**** FIX THIS ****/
+               switch (conf->algorithm) {
+               case ALGORITHM_LEFT_ASYMMETRIC:
+                       pd_idx = raid_disks - 1 - (stripe % raid_disks);
+                       qd_idx = pd_idx + 1;
+                       if (pd_idx == raid_disks-1) {
+-                              (*dd_idx)++;    /* Q D D D P */
++                              (*dd_idx)++;    /* Q D D D P */
+                               qd_idx = 0;
+                       } else if (*dd_idx >= pd_idx)
+                               (*dd_idx) += 2; /* D D P Q D */
+@@ -1344,7 +1351,7 @@ static sector_t raid5_compute_sector(rai
+                       pd_idx = stripe % raid_disks;
+                       qd_idx = pd_idx + 1;
+                       if (pd_idx == raid_disks-1) {
+-                              (*dd_idx)++;    /* Q D D D P */
++                              (*dd_idx)++;    /* Q D D D P */
+                               qd_idx = 0;
+                       } else if (*dd_idx >= pd_idx)
+                               (*dd_idx) += 2; /* D D P Q D */
+@@ -1359,9 +1366,89 @@ static sector_t raid5_compute_sector(rai
+                       qd_idx = (pd_idx + 1) % raid_disks;
+                       *dd_idx = (pd_idx + 2 + *dd_idx) % raid_disks;
+                       break;
++
++              case ALGORITHM_PARITY_0:
++                      pd_idx = 0;
++                      qd_idx = 1;
++                      (*dd_idx) += 2;
++                      break;
++              case ALGORITHM_PARITY_N:
++                      pd_idx = data_disks;
++                      qd_idx = data_disks + 1;
++                      break;
++
++              case ALGORITHM_ROTATING_ZERO_RESTART:
++                      /* Exactly the same as RIGHT_ASYMMETRIC, but or
++                       * of blocks for computing Q is different.
++                       */
++                      pd_idx = stripe % raid_disks;
++                      qd_idx = pd_idx + 1;
++                      if (pd_idx == raid_disks-1) {
++                              (*dd_idx)++;    /* Q D D D P */
++                              qd_idx = 0;
++                      } else if (*dd_idx >= pd_idx)
++                              (*dd_idx) += 2; /* D D P Q D */
++                      break;
++
++              case ALGORITHM_ROTATING_N_RESTART:
++                      /* Same a left_asymmetric, by first stripe is
++                       * D D D P Q  rather than
++                       * Q D D D P
++                       */
++                      pd_idx = raid_disks - 1 - ((stripe + 1) % raid_disks);
++                      qd_idx = pd_idx + 1;
++                      if (pd_idx == raid_disks-1) {
++                              (*dd_idx)++;    /* Q D D D P */
++                              qd_idx = 0;
++                      } else if (*dd_idx >= pd_idx)
++                              (*dd_idx) += 2; /* D D P Q D */
++                      break;
++
++              case ALGORITHM_ROTATING_N_CONTINUE:
++                      /* Same as left_symmetric but Q is before P */
++                      pd_idx = raid_disks - 1 - (stripe % raid_disks);
++                      qd_idx = (pd_idx + raid_disks - 1) % raid_disks;
++                      *dd_idx = (pd_idx + 1 + *dd_idx) % raid_disks;
++                      break;
++
++              case ALGORITHM_LEFT_ASYMMETRIC_6:
++                      /* RAID5 left_asymmetric, with Q on last device */
++                      pd_idx = data_disks - stripe % (raid_disks-1);
++                      if (*dd_idx >= pd_idx)
++                              (*dd_idx)++;
++                      qd_idx = raid_disks - 1;
++                      break;
++
++              case ALGORITHM_RIGHT_ASYMMETRIC_6:
++                      pd_idx = stripe % (raid_disks-1);
++                      if (*dd_idx >= pd_idx)
++                              (*dd_idx)++;
++                      qd_idx = raid_disks - 1;
++                      break;
++
++              case ALGORITHM_LEFT_SYMMETRIC_6:
++                      pd_idx = data_disks - stripe % (raid_disks-1);
++                      *dd_idx = (pd_idx + 1 + *dd_idx) % (raid_disks-1);
++                      qd_idx = raid_disks - 1;
++                      break;
++
++              case ALGORITHM_RIGHT_SYMMETRIC_6:
++                      pd_idx = stripe % (raid_disks-1);
++                      *dd_idx = (pd_idx + 1 + *dd_idx) % (raid_disks-1);
++                      qd_idx = raid_disks - 1;
++                      break;
++
++              case ALGORITHM_PARITY_0_6:
++                      pd_idx = 0;
++                      (*dd_idx)++;
++                      qd_idx = raid_disks - 1;
++                      break;
++
++
+               default:
+                       printk (KERN_CRIT "raid6: unsupported algorithm %d\n",
+                               conf->algorithm);
++                      BUG();
+               }
+               break;
+       }
+@@ -1413,9 +1500,15 @@ static sector_t compute_blocknr(struct s
+                               i += raid_disks;
+                       i -= (sh->pd_idx + 1);
+                       break;
++              case ALGORITHM_PARITY_0:
++                      i -= 1;
++                      break;
++              case ALGORITHM_PARITY_N:
++                      break;
+               default:
+                       printk(KERN_ERR "raid5: unsupported algorithm %d\n",
+                              conf->algorithm);
++                      BUG();
+               }
+               break;
+       case 6:
+@@ -1424,8 +1517,10 @@ static sector_t compute_blocknr(struct s
+               switch (conf->algorithm) {
+               case ALGORITHM_LEFT_ASYMMETRIC:
+               case ALGORITHM_RIGHT_ASYMMETRIC:
+-                      if (sh->pd_idx == raid_disks-1)
+-                              i--;    /* Q D D D P */
++              case ALGORITHM_ROTATING_ZERO_RESTART:
++              case ALGORITHM_ROTATING_N_RESTART:
++                      if (sh->pd_idx == raid_disks-1)
++                              i--;    /* Q D D D P */
+                       else if (i > sh->pd_idx)
+                               i -= 2; /* D D P Q D */
+                       break;
+@@ -1440,9 +1535,35 @@ static sector_t compute_blocknr(struct s
+                               i -= (sh->pd_idx + 2);
+                       }
+                       break;
++              case ALGORITHM_PARITY_0:
++                      i -= 2;
++                      break;
++              case ALGORITHM_PARITY_N:
++                      break;
++              case ALGORITHM_ROTATING_N_CONTINUE:
++                      if (sh->pd_idx == 0)
++                              i--;    /* P D D D Q */
++                      else if (i > sh->pd_idx)
++                              i -= 2; /* D D Q P D */
++                      break;
++              case ALGORITHM_LEFT_ASYMMETRIC_6:
++              case ALGORITHM_RIGHT_ASYMMETRIC_6:
++                      if (i > sh->pd_idx)
++                              i--;
++                      break;
++              case ALGORITHM_LEFT_SYMMETRIC_6:
++              case ALGORITHM_RIGHT_SYMMETRIC_6:
++                      if (i < sh->pd_idx)
++                              i += data_disks + 1;
++                      i -= (sh->pd_idx + 1);
++                      break;
++              case ALGORITHM_PARITY_0_6:
++                      i -= 1;
++                      break;
+               default:
+                       printk (KERN_CRIT "raid6: unsupported algorithm %d\n",
+                               conf->algorithm);
++                      BUG();
+               }
+               break;
+       }
+@@ -3310,7 +3431,7 @@ static int chunk_aligned_read(struct req
+               return 0;
+       }
+       /*
+-       * use bio_clone to make a copy of the bio
++       * use bio_clone to make a copy of the bio
+        */
+       align_bi = bio_clone(raid_bio, GFP_NOIO);
+       if (!align_bi)
+@@ -3438,7 +3559,7 @@ static int make_request(struct request_q
+       if (rw == READ &&
+            mddev->reshape_position == MaxSector &&
+            chunk_aligned_read(q,bi))
+-              return 0;
++              return 0;
+       logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1);
+       last_sector = bi->bi_sector + (bi->bi_size>>9);
+@@ -4035,6 +4156,12 @@ static int run(mddev_t *mddev)
+                      mdname(mddev), mddev->level);
+               return -EIO;
+       }
++      if ((mddev->level == 5 && !algorithm_valid_raid5(mddev->layout)) ||
++          (mddev->level == 6 && !algorithm_valid_raid6(mddev->layout))) {
++              printk(KERN_ERR "raid5: %s: layout %d not supported\n",
++                     mdname(mddev), mddev->layout);
++              return -EIO;
++      }
+       if (mddev->chunk_size < PAGE_SIZE) {
+               printk(KERN_ERR "md/raid5: chunk_size must be at least "
+@@ -4186,12 +4313,6 @@ static int run(mddev_t *mddev)
+                       conf->chunk_size, mdname(mddev));
+               goto abort;
+       }
+-      if (conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) {
+-              printk(KERN_ERR 
+-                      "raid5: unsupported parity algorithm %d for %s\n",
+-                      conf->algorithm, mdname(mddev));
+-              goto abort;
+-      }
+       if (mddev->degraded > conf->max_degraded) {
+               printk(KERN_ERR "raid5: not enough operational devices for %s"
+                       " (%d/%d failed)\n",
+--- linux-2.6.27-SLE11_BRANCH.orig/include/linux/raid/raid5.h
++++ linux-2.6.27-SLE11_BRANCH/include/linux/raid/raid5.h
+@@ -395,9 +395,62 @@ typedef struct raid5_private_data raid5_
+ /*
+  * Our supported algorithms
+  */
+-#define ALGORITHM_LEFT_ASYMMETRIC     0
+-#define ALGORITHM_RIGHT_ASYMMETRIC    1
+-#define ALGORITHM_LEFT_SYMMETRIC      2
+-#define ALGORITHM_RIGHT_SYMMETRIC     3
++#define ALGORITHM_LEFT_ASYMMETRIC     0 /* Rotating Parity N with Data Restart */
++#define ALGORITHM_RIGHT_ASYMMETRIC    1 /* Rotating Parity 0 with Data Restart */
++#define ALGORITHM_LEFT_SYMMETRIC      2 /* Rotating Parity N with Data Continuation */
++#define ALGORITHM_RIGHT_SYMMETRIC     3 /* Rotating Parity 0 with Data Continuation */
++/* Define non-rotating (raid4) algorithms.  These allow
++ * conversion of raid4 to raid5.
++ */
++#define ALGORITHM_PARITY_0            4 /* P or P,Q are initial devices */
++#define ALGORITHM_PARITY_N            5 /* P or P,Q are final devices. */
++
++/* DDF RAID6 layouts differ from md/raid6 layouts in two ways.
++ * Firstly, the exact positioning of the parity block is slightly
++ * different between the 'LEFT_*' modes of md and the "_N_*" modes
++ * of DDF.
++ * Secondly, or order of datablocks over which the Q syndrome is computed
++ * is different.
++ * Consequently we have different layouts for DDF/raid6 than md/raid6.
++ * These layouts are from the DDFv1.2 spec.
++ * Interestingly DDFv1.2-Errata-A does not specify N_CONTINUE but
++ * leaves RLQ=3 as 'Vendor Specific'
++ */
++
++#define ALGORITHM_ROTATING_ZERO_RESTART       8 /* DDF PRL=6 RLQ=1 */
++#define ALGORITHM_ROTATING_N_RESTART  9 /* DDF PRL=6 RLQ=2 */
++#define ALGORITHM_ROTATING_N_CONTINUE 10 /*DDF PRL=6 RLQ=3 */
++
++
++/* For every RAID5 algorithm we define a RAID6 algorithm
++ * with exactly the same layout for data and parity, and
++ * with the Q block always on the last device (N-1).
++ * This allows trivial conversion from RAID5 to RAID6
++ */
++#define ALGORITHM_LEFT_ASYMMETRIC_6   16
++#define ALGORITHM_RIGHT_ASYMMETRIC_6  17
++#define ALGORITHM_LEFT_SYMMETRIC_6    18
++#define ALGORITHM_RIGHT_SYMMETRIC_6   19
++#define ALGORITHM_PARITY_0_6          20
++#define ALGORITHM_PARITY_N_6          ALGORITHM_PARITY_N
++
++static inline int algorithm_valid_raid5(int layout)
++{
++      return (layout >= 0) &&
++              (layout <= 5);
++}
++static inline int algorithm_valid_raid6(int layout)
++{
++      return (layout >= 0 && layout <= 5)
++              ||
++              (layout == 8 || layout == 10)
++              ||
++              (layout >= 16 && layout <= 20);
++}
++
++static inline int algorithm_is_DDF(int layout)
++{
++      return layout >= 8 && layout <= 10;
++}
+ #endif