diff options
author | shli@kernel.org <shli@kernel.org> | 2014-12-14 20:57:03 -0500 |
---|---|---|
committer | NeilBrown <neilb@suse.de> | 2015-04-21 18:00:41 -0400 |
commit | 72ac733015bbdc0356ba3e92c52137a265910a91 (patch) | |
tree | 20dfdc319ebbd53033f325017f24b5ad92970c31 /drivers/md/raid5.c | |
parent | 59fc630b8b5f9f21c8ce3ba153341c107dce1b0c (diff) |
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: Shaohua Li <shli@fusionio.com>
Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md/raid5.c')
-rw-r--r-- | drivers/md/raid5.c | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 717189e74243..54f3cb312b42 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -1070,6 +1070,9 @@ again: | |||
1070 | pr_debug("skip op %ld on disc %d for sector %llu\n", | 1070 | pr_debug("skip op %ld on disc %d for sector %llu\n", |
1071 | bi->bi_rw, i, (unsigned long long)sh->sector); | 1071 | bi->bi_rw, i, (unsigned long long)sh->sector); |
1072 | clear_bit(R5_LOCKED, &sh->dev[i].flags); | 1072 | clear_bit(R5_LOCKED, &sh->dev[i].flags); |
1073 | if (sh->batch_head) | ||
1074 | set_bit(STRIPE_BATCH_ERR, | ||
1075 | &sh->batch_head->state); | ||
1073 | set_bit(STRIPE_HANDLE, &sh->state); | 1076 | set_bit(STRIPE_HANDLE, &sh->state); |
1074 | } | 1077 | } |
1075 | 1078 | ||
@@ -2380,6 +2383,9 @@ static void raid5_end_write_request(struct bio *bi, int error) | |||
2380 | } | 2383 | } |
2381 | rdev_dec_pending(rdev, conf->mddev); | 2384 | rdev_dec_pending(rdev, conf->mddev); |
2382 | 2385 | ||
2386 | if (sh->batch_head && !uptodate) | ||
2387 | set_bit(STRIPE_BATCH_ERR, &sh->batch_head->state); | ||
2388 | |||
2383 | if (!test_and_clear_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags)) | 2389 | if (!test_and_clear_bit(R5_DOUBLE_LOCKED, &sh->dev[i].flags)) |
2384 | clear_bit(R5_LOCKED, &sh->dev[i].flags); | 2390 | clear_bit(R5_LOCKED, &sh->dev[i].flags); |
2385 | set_bit(STRIPE_HANDLE, &sh->state); | 2391 | set_bit(STRIPE_HANDLE, &sh->state); |
@@ -4124,6 +4130,46 @@ static int clear_batch_ready(struct stripe_head *sh) | |||
4124 | return 0; | 4130 | return 0; |
4125 | } | 4131 | } |
4126 | 4132 | ||
4133 | static void check_break_stripe_batch_list(struct stripe_head *sh) | ||
4134 | { | ||
4135 | struct stripe_head *head_sh, *next; | ||
4136 | int i; | ||
4137 | |||
4138 | if (!test_and_clear_bit(STRIPE_BATCH_ERR, &sh->state)) | ||
4139 | return; | ||
4140 | |||
4141 | head_sh = sh; | ||
4142 | do { | ||
4143 | sh = list_first_entry(&sh->batch_list, | ||
4144 | struct stripe_head, batch_list); | ||
4145 | BUG_ON(sh == head_sh); | ||
4146 | } while (!test_bit(STRIPE_DEGRADED, &sh->state)); | ||
4147 | |||
4148 | while (sh != head_sh) { | ||
4149 | next = list_first_entry(&sh->batch_list, | ||
4150 | struct stripe_head, batch_list); | ||
4151 | list_del_init(&sh->batch_list); | ||
4152 | |||
4153 | sh->state = head_sh->state & ~((1 << STRIPE_ACTIVE) | | ||
4154 | (1 << STRIPE_PREREAD_ACTIVE) | | ||
4155 | (1 << STRIPE_DEGRADED)); | ||
4156 | sh->check_state = head_sh->check_state; | ||
4157 | sh->reconstruct_state = head_sh->reconstruct_state; | ||
4158 | for (i = 0; i < sh->disks; i++) | ||
4159 | sh->dev[i].flags = head_sh->dev[i].flags & | ||
4160 | (~((1 << R5_WriteError) | (1 << R5_Overlap))); | ||
4161 | |||
4162 | spin_lock_irq(&sh->stripe_lock); | ||
4163 | sh->batch_head = NULL; | ||
4164 | spin_unlock_irq(&sh->stripe_lock); | ||
4165 | |||
4166 | set_bit(STRIPE_HANDLE, &sh->state); | ||
4167 | release_stripe(sh); | ||
4168 | |||
4169 | sh = next; | ||
4170 | } | ||
4171 | } | ||
4172 | |||
4127 | static void handle_stripe(struct stripe_head *sh) | 4173 | static void handle_stripe(struct stripe_head *sh) |
4128 | { | 4174 | { |
4129 | struct stripe_head_state s; | 4175 | struct stripe_head_state s; |
@@ -4146,6 +4192,8 @@ static void handle_stripe(struct stripe_head *sh) | |||
4146 | return; | 4192 | return; |
4147 | } | 4193 | } |
4148 | 4194 | ||
4195 | check_break_stripe_batch_list(sh); | ||
4196 | |||
4149 | if (test_bit(STRIPE_SYNC_REQUESTED, &sh->state)) { | 4197 | if (test_bit(STRIPE_SYNC_REQUESTED, &sh->state)) { |
4150 | spin_lock(&sh->stripe_lock); | 4198 | spin_lock(&sh->stripe_lock); |
4151 | /* Cannot process 'sync' concurrently with 'discard' */ | 4199 | /* Cannot process 'sync' concurrently with 'discard' */ |