Commit 72ac7330 authored by shli@kernel.org's avatar shli@kernel.org Committed by NeilBrown

raid5: handle io error of batch list

If io error happens in any stripe of a batch list, the batch list will be
split, then normal process will run for the stripes in the list.
Signed-off-by: default avatarShaohua Li <shli@fusionio.com>
Signed-off-by: default avatarNeilBrown <neilb@suse.de>
parent 59fc630b
...@@ -1070,6 +1070,9 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) ...@@ -1070,6 +1070,9 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
pr_debug("skip op %ld on disc %d for sector %llu\n", pr_debug("skip op %ld on disc %d for sector %llu\n",
bi->bi_rw, i, (unsigned long long)sh->sector); bi->bi_rw, i, (unsigned long long)sh->sector);
clear_bit(R5_LOCKED, &sh->dev[i].flags); clear_bit(R5_LOCKED, &sh->dev[i].flags);
if (sh->batch_head)
set_bit(STRIPE_BATCH_ERR,
&sh->batch_head->state);
set_bit(STRIPE_HANDLE, &sh->state); set_bit(STRIPE_HANDLE, &sh->state);
} }
...@@ -2380,6 +2383,9 @@ static void raid5_end_write_request(struct bio *bi, int error) ...@@ -2380,6 +2383,9 @@ static void raid5_end_write_request(struct bio *bi, int error)
} }
rdev_dec_pending(rdev, conf->mddev); rdev_dec_pending(rdev, conf->mddev);
if (sh->batch_head && !uptodate)
set_bit(STRIPE_BATCH_ERR, &sh->batch_head->state);
if (!test_and_clear_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags)) if (!test_and_clear_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags))
clear_bit(R5_LOCKED, &sh->dev[i].flags); clear_bit(R5_LOCKED, &sh->dev[i].flags);
set_bit(STRIPE_HANDLE, &sh->state); set_bit(STRIPE_HANDLE, &sh->state);
...@@ -4124,6 +4130,46 @@ static int clear_batch_ready(struct stripe_head *sh) ...@@ -4124,6 +4130,46 @@ static int clear_batch_ready(struct stripe_head *sh)
return 0; return 0;
} }
static void check_break_stripe_batch_list(struct stripe_head *sh)
{
struct stripe_head *head_sh, *next;
int i;
if (!test_and_clear_bit(STRIPE_BATCH_ERR, &sh->state))
return;
head_sh = sh;
do {
sh = list_first_entry(&sh->batch_list,
struct stripe_head, batch_list);
BUG_ON(sh == head_sh);
} while (!test_bit(STRIPE_DEGRADED, &sh->state));
while (sh != head_sh) {
next = list_first_entry(&sh->batch_list,
struct stripe_head, batch_list);
list_del_init(&sh->batch_list);
sh->state = head_sh->state & ~((1 << STRIPE_ACTIVE) |
(1 << STRIPE_PREREAD_ACTIVE) |
(1 << STRIPE_DEGRADED));
sh->check_state = head_sh->check_state;
sh->reconstruct_state = head_sh->reconstruct_state;
for (i = 0; i < sh->disks; i++)
sh->dev[i].flags = head_sh->dev[i].flags &
(~((1 << R5_WriteError) | (1 << R5_Overlap)));
spin_lock_irq(&sh->stripe_lock);
sh->batch_head = NULL;
spin_unlock_irq(&sh->stripe_lock);
set_bit(STRIPE_HANDLE, &sh->state);
release_stripe(sh);
sh = next;
}
}
static void handle_stripe(struct stripe_head *sh) static void handle_stripe(struct stripe_head *sh)
{ {
struct stripe_head_state s; struct stripe_head_state s;
...@@ -4146,6 +4192,8 @@ static void handle_stripe(struct stripe_head *sh) ...@@ -4146,6 +4192,8 @@ static void handle_stripe(struct stripe_head *sh)
return; return;
} }
check_break_stripe_batch_list(sh);
if (test_bit(STRIPE_SYNC_REQUESTED, &sh->state)) { if (test_bit(STRIPE_SYNC_REQUESTED, &sh->state)) {
spin_lock(&sh->stripe_lock); spin_lock(&sh->stripe_lock);
/* Cannot process 'sync' concurrently with 'discard' */ /* Cannot process 'sync' concurrently with 'discard' */
......
...@@ -336,6 +336,7 @@ enum { ...@@ -336,6 +336,7 @@ enum {
STRIPE_DISCARD, STRIPE_DISCARD,
STRIPE_ON_RELEASE_LIST, STRIPE_ON_RELEASE_LIST,
STRIPE_BATCH_READY, STRIPE_BATCH_READY,
STRIPE_BATCH_ERR,
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment