On 8/30/07, Yuri Tikhonov <[EMAIL PROTECTED]> wrote:
>
> Hi Dan,
>
> On Monday 27 August 2007 23:12, you wrote:
> > This still looks racy... I think the complete fix is to make the
> > R5_Wantfill and dev_q->toread accesses atomic. Please test the
> > following patch (also attached) and let me know if it fixes what you are
> > seeing:
>
> Your approach doesn't help, the Bonnie++ utility hangs up during the
> ReWriting stage.
>
Looking at it again I see that what I added would not affect the
failure you are seeing. However I noticed that you are using a broken
version of the stripe-queue and cache_arbiter patches. In the current
revisions the dev_q->flags field has been moved back to dev->flags
which fixes a data corruption issue and could potentially address the
hang you are seeing. The latest revisions are:
raid5: add the stripe_queue object for tracking raid io requests (rev2)
raid5: use stripe_queues to prioritize the "most deserving" requests (rev6)
> Note that before applying your patch I rolled my fix in the
> ops_complete_biofill() function back. Do I understand it right that your
> patch should be used *instead* of my one rather than *with* it ?
>
You understood correctly. The attached patch integrates your change
to keep R5_Wantfill set while also protecting the 'more_to_read' case.
Please try it on top of the latest stripe-queue changes [1] (instead
of the other proposed patches) .
> Regards, Yuri
Thanks,
Dan
[1] git fetch -f git://lost.foo-projects.org/~dwillia2/git/iop
md-for-linus:refs/heads/md-for-linus
raid5: fix the 'more_to_read' case in ops_complete_biofill
From: Dan Williams <[EMAIL PROTECTED]>
Prevent ops_complete_biofill from running concurrently with add_queue_bio
---
drivers/md/raid5.c | 33 +++++++++++++++++++--------------
1 files changed, 19 insertions(+), 14 deletions(-)
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 2f9022d..1c591d3 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -828,22 +828,19 @@ static void ops_complete_biofill(void *stripe_head_ref)
struct r5dev *dev = &sh->dev[i];
struct r5_queue_dev *dev_q = &sq->dev[i];
- /* check if this stripe has new incoming reads */
+ /* 1/ acknowledge completion of a biofill operation
+ * 2/ check if we need to reply to a read request.
+ * 3/ check if we need to reschedule handle_stripe
+ */
if (dev_q->toread)
more_to_read++;
- /* acknowledge completion of a biofill operation */
- /* and check if we need to reply to a read request
- */
- if (test_bit(R5_Wantfill, &dev->flags) && !dev_q->toread) {
+ if (test_bit(R5_Wantfill, &dev->flags)) {
struct bio *rbi, *rbi2;
- clear_bit(R5_Wantfill, &dev->flags);
- /* The access to dev->read is outside of the
- * spin_lock_irq(&conf->device_lock), but is protected
- * by the STRIPE_OP_BIOFILL pending bit
- */
- BUG_ON(!dev->read);
+ if (!dev_q->toread)
+ clear_bit(R5_Wantfill, &dev->flags);
+
rbi = dev->read;
dev->read = NULL;
while (rbi && rbi->bi_sector <
@@ -899,8 +896,15 @@ static void ops_run_biofill(struct stripe_head *sh)
}
atomic_inc(&sh->count);
+
+ /* spin_lock prevents ops_complete_biofill from running concurrently
+ * with add_queue_bio in the synchronous case
+ */
+ spin_lock(&sq->lock);
async_trigger_callback(ASYNC_TX_DEP_ACK | ASYNC_TX_ACK, tx,
ops_complete_biofill, sh);
+ spin_unlock(&sq->lock);
+
}
static void ops_complete_compute5(void *stripe_head_ref)
@@ -2279,7 +2283,8 @@ static int add_queue_bio(struct stripe_queue *sq, struct bio *bi, int dd_idx,
(unsigned long long)bi->bi_sector,
(unsigned long long)sq->sector);
- spin_lock(&sq->lock);
+ /* prevent asynchronous completions from running */
+ spin_lock_bh(&sq->lock);
spin_lock_irq(&conf->device_lock);
sh = sq->sh;
if (forwrite) {
@@ -2306,7 +2311,7 @@ static int add_queue_bio(struct stripe_queue *sq, struct bio *bi, int dd_idx,
*bip = bi;
bi->bi_phys_segments ++;
spin_unlock_irq(&conf->device_lock);
- spin_unlock(&sq->lock);
+ spin_unlock_bh(&sq->lock);
pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
(unsigned long long)bi->bi_sector,
@@ -2339,7 +2344,7 @@ static int add_queue_bio(struct stripe_queue *sq, struct bio *bi, int dd_idx,
overlap:
set_bit(R5_Overlap, &sh->dev[dd_idx].flags);
spin_unlock_irq(&conf->device_lock);
- spin_unlock(&sq->lock);
+ spin_unlock_bh(&sq->lock);
return 0;
}