diff options
author | Dan Williams <dan.j.williams@intel.com> | 2008-04-30 03:52:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-30 11:29:33 -0400 |
commit | 6bfe0b499082fd3950429017cd8ebf2a6c458aa5 (patch) | |
tree | 81476cf7f7ddbea135bdb93729e0bffae0e7c163 /drivers/md/raid1.c | |
parent | 11e2ede0228ee0f81ccacd15894908c3bf241f73 (diff) |
md: support blocking writes to an array on device failure
Allows a userspace metadata handler to take action upon detecting a device
failure.
Based on an original patch by Neil Brown.
Changes:
-added blocked_wait waitqueue to rdev
-don't qualify Blocked with Faulty always let userspace block writes
-added md_wait_for_blocked_rdev to wait for the block device to be clear, if
userspace misses the notification another one is sent every 5 seconds
-set MD_RECOVERY_NEEDED after clearing "blocked"
-kill DoBlock flag, just test mddev->external
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/md/raid1.c')
-rw-r--r-- | drivers/md/raid1.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 9fd473a6dbf5..6778b7cb39bd 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c | |||
@@ -773,7 +773,6 @@ static int make_request(struct request_queue *q, struct bio * bio) | |||
773 | r1bio_t *r1_bio; | 773 | r1bio_t *r1_bio; |
774 | struct bio *read_bio; | 774 | struct bio *read_bio; |
775 | int i, targets = 0, disks; | 775 | int i, targets = 0, disks; |
776 | mdk_rdev_t *rdev; | ||
777 | struct bitmap *bitmap = mddev->bitmap; | 776 | struct bitmap *bitmap = mddev->bitmap; |
778 | unsigned long flags; | 777 | unsigned long flags; |
779 | struct bio_list bl; | 778 | struct bio_list bl; |
@@ -781,6 +780,7 @@ static int make_request(struct request_queue *q, struct bio * bio) | |||
781 | const int rw = bio_data_dir(bio); | 780 | const int rw = bio_data_dir(bio); |
782 | const int do_sync = bio_sync(bio); | 781 | const int do_sync = bio_sync(bio); |
783 | int do_barriers; | 782 | int do_barriers; |
783 | mdk_rdev_t *blocked_rdev; | ||
784 | 784 | ||
785 | /* | 785 | /* |
786 | * Register the new request and wait if the reconstruction | 786 | * Register the new request and wait if the reconstruction |
@@ -862,10 +862,17 @@ static int make_request(struct request_queue *q, struct bio * bio) | |||
862 | first = 0; | 862 | first = 0; |
863 | } | 863 | } |
864 | #endif | 864 | #endif |
865 | retry_write: | ||
866 | blocked_rdev = NULL; | ||
865 | rcu_read_lock(); | 867 | rcu_read_lock(); |
866 | for (i = 0; i < disks; i++) { | 868 | for (i = 0; i < disks; i++) { |
867 | if ((rdev=rcu_dereference(conf->mirrors[i].rdev)) != NULL && | 869 | mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev); |
868 | !test_bit(Faulty, &rdev->flags)) { | 870 | if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) { |
871 | atomic_inc(&rdev->nr_pending); | ||
872 | blocked_rdev = rdev; | ||
873 | break; | ||
874 | } | ||
875 | if (rdev && !test_bit(Faulty, &rdev->flags)) { | ||
869 | atomic_inc(&rdev->nr_pending); | 876 | atomic_inc(&rdev->nr_pending); |
870 | if (test_bit(Faulty, &rdev->flags)) { | 877 | if (test_bit(Faulty, &rdev->flags)) { |
871 | rdev_dec_pending(rdev, mddev); | 878 | rdev_dec_pending(rdev, mddev); |
@@ -878,6 +885,20 @@ static int make_request(struct request_queue *q, struct bio * bio) | |||
878 | } | 885 | } |
879 | rcu_read_unlock(); | 886 | rcu_read_unlock(); |
880 | 887 | ||
888 | if (unlikely(blocked_rdev)) { | ||
889 | /* Wait for this device to become unblocked */ | ||
890 | int j; | ||
891 | |||
892 | for (j = 0; j < i; j++) | ||
893 | if (r1_bio->bios[j]) | ||
894 | rdev_dec_pending(conf->mirrors[j].rdev, mddev); | ||
895 | |||
896 | allow_barrier(conf); | ||
897 | md_wait_for_blocked_rdev(blocked_rdev, mddev); | ||
898 | wait_barrier(conf); | ||
899 | goto retry_write; | ||
900 | } | ||
901 | |||
881 | BUG_ON(targets == 0); /* we never fail the last device */ | 902 | BUG_ON(targets == 0); /* we never fail the last device */ |
882 | 903 | ||
883 | if (targets < conf->raid_disks) { | 904 | if (targets < conf->raid_disks) { |