[PATCH 05/12] md: move write operations to raid5_run_ops

2007-01-22 Thread Dan Williams
From: Dan Williams <[EMAIL PROTECTED]>

handle_stripe sets STRIPE_OP_PREXOR, STRIPE_OP_BIODRAIN, STRIPE_OP_POSTXOR
to request a write to the stripe cache.  raid5_run_ops is triggerred to run
and executes the request outside the stripe lock.

Signed-off-by: Dan Williams <[EMAIL PROTECTED]>
---

 drivers/md/raid5.c |  152 +---
 1 files changed, 131 insertions(+), 21 deletions(-)

diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 2c74f9b..2390657 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -1788,7 +1788,75 @@ static void compute_block_2(struct stripe_head *sh, int 
dd_idx1, int dd_idx2)
}
 }
 
+static int handle_write_operations5(struct stripe_head *sh, int rcw, int 
expand)
+{
+   int i, pd_idx = sh->pd_idx, disks = sh->disks;
+   int locked=0;
+
+   if (rcw == 0) {
+   /* skip the drain operation on an expand */
+   if (!expand) {
+   BUG_ON(test_and_set_bit(STRIPE_OP_BIODRAIN,
+   >ops.pending));
+   sh->ops.count++;
+   }
+
+   BUG_ON(test_and_set_bit(STRIPE_OP_POSTXOR, >ops.pending));
+   sh->ops.count++;
+
+   for (i=disks ; i-- ;) {
+   struct r5dev *dev = >dev[i];
+
+   if (dev->towrite) {
+   set_bit(R5_LOCKED, >flags);
+   if (!expand)
+   clear_bit(R5_UPTODATE, >flags);
+   locked++;
+   }
+   }
+   } else {
+   BUG_ON(!(test_bit(R5_UPTODATE, >dev[pd_idx].flags) ||
+   test_bit(R5_Wantcompute, >dev[pd_idx].flags)));
+
+   BUG_ON(test_and_set_bit(STRIPE_OP_PREXOR, >ops.pending) ||
+   test_and_set_bit(STRIPE_OP_BIODRAIN, >ops.pending) 
||
+   test_and_set_bit(STRIPE_OP_POSTXOR, >ops.pending));
+
+   sh->ops.count += 3;
+
+   for (i=disks ; i-- ;) {
+   struct r5dev *dev = >dev[i];
+   if (i==pd_idx)
+   continue;
 
+   /* For a read-modify write there may be blocks that are
+* locked for reading while others are ready to be 
written
+* so we distinguish these blocks by the R5_Wantprexor 
bit
+*/
+   if (dev->towrite &&
+   (test_bit(R5_UPTODATE, >flags) ||
+   test_bit(R5_Wantcompute, >flags))) {
+   set_bit(R5_Wantprexor, >flags);
+   set_bit(R5_LOCKED, >flags);
+   clear_bit(R5_UPTODATE, >flags);
+   locked++;
+   }
+   }
+   }
+
+   /* keep the parity disk locked while asynchronous operations
+* are in flight
+*/
+   set_bit(R5_LOCKED, >dev[pd_idx].flags);
+   clear_bit(R5_UPTODATE, >dev[pd_idx].flags);
+   locked++;
+
+   PRINTK("%s: stripe %llu locked: %d pending: %lx\n",
+   __FUNCTION__, (unsigned long long)sh->sector,
+   locked, sh->ops.pending);
+
+   return locked;
+}
 
 /*
  * Each stripe/dev can have one or more bion attached.
@@ -2151,8 +2219,67 @@ static void handle_stripe5(struct stripe_head *sh)
set_bit(STRIPE_HANDLE, >state);
}
 
-   /* now to consider writing and what else, if anything should be read */
-   if (to_write) {
+   /* Now we check to see if any write operations have recently
+* completed
+*/
+
+   /* leave prexor set until postxor is done, allows us to distinguish
+* a rmw from a rcw during biodrain
+*/
+   if (test_bit(STRIPE_OP_PREXOR, >ops.complete) &&
+   test_bit(STRIPE_OP_POSTXOR, >ops.complete)) {
+
+   clear_bit(STRIPE_OP_PREXOR, >ops.complete);
+   clear_bit(STRIPE_OP_PREXOR, >ops.ack);
+   clear_bit(STRIPE_OP_PREXOR, >ops.pending);
+
+   for (i=disks; i--;)
+   clear_bit(R5_Wantprexor, >dev[i].flags);
+   }
+
+   /* if only POSTXOR is set then this is an 'expand' postxor */
+   if (test_bit(STRIPE_OP_BIODRAIN, >ops.complete) &&
+   test_bit(STRIPE_OP_POSTXOR, >ops.complete)) {
+
+   clear_bit(STRIPE_OP_BIODRAIN, >ops.complete);
+   clear_bit(STRIPE_OP_BIODRAIN, >ops.ack);
+   clear_bit(STRIPE_OP_BIODRAIN, >ops.pending);
+
+   clear_bit(STRIPE_OP_POSTXOR, >ops.complete);
+   clear_bit(STRIPE_OP_POSTXOR, >ops.ack);
+   clear_bit(STRIPE_OP_POSTXOR, >ops.pending);
+
+   /* All the 'written' buffers and the parity block are ready to 
be
+ 

[PATCH 05/12] md: move write operations to raid5_run_ops

2007-01-22 Thread Dan Williams
From: Dan Williams [EMAIL PROTECTED]

handle_stripe sets STRIPE_OP_PREXOR, STRIPE_OP_BIODRAIN, STRIPE_OP_POSTXOR
to request a write to the stripe cache.  raid5_run_ops is triggerred to run
and executes the request outside the stripe lock.

Signed-off-by: Dan Williams [EMAIL PROTECTED]
---

 drivers/md/raid5.c |  152 +---
 1 files changed, 131 insertions(+), 21 deletions(-)

diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 2c74f9b..2390657 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -1788,7 +1788,75 @@ static void compute_block_2(struct stripe_head *sh, int 
dd_idx1, int dd_idx2)
}
 }
 
+static int handle_write_operations5(struct stripe_head *sh, int rcw, int 
expand)
+{
+   int i, pd_idx = sh-pd_idx, disks = sh-disks;
+   int locked=0;
+
+   if (rcw == 0) {
+   /* skip the drain operation on an expand */
+   if (!expand) {
+   BUG_ON(test_and_set_bit(STRIPE_OP_BIODRAIN,
+   sh-ops.pending));
+   sh-ops.count++;
+   }
+
+   BUG_ON(test_and_set_bit(STRIPE_OP_POSTXOR, sh-ops.pending));
+   sh-ops.count++;
+
+   for (i=disks ; i-- ;) {
+   struct r5dev *dev = sh-dev[i];
+
+   if (dev-towrite) {
+   set_bit(R5_LOCKED, dev-flags);
+   if (!expand)
+   clear_bit(R5_UPTODATE, dev-flags);
+   locked++;
+   }
+   }
+   } else {
+   BUG_ON(!(test_bit(R5_UPTODATE, sh-dev[pd_idx].flags) ||
+   test_bit(R5_Wantcompute, sh-dev[pd_idx].flags)));
+
+   BUG_ON(test_and_set_bit(STRIPE_OP_PREXOR, sh-ops.pending) ||
+   test_and_set_bit(STRIPE_OP_BIODRAIN, sh-ops.pending) 
||
+   test_and_set_bit(STRIPE_OP_POSTXOR, sh-ops.pending));
+
+   sh-ops.count += 3;
+
+   for (i=disks ; i-- ;) {
+   struct r5dev *dev = sh-dev[i];
+   if (i==pd_idx)
+   continue;
 
+   /* For a read-modify write there may be blocks that are
+* locked for reading while others are ready to be 
written
+* so we distinguish these blocks by the R5_Wantprexor 
bit
+*/
+   if (dev-towrite 
+   (test_bit(R5_UPTODATE, dev-flags) ||
+   test_bit(R5_Wantcompute, dev-flags))) {
+   set_bit(R5_Wantprexor, dev-flags);
+   set_bit(R5_LOCKED, dev-flags);
+   clear_bit(R5_UPTODATE, dev-flags);
+   locked++;
+   }
+   }
+   }
+
+   /* keep the parity disk locked while asynchronous operations
+* are in flight
+*/
+   set_bit(R5_LOCKED, sh-dev[pd_idx].flags);
+   clear_bit(R5_UPTODATE, sh-dev[pd_idx].flags);
+   locked++;
+
+   PRINTK(%s: stripe %llu locked: %d pending: %lx\n,
+   __FUNCTION__, (unsigned long long)sh-sector,
+   locked, sh-ops.pending);
+
+   return locked;
+}
 
 /*
  * Each stripe/dev can have one or more bion attached.
@@ -2151,8 +2219,67 @@ static void handle_stripe5(struct stripe_head *sh)
set_bit(STRIPE_HANDLE, sh-state);
}
 
-   /* now to consider writing and what else, if anything should be read */
-   if (to_write) {
+   /* Now we check to see if any write operations have recently
+* completed
+*/
+
+   /* leave prexor set until postxor is done, allows us to distinguish
+* a rmw from a rcw during biodrain
+*/
+   if (test_bit(STRIPE_OP_PREXOR, sh-ops.complete) 
+   test_bit(STRIPE_OP_POSTXOR, sh-ops.complete)) {
+
+   clear_bit(STRIPE_OP_PREXOR, sh-ops.complete);
+   clear_bit(STRIPE_OP_PREXOR, sh-ops.ack);
+   clear_bit(STRIPE_OP_PREXOR, sh-ops.pending);
+
+   for (i=disks; i--;)
+   clear_bit(R5_Wantprexor, sh-dev[i].flags);
+   }
+
+   /* if only POSTXOR is set then this is an 'expand' postxor */
+   if (test_bit(STRIPE_OP_BIODRAIN, sh-ops.complete) 
+   test_bit(STRIPE_OP_POSTXOR, sh-ops.complete)) {
+
+   clear_bit(STRIPE_OP_BIODRAIN, sh-ops.complete);
+   clear_bit(STRIPE_OP_BIODRAIN, sh-ops.ack);
+   clear_bit(STRIPE_OP_BIODRAIN, sh-ops.pending);
+
+   clear_bit(STRIPE_OP_POSTXOR, sh-ops.complete);
+   clear_bit(STRIPE_OP_POSTXOR, sh-ops.ack);
+   clear_bit(STRIPE_OP_POSTXOR, sh-ops.pending);
+
+   /* All the 'written'