diff options
Diffstat (limited to 'drivers/md')
-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); |