diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-11-05 14:34:07 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-11-05 14:34:07 -0400 |
commit | 6c286e812d5f306ebf991c3f78ebc511121896e0 (patch) | |
tree | db4345eba03a3245d2377e60d92275d1776e4e7a | |
parent | e12d8d512f090b6c540c7f75bf879f0d6a908587 (diff) | |
parent | 1217e1d1999ed6c9c1e1b1acae0a74ab70464ae2 (diff) |
Merge tag 'md/4.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/shli/md
Pull MD fixes from Shaohua Li:
"There are several bug fixes queued:
- fix raid5-cache recovery bugs
- fix discard IO error handling for raid1/10
- fix array sync writes bogus position to superblock
- fix IO error handling for raid array with external metadata"
* tag 'md/4.9-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/shli/md:
md: be careful not lot leak internal curr_resync value into metadata. -- (all)
raid1: handle read error also in readonly mode
raid5-cache: correct condition for empty metadata write
md: report 'write_pending' state when array in sync
md/raid5: write an empty meta-block when creating log super-block
md/raid5: initialize next_checkpoint field before use
RAID10: ignore discard error
RAID1: ignore discard error
-rw-r--r-- | drivers/md/md.c | 10 | ||||
-rw-r--r-- | drivers/md/raid1.c | 26 | ||||
-rw-r--r-- | drivers/md/raid10.c | 7 | ||||
-rw-r--r-- | drivers/md/raid5-cache.c | 6 |
4 files changed, 30 insertions, 19 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index eac84d8ff724..2089d46b0eb8 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -3887,10 +3887,10 @@ array_state_show(struct mddev *mddev, char *page) | |||
3887 | st = read_auto; | 3887 | st = read_auto; |
3888 | break; | 3888 | break; |
3889 | case 0: | 3889 | case 0: |
3890 | if (mddev->in_sync) | 3890 | if (test_bit(MD_CHANGE_PENDING, &mddev->flags)) |
3891 | st = clean; | ||
3892 | else if (test_bit(MD_CHANGE_PENDING, &mddev->flags)) | ||
3893 | st = write_pending; | 3891 | st = write_pending; |
3892 | else if (mddev->in_sync) | ||
3893 | st = clean; | ||
3894 | else if (mddev->safemode) | 3894 | else if (mddev->safemode) |
3895 | st = active_idle; | 3895 | st = active_idle; |
3896 | else | 3896 | else |
@@ -8144,14 +8144,14 @@ void md_do_sync(struct md_thread *thread) | |||
8144 | 8144 | ||
8145 | if (!test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && | 8145 | if (!test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && |
8146 | !test_bit(MD_RECOVERY_INTR, &mddev->recovery) && | 8146 | !test_bit(MD_RECOVERY_INTR, &mddev->recovery) && |
8147 | mddev->curr_resync > 2) { | 8147 | mddev->curr_resync > 3) { |
8148 | mddev->curr_resync_completed = mddev->curr_resync; | 8148 | mddev->curr_resync_completed = mddev->curr_resync; |
8149 | sysfs_notify(&mddev->kobj, NULL, "sync_completed"); | 8149 | sysfs_notify(&mddev->kobj, NULL, "sync_completed"); |
8150 | } | 8150 | } |
8151 | mddev->pers->sync_request(mddev, max_sectors, &skipped); | 8151 | mddev->pers->sync_request(mddev, max_sectors, &skipped); |
8152 | 8152 | ||
8153 | if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) && | 8153 | if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) && |
8154 | mddev->curr_resync > 2) { | 8154 | mddev->curr_resync > 3) { |
8155 | if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { | 8155 | if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { |
8156 | if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { | 8156 | if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { |
8157 | if (mddev->curr_resync >= mddev->recovery_cp) { | 8157 | if (mddev->curr_resync >= mddev->recovery_cp) { |
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 1961d827dbd1..29e2df5cd77b 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c | |||
@@ -403,11 +403,14 @@ static void raid1_end_write_request(struct bio *bio) | |||
403 | struct bio *to_put = NULL; | 403 | struct bio *to_put = NULL; |
404 | int mirror = find_bio_disk(r1_bio, bio); | 404 | int mirror = find_bio_disk(r1_bio, bio); |
405 | struct md_rdev *rdev = conf->mirrors[mirror].rdev; | 405 | struct md_rdev *rdev = conf->mirrors[mirror].rdev; |
406 | bool discard_error; | ||
407 | |||
408 | discard_error = bio->bi_error && bio_op(bio) == REQ_OP_DISCARD; | ||
406 | 409 | ||
407 | /* | 410 | /* |
408 | * 'one mirror IO has finished' event handler: | 411 | * 'one mirror IO has finished' event handler: |
409 | */ | 412 | */ |
410 | if (bio->bi_error) { | 413 | if (bio->bi_error && !discard_error) { |
411 | set_bit(WriteErrorSeen, &rdev->flags); | 414 | set_bit(WriteErrorSeen, &rdev->flags); |
412 | if (!test_and_set_bit(WantReplacement, &rdev->flags)) | 415 | if (!test_and_set_bit(WantReplacement, &rdev->flags)) |
413 | set_bit(MD_RECOVERY_NEEDED, & | 416 | set_bit(MD_RECOVERY_NEEDED, & |
@@ -444,7 +447,7 @@ static void raid1_end_write_request(struct bio *bio) | |||
444 | 447 | ||
445 | /* Maybe we can clear some bad blocks. */ | 448 | /* Maybe we can clear some bad blocks. */ |
446 | if (is_badblock(rdev, r1_bio->sector, r1_bio->sectors, | 449 | if (is_badblock(rdev, r1_bio->sector, r1_bio->sectors, |
447 | &first_bad, &bad_sectors)) { | 450 | &first_bad, &bad_sectors) && !discard_error) { |
448 | r1_bio->bios[mirror] = IO_MADE_GOOD; | 451 | r1_bio->bios[mirror] = IO_MADE_GOOD; |
449 | set_bit(R1BIO_MadeGood, &r1_bio->state); | 452 | set_bit(R1BIO_MadeGood, &r1_bio->state); |
450 | } | 453 | } |
@@ -2294,17 +2297,23 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio) | |||
2294 | * This is all done synchronously while the array is | 2297 | * This is all done synchronously while the array is |
2295 | * frozen | 2298 | * frozen |
2296 | */ | 2299 | */ |
2300 | |||
2301 | bio = r1_bio->bios[r1_bio->read_disk]; | ||
2302 | bdevname(bio->bi_bdev, b); | ||
2303 | bio_put(bio); | ||
2304 | r1_bio->bios[r1_bio->read_disk] = NULL; | ||
2305 | |||
2297 | if (mddev->ro == 0) { | 2306 | if (mddev->ro == 0) { |
2298 | freeze_array(conf, 1); | 2307 | freeze_array(conf, 1); |
2299 | fix_read_error(conf, r1_bio->read_disk, | 2308 | fix_read_error(conf, r1_bio->read_disk, |
2300 | r1_bio->sector, r1_bio->sectors); | 2309 | r1_bio->sector, r1_bio->sectors); |
2301 | unfreeze_array(conf); | 2310 | unfreeze_array(conf); |
2302 | } else | 2311 | } else { |
2303 | md_error(mddev, conf->mirrors[r1_bio->read_disk].rdev); | 2312 | r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED; |
2313 | } | ||
2314 | |||
2304 | rdev_dec_pending(conf->mirrors[r1_bio->read_disk].rdev, conf->mddev); | 2315 | rdev_dec_pending(conf->mirrors[r1_bio->read_disk].rdev, conf->mddev); |
2305 | 2316 | ||
2306 | bio = r1_bio->bios[r1_bio->read_disk]; | ||
2307 | bdevname(bio->bi_bdev, b); | ||
2308 | read_more: | 2317 | read_more: |
2309 | disk = read_balance(conf, r1_bio, &max_sectors); | 2318 | disk = read_balance(conf, r1_bio, &max_sectors); |
2310 | if (disk == -1) { | 2319 | if (disk == -1) { |
@@ -2315,11 +2324,6 @@ read_more: | |||
2315 | } else { | 2324 | } else { |
2316 | const unsigned long do_sync | 2325 | const unsigned long do_sync |
2317 | = r1_bio->master_bio->bi_opf & REQ_SYNC; | 2326 | = r1_bio->master_bio->bi_opf & REQ_SYNC; |
2318 | if (bio) { | ||
2319 | r1_bio->bios[r1_bio->read_disk] = | ||
2320 | mddev->ro ? IO_BLOCKED : NULL; | ||
2321 | bio_put(bio); | ||
2322 | } | ||
2323 | r1_bio->read_disk = disk; | 2327 | r1_bio->read_disk = disk; |
2324 | bio = bio_clone_mddev(r1_bio->master_bio, GFP_NOIO, mddev); | 2328 | bio = bio_clone_mddev(r1_bio->master_bio, GFP_NOIO, mddev); |
2325 | bio_trim(bio, r1_bio->sector - bio->bi_iter.bi_sector, | 2329 | bio_trim(bio, r1_bio->sector - bio->bi_iter.bi_sector, |
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index be1a9fca3b2d..39fddda2fef2 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c | |||
@@ -447,6 +447,9 @@ static void raid10_end_write_request(struct bio *bio) | |||
447 | struct r10conf *conf = r10_bio->mddev->private; | 447 | struct r10conf *conf = r10_bio->mddev->private; |
448 | int slot, repl; | 448 | int slot, repl; |
449 | struct md_rdev *rdev = NULL; | 449 | struct md_rdev *rdev = NULL; |
450 | bool discard_error; | ||
451 | |||
452 | discard_error = bio->bi_error && bio_op(bio) == REQ_OP_DISCARD; | ||
450 | 453 | ||
451 | dev = find_bio_disk(conf, r10_bio, bio, &slot, &repl); | 454 | dev = find_bio_disk(conf, r10_bio, bio, &slot, &repl); |
452 | 455 | ||
@@ -460,7 +463,7 @@ static void raid10_end_write_request(struct bio *bio) | |||
460 | /* | 463 | /* |
461 | * this branch is our 'one mirror IO has finished' event handler: | 464 | * this branch is our 'one mirror IO has finished' event handler: |
462 | */ | 465 | */ |
463 | if (bio->bi_error) { | 466 | if (bio->bi_error && !discard_error) { |
464 | if (repl) | 467 | if (repl) |
465 | /* Never record new bad blocks to replacement, | 468 | /* Never record new bad blocks to replacement, |
466 | * just fail it. | 469 | * just fail it. |
@@ -503,7 +506,7 @@ static void raid10_end_write_request(struct bio *bio) | |||
503 | if (is_badblock(rdev, | 506 | if (is_badblock(rdev, |
504 | r10_bio->devs[slot].addr, | 507 | r10_bio->devs[slot].addr, |
505 | r10_bio->sectors, | 508 | r10_bio->sectors, |
506 | &first_bad, &bad_sectors)) { | 509 | &first_bad, &bad_sectors) && !discard_error) { |
507 | bio_put(bio); | 510 | bio_put(bio); |
508 | if (repl) | 511 | if (repl) |
509 | r10_bio->devs[slot].repl_bio = IO_MADE_GOOD; | 512 | r10_bio->devs[slot].repl_bio = IO_MADE_GOOD; |
diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c index 1b1ab4a1d132..a227a9f3ee65 100644 --- a/drivers/md/raid5-cache.c +++ b/drivers/md/raid5-cache.c | |||
@@ -1087,7 +1087,7 @@ static int r5l_recovery_log(struct r5l_log *log) | |||
1087 | * 1's seq + 10 and let superblock points to meta2. The same recovery will | 1087 | * 1's seq + 10 and let superblock points to meta2. The same recovery will |
1088 | * not think meta 3 is a valid meta, because its seq doesn't match | 1088 | * not think meta 3 is a valid meta, because its seq doesn't match |
1089 | */ | 1089 | */ |
1090 | if (ctx.seq > log->last_cp_seq + 1) { | 1090 | if (ctx.seq > log->last_cp_seq) { |
1091 | int ret; | 1091 | int ret; |
1092 | 1092 | ||
1093 | ret = r5l_log_write_empty_meta_block(log, ctx.pos, ctx.seq + 10); | 1093 | ret = r5l_log_write_empty_meta_block(log, ctx.pos, ctx.seq + 10); |
@@ -1096,6 +1096,8 @@ static int r5l_recovery_log(struct r5l_log *log) | |||
1096 | log->seq = ctx.seq + 11; | 1096 | log->seq = ctx.seq + 11; |
1097 | log->log_start = r5l_ring_add(log, ctx.pos, BLOCK_SECTORS); | 1097 | log->log_start = r5l_ring_add(log, ctx.pos, BLOCK_SECTORS); |
1098 | r5l_write_super(log, ctx.pos); | 1098 | r5l_write_super(log, ctx.pos); |
1099 | log->last_checkpoint = ctx.pos; | ||
1100 | log->next_checkpoint = ctx.pos; | ||
1099 | } else { | 1101 | } else { |
1100 | log->log_start = ctx.pos; | 1102 | log->log_start = ctx.pos; |
1101 | log->seq = ctx.seq; | 1103 | log->seq = ctx.seq; |
@@ -1154,6 +1156,7 @@ create: | |||
1154 | if (create_super) { | 1156 | if (create_super) { |
1155 | log->last_cp_seq = prandom_u32(); | 1157 | log->last_cp_seq = prandom_u32(); |
1156 | cp = 0; | 1158 | cp = 0; |
1159 | r5l_log_write_empty_meta_block(log, cp, log->last_cp_seq); | ||
1157 | /* | 1160 | /* |
1158 | * Make sure super points to correct address. Log might have | 1161 | * Make sure super points to correct address. Log might have |
1159 | * data very soon. If super hasn't correct log tail address, | 1162 | * data very soon. If super hasn't correct log tail address, |
@@ -1168,6 +1171,7 @@ create: | |||
1168 | if (log->max_free_space > RECLAIM_MAX_FREE_SPACE) | 1171 | if (log->max_free_space > RECLAIM_MAX_FREE_SPACE) |
1169 | log->max_free_space = RECLAIM_MAX_FREE_SPACE; | 1172 | log->max_free_space = RECLAIM_MAX_FREE_SPACE; |
1170 | log->last_checkpoint = cp; | 1173 | log->last_checkpoint = cp; |
1174 | log->next_checkpoint = cp; | ||
1171 | 1175 | ||
1172 | __free_page(page); | 1176 | __free_page(page); |
1173 | 1177 | ||