diff options
| -rw-r--r-- | drivers/md/md.c | 77 | ||||
| -rw-r--r-- | drivers/md/md.h | 25 | ||||
| -rw-r--r-- | drivers/md/raid1.c | 3 | ||||
| -rw-r--r-- | drivers/md/raid10.c | 3 | ||||
| -rw-r--r-- | drivers/md/raid5.c | 4 |
5 files changed, 85 insertions, 27 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 1520d18c5af5..a6b6471da2bc 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
| @@ -2341,8 +2341,18 @@ repeat: | |||
| 2341 | if (!mddev->persistent) { | 2341 | if (!mddev->persistent) { |
| 2342 | clear_bit(MD_CHANGE_CLEAN, &mddev->flags); | 2342 | clear_bit(MD_CHANGE_CLEAN, &mddev->flags); |
| 2343 | clear_bit(MD_CHANGE_DEVS, &mddev->flags); | 2343 | clear_bit(MD_CHANGE_DEVS, &mddev->flags); |
| 2344 | if (!mddev->external) | 2344 | if (!mddev->external) { |
| 2345 | clear_bit(MD_CHANGE_PENDING, &mddev->flags); | 2345 | clear_bit(MD_CHANGE_PENDING, &mddev->flags); |
| 2346 | list_for_each_entry(rdev, &mddev->disks, same_set) { | ||
| 2347 | if (rdev->badblocks.changed) { | ||
| 2348 | md_ack_all_badblocks(&rdev->badblocks); | ||
| 2349 | md_error(mddev, rdev); | ||
| 2350 | } | ||
| 2351 | clear_bit(Blocked, &rdev->flags); | ||
| 2352 | clear_bit(BlockedBadBlocks, &rdev->flags); | ||
| 2353 | wake_up(&rdev->blocked_wait); | ||
| 2354 | } | ||
| 2355 | } | ||
| 2346 | wake_up(&mddev->sb_wait); | 2356 | wake_up(&mddev->sb_wait); |
| 2347 | return; | 2357 | return; |
| 2348 | } | 2358 | } |
| @@ -2399,9 +2409,12 @@ repeat: | |||
| 2399 | mddev->events --; | 2409 | mddev->events --; |
| 2400 | } | 2410 | } |
| 2401 | 2411 | ||
| 2402 | list_for_each_entry(rdev, &mddev->disks, same_set) | 2412 | list_for_each_entry(rdev, &mddev->disks, same_set) { |
| 2403 | if (rdev->badblocks.changed) | 2413 | if (rdev->badblocks.changed) |
| 2404 | any_badblocks_changed++; | 2414 | any_badblocks_changed++; |
| 2415 | if (test_bit(Faulty, &rdev->flags)) | ||
| 2416 | set_bit(FaultRecorded, &rdev->flags); | ||
| 2417 | } | ||
| 2405 | 2418 | ||
| 2406 | sync_sbs(mddev, nospares); | 2419 | sync_sbs(mddev, nospares); |
| 2407 | spin_unlock_irq(&mddev->write_lock); | 2420 | spin_unlock_irq(&mddev->write_lock); |
| @@ -2458,9 +2471,15 @@ repeat: | |||
| 2458 | if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) | 2471 | if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) |
| 2459 | sysfs_notify(&mddev->kobj, NULL, "sync_completed"); | 2472 | sysfs_notify(&mddev->kobj, NULL, "sync_completed"); |
| 2460 | 2473 | ||
| 2461 | if (any_badblocks_changed) | 2474 | list_for_each_entry(rdev, &mddev->disks, same_set) { |
| 2462 | list_for_each_entry(rdev, &mddev->disks, same_set) | 2475 | if (test_and_clear_bit(FaultRecorded, &rdev->flags)) |
| 2476 | clear_bit(Blocked, &rdev->flags); | ||
| 2477 | |||
| 2478 | if (any_badblocks_changed) | ||
| 2463 | md_ack_all_badblocks(&rdev->badblocks); | 2479 | md_ack_all_badblocks(&rdev->badblocks); |
| 2480 | clear_bit(BlockedBadBlocks, &rdev->flags); | ||
| 2481 | wake_up(&rdev->blocked_wait); | ||
| 2482 | } | ||
| 2464 | } | 2483 | } |
| 2465 | 2484 | ||
| 2466 | /* words written to sysfs files may, or may not, be \n terminated. | 2485 | /* words written to sysfs files may, or may not, be \n terminated. |
| @@ -2495,7 +2514,8 @@ state_show(mdk_rdev_t *rdev, char *page) | |||
| 2495 | char *sep = ""; | 2514 | char *sep = ""; |
| 2496 | size_t len = 0; | 2515 | size_t len = 0; |
| 2497 | 2516 | ||
| 2498 | if (test_bit(Faulty, &rdev->flags)) { | 2517 | if (test_bit(Faulty, &rdev->flags) || |
| 2518 | rdev->badblocks.unacked_exist) { | ||
| 2499 | len+= sprintf(page+len, "%sfaulty",sep); | 2519 | len+= sprintf(page+len, "%sfaulty",sep); |
| 2500 | sep = ","; | 2520 | sep = ","; |
| 2501 | } | 2521 | } |
| @@ -2507,7 +2527,8 @@ state_show(mdk_rdev_t *rdev, char *page) | |||
| 2507 | len += sprintf(page+len, "%swrite_mostly",sep); | 2527 | len += sprintf(page+len, "%swrite_mostly",sep); |
| 2508 | sep = ","; | 2528 | sep = ","; |
| 2509 | } | 2529 | } |
| 2510 | if (test_bit(Blocked, &rdev->flags)) { | 2530 | if (test_bit(Blocked, &rdev->flags) || |
| 2531 | rdev->badblocks.unacked_exist) { | ||
| 2511 | len += sprintf(page+len, "%sblocked", sep); | 2532 | len += sprintf(page+len, "%sblocked", sep); |
| 2512 | sep = ","; | 2533 | sep = ","; |
| 2513 | } | 2534 | } |
| @@ -2527,12 +2548,12 @@ static ssize_t | |||
| 2527 | state_store(mdk_rdev_t *rdev, const char *buf, size_t len) | 2548 | state_store(mdk_rdev_t *rdev, const char *buf, size_t len) |
| 2528 | { | 2549 | { |
| 2529 | /* can write | 2550 | /* can write |
| 2530 | * faulty - simulates and error | 2551 | * faulty - simulates an error |
| 2531 | * remove - disconnects the device | 2552 | * remove - disconnects the device |
| 2532 | * writemostly - sets write_mostly | 2553 | * writemostly - sets write_mostly |
| 2533 | * -writemostly - clears write_mostly | 2554 | * -writemostly - clears write_mostly |
| 2534 | * blocked - sets the Blocked flag | 2555 | * blocked - sets the Blocked flags |
| 2535 | * -blocked - clears the Blocked flag | 2556 | * -blocked - clears the Blocked and possibly simulates an error |
| 2536 | * insync - sets Insync providing device isn't active | 2557 | * insync - sets Insync providing device isn't active |
| 2537 | * write_error - sets WriteErrorSeen | 2558 | * write_error - sets WriteErrorSeen |
| 2538 | * -write_error - clears WriteErrorSeen | 2559 | * -write_error - clears WriteErrorSeen |
| @@ -2562,7 +2583,15 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len) | |||
| 2562 | set_bit(Blocked, &rdev->flags); | 2583 | set_bit(Blocked, &rdev->flags); |
| 2563 | err = 0; | 2584 | err = 0; |
| 2564 | } else if (cmd_match(buf, "-blocked")) { | 2585 | } else if (cmd_match(buf, "-blocked")) { |
| 2586 | if (!test_bit(Faulty, &rdev->flags) && | ||
| 2587 | test_bit(BlockedBadBlocks, &rdev->flags)) { | ||
| 2588 | /* metadata handler doesn't understand badblocks, | ||
| 2589 | * so we need to fail the device | ||
| 2590 | */ | ||
| 2591 | md_error(rdev->mddev, rdev); | ||
| 2592 | } | ||
| 2565 | clear_bit(Blocked, &rdev->flags); | 2593 | clear_bit(Blocked, &rdev->flags); |
| 2594 | clear_bit(BlockedBadBlocks, &rdev->flags); | ||
| 2566 | wake_up(&rdev->blocked_wait); | 2595 | wake_up(&rdev->blocked_wait); |
| 2567 | set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery); | 2596 | set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery); |
| 2568 | md_wakeup_thread(rdev->mddev->thread); | 2597 | md_wakeup_thread(rdev->mddev->thread); |
| @@ -2881,7 +2910,11 @@ static ssize_t bb_show(mdk_rdev_t *rdev, char *page) | |||
| 2881 | } | 2910 | } |
| 2882 | static ssize_t bb_store(mdk_rdev_t *rdev, const char *page, size_t len) | 2911 | static ssize_t bb_store(mdk_rdev_t *rdev, const char *page, size_t len) |
| 2883 | { | 2912 | { |
| 2884 | return badblocks_store(&rdev->badblocks, page, len, 0); | 2913 | int rv = badblocks_store(&rdev->badblocks, page, len, 0); |
| 2914 | /* Maybe that ack was all we needed */ | ||
| 2915 | if (test_and_clear_bit(BlockedBadBlocks, &rdev->flags)) | ||
| 2916 | wake_up(&rdev->blocked_wait); | ||
| 2917 | return rv; | ||
| 2885 | } | 2918 | } |
| 2886 | static struct rdev_sysfs_entry rdev_bad_blocks = | 2919 | static struct rdev_sysfs_entry rdev_bad_blocks = |
| 2887 | __ATTR(bad_blocks, S_IRUGO|S_IWUSR, bb_show, bb_store); | 2920 | __ATTR(bad_blocks, S_IRUGO|S_IWUSR, bb_show, bb_store); |
| @@ -6398,18 +6431,7 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev) | |||
| 6398 | if (!rdev || test_bit(Faulty, &rdev->flags)) | 6431 | if (!rdev || test_bit(Faulty, &rdev->flags)) |
| 6399 | return; | 6432 | return; |
| 6400 | 6433 | ||
| 6401 | if (mddev->external) | 6434 | if (!mddev->pers || !mddev->pers->error_handler) |
| 6402 | set_bit(Blocked, &rdev->flags); | ||
| 6403 | /* | ||
| 6404 | dprintk("md_error dev:%s, rdev:(%d:%d), (caller: %p,%p,%p,%p).\n", | ||
| 6405 | mdname(mddev), | ||
| 6406 | MAJOR(rdev->bdev->bd_dev), MINOR(rdev->bdev->bd_dev), | ||
| 6407 | __builtin_return_address(0),__builtin_return_address(1), | ||
| 6408 | __builtin_return_address(2),__builtin_return_address(3)); | ||
| 6409 | */ | ||
| 6410 | if (!mddev->pers) | ||
| 6411 | return; | ||
| 6412 | if (!mddev->pers->error_handler) | ||
| 6413 | return; | 6435 | return; |
| 6414 | mddev->pers->error_handler(mddev,rdev); | 6436 | mddev->pers->error_handler(mddev,rdev); |
| 6415 | if (mddev->degraded) | 6437 | if (mddev->degraded) |
| @@ -7286,8 +7308,7 @@ static int remove_and_add_spares(mddev_t *mddev) | |||
| 7286 | list_for_each_entry(rdev, &mddev->disks, same_set) { | 7308 | list_for_each_entry(rdev, &mddev->disks, same_set) { |
| 7287 | if (rdev->raid_disk >= 0 && | 7309 | if (rdev->raid_disk >= 0 && |
| 7288 | !test_bit(In_sync, &rdev->flags) && | 7310 | !test_bit(In_sync, &rdev->flags) && |
| 7289 | !test_bit(Faulty, &rdev->flags) && | 7311 | !test_bit(Faulty, &rdev->flags)) |
| 7290 | !test_bit(Blocked, &rdev->flags)) | ||
| 7291 | spares++; | 7312 | spares++; |
| 7292 | if (rdev->raid_disk < 0 | 7313 | if (rdev->raid_disk < 0 |
| 7293 | && !test_bit(Faulty, &rdev->flags)) { | 7314 | && !test_bit(Faulty, &rdev->flags)) { |
| @@ -7533,7 +7554,8 @@ void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev) | |||
| 7533 | { | 7554 | { |
| 7534 | sysfs_notify_dirent_safe(rdev->sysfs_state); | 7555 | sysfs_notify_dirent_safe(rdev->sysfs_state); |
| 7535 | wait_event_timeout(rdev->blocked_wait, | 7556 | wait_event_timeout(rdev->blocked_wait, |
| 7536 | !test_bit(Blocked, &rdev->flags), | 7557 | !test_bit(Blocked, &rdev->flags) && |
| 7558 | !test_bit(BlockedBadBlocks, &rdev->flags), | ||
| 7537 | msecs_to_jiffies(5000)); | 7559 | msecs_to_jiffies(5000)); |
| 7538 | rdev_dec_pending(rdev, mddev); | 7560 | rdev_dec_pending(rdev, mddev); |
| 7539 | } | 7561 | } |
| @@ -7779,6 +7801,8 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors, | |||
| 7779 | } | 7801 | } |
| 7780 | 7802 | ||
| 7781 | bb->changed = 1; | 7803 | bb->changed = 1; |
| 7804 | if (!acknowledged) | ||
| 7805 | bb->unacked_exist = 1; | ||
| 7782 | write_sequnlock_irq(&bb->lock); | 7806 | write_sequnlock_irq(&bb->lock); |
| 7783 | 7807 | ||
| 7784 | return rv; | 7808 | return rv; |
| @@ -7923,6 +7947,7 @@ void md_ack_all_badblocks(struct badblocks *bb) | |||
| 7923 | p[i] = BB_MAKE(start, len, 1); | 7947 | p[i] = BB_MAKE(start, len, 1); |
| 7924 | } | 7948 | } |
| 7925 | } | 7949 | } |
| 7950 | bb->unacked_exist = 0; | ||
| 7926 | } | 7951 | } |
| 7927 | write_sequnlock_irq(&bb->lock); | 7952 | write_sequnlock_irq(&bb->lock); |
| 7928 | } | 7953 | } |
| @@ -7970,6 +7995,8 @@ retry: | |||
| 7970 | (unsigned long long)s << bb->shift, | 7995 | (unsigned long long)s << bb->shift, |
| 7971 | length << bb->shift); | 7996 | length << bb->shift); |
| 7972 | } | 7997 | } |
| 7998 | if (unack && len == 0) | ||
| 7999 | bb->unacked_exist = 0; | ||
| 7973 | 8000 | ||
| 7974 | if (read_seqretry(&bb->lock, seq)) | 8001 | if (read_seqretry(&bb->lock, seq)) |
| 7975 | goto retry; | 8002 | goto retry; |
diff --git a/drivers/md/md.h b/drivers/md/md.h index fa4b607854ac..1e586bb4452e 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h | |||
| @@ -81,12 +81,29 @@ struct mdk_rdev_s | |||
| 81 | #define In_sync 2 /* device is in_sync with rest of array */ | 81 | #define In_sync 2 /* device is in_sync with rest of array */ |
| 82 | #define WriteMostly 4 /* Avoid reading if at all possible */ | 82 | #define WriteMostly 4 /* Avoid reading if at all possible */ |
| 83 | #define AutoDetected 7 /* added by auto-detect */ | 83 | #define AutoDetected 7 /* added by auto-detect */ |
| 84 | #define Blocked 8 /* An error occurred on an externally | 84 | #define Blocked 8 /* An error occurred but has not yet |
| 85 | * managed array, don't allow writes | 85 | * been acknowledged by the metadata |
| 86 | * handler, so don't allow writes | ||
| 86 | * until it is cleared */ | 87 | * until it is cleared */ |
| 87 | #define WriteErrorSeen 9 /* A write error has been seen on this | 88 | #define WriteErrorSeen 9 /* A write error has been seen on this |
| 88 | * device | 89 | * device |
| 89 | */ | 90 | */ |
| 91 | #define FaultRecorded 10 /* Intermediate state for clearing | ||
| 92 | * Blocked. The Fault is/will-be | ||
| 93 | * recorded in the metadata, but that | ||
| 94 | * metadata hasn't been stored safely | ||
| 95 | * on disk yet. | ||
| 96 | */ | ||
| 97 | #define BlockedBadBlocks 11 /* A writer is blocked because they | ||
| 98 | * found an unacknowledged bad-block. | ||
| 99 | * This can safely be cleared at any | ||
| 100 | * time, and the writer will re-check. | ||
| 101 | * It may be set at any time, and at | ||
| 102 | * worst the writer will timeout and | ||
| 103 | * re-check. So setting it as | ||
| 104 | * accurately as possible is good, but | ||
| 105 | * not absolutely critical. | ||
| 106 | */ | ||
| 90 | wait_queue_head_t blocked_wait; | 107 | wait_queue_head_t blocked_wait; |
| 91 | 108 | ||
| 92 | int desc_nr; /* descriptor index in the superblock */ | 109 | int desc_nr; /* descriptor index in the superblock */ |
| @@ -124,6 +141,10 @@ struct mdk_rdev_s | |||
| 124 | 141 | ||
| 125 | struct badblocks { | 142 | struct badblocks { |
| 126 | int count; /* count of bad blocks */ | 143 | int count; /* count of bad blocks */ |
| 144 | int unacked_exist; /* there probably are unacknowledged | ||
| 145 | * bad blocks. This is only cleared | ||
| 146 | * when a read discovers none | ||
| 147 | */ | ||
| 127 | int shift; /* shift from sectors to block size | 148 | int shift; /* shift from sectors to block size |
| 128 | * a -ve shift means badblocks are | 149 | * a -ve shift means badblocks are |
| 129 | * disabled.*/ | 150 | * disabled.*/ |
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 8c31c39b6f8c..4d40d9d54a20 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c | |||
| @@ -1059,6 +1059,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) | |||
| 1059 | conf->recovery_disabled = mddev->recovery_disabled; | 1059 | conf->recovery_disabled = mddev->recovery_disabled; |
| 1060 | return; | 1060 | return; |
| 1061 | } | 1061 | } |
| 1062 | set_bit(Blocked, &rdev->flags); | ||
| 1062 | if (test_and_clear_bit(In_sync, &rdev->flags)) { | 1063 | if (test_and_clear_bit(In_sync, &rdev->flags)) { |
| 1063 | unsigned long flags; | 1064 | unsigned long flags; |
| 1064 | spin_lock_irqsave(&conf->device_lock, flags); | 1065 | spin_lock_irqsave(&conf->device_lock, flags); |
| @@ -1751,6 +1752,8 @@ read_more: | |||
| 1751 | generic_make_request(r1_bio->bios[r1_bio->read_disk]); | 1752 | generic_make_request(r1_bio->bios[r1_bio->read_disk]); |
| 1752 | } | 1753 | } |
| 1753 | cond_resched(); | 1754 | cond_resched(); |
| 1755 | if (mddev->flags & ~(1<<MD_CHANGE_PENDING)) | ||
| 1756 | md_check_recovery(mddev); | ||
| 1754 | } | 1757 | } |
| 1755 | blk_finish_plug(&plug); | 1758 | blk_finish_plug(&plug); |
| 1756 | } | 1759 | } |
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 8aadd2f52dc8..fe6692e62215 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c | |||
| @@ -1021,6 +1021,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) | |||
| 1021 | */ | 1021 | */ |
| 1022 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); | 1022 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); |
| 1023 | } | 1023 | } |
| 1024 | set_bit(Blocked, &rdev->flags); | ||
| 1024 | set_bit(Faulty, &rdev->flags); | 1025 | set_bit(Faulty, &rdev->flags); |
| 1025 | set_bit(MD_CHANGE_DEVS, &mddev->flags); | 1026 | set_bit(MD_CHANGE_DEVS, &mddev->flags); |
| 1026 | printk(KERN_ALERT | 1027 | printk(KERN_ALERT |
| @@ -1703,6 +1704,8 @@ static void raid10d(mddev_t *mddev) | |||
| 1703 | } | 1704 | } |
| 1704 | } | 1705 | } |
| 1705 | cond_resched(); | 1706 | cond_resched(); |
| 1707 | if (mddev->flags & ~(1<<MD_CHANGE_PENDING)) | ||
| 1708 | md_check_recovery(mddev); | ||
| 1706 | } | 1709 | } |
| 1707 | blk_finish_plug(&plug); | 1710 | blk_finish_plug(&plug); |
| 1708 | } | 1711 | } |
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 719445004dd9..304389ba5e27 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
| @@ -1706,6 +1706,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) | |||
| 1706 | */ | 1706 | */ |
| 1707 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); | 1707 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); |
| 1708 | } | 1708 | } |
| 1709 | set_bit(Blocked, &rdev->flags); | ||
| 1709 | set_bit(Faulty, &rdev->flags); | 1710 | set_bit(Faulty, &rdev->flags); |
| 1710 | set_bit(MD_CHANGE_DEVS, &mddev->flags); | 1711 | set_bit(MD_CHANGE_DEVS, &mddev->flags); |
| 1711 | printk(KERN_ALERT | 1712 | printk(KERN_ALERT |
| @@ -4143,6 +4144,9 @@ static void raid5d(mddev_t *mddev) | |||
| 4143 | release_stripe(sh); | 4144 | release_stripe(sh); |
| 4144 | cond_resched(); | 4145 | cond_resched(); |
| 4145 | 4146 | ||
| 4147 | if (mddev->flags & ~(1<<MD_CHANGE_PENDING)) | ||
| 4148 | md_check_recovery(mddev); | ||
| 4149 | |||
| 4146 | spin_lock_irq(&conf->device_lock); | 4150 | spin_lock_irq(&conf->device_lock); |
| 4147 | } | 4151 | } |
| 4148 | pr_debug("%d stripes handled\n", handled); | 4152 | pr_debug("%d stripes handled\n", handled); |
