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/raid10.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/raid10.c')
-rw-r--r-- | drivers/md/raid10.c | 29 |
1 files changed, 26 insertions, 3 deletions
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 1e96aa3ff513..5938fa962922 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c | |||
@@ -790,6 +790,7 @@ static int make_request(struct request_queue *q, struct bio * bio) | |||
790 | const int do_sync = bio_sync(bio); | 790 | const int do_sync = bio_sync(bio); |
791 | struct bio_list bl; | 791 | struct bio_list bl; |
792 | unsigned long flags; | 792 | unsigned long flags; |
793 | mdk_rdev_t *blocked_rdev; | ||
793 | 794 | ||
794 | if (unlikely(bio_barrier(bio))) { | 795 | if (unlikely(bio_barrier(bio))) { |
795 | bio_endio(bio, -EOPNOTSUPP); | 796 | bio_endio(bio, -EOPNOTSUPP); |
@@ -879,17 +880,23 @@ static int make_request(struct request_queue *q, struct bio * bio) | |||
879 | /* | 880 | /* |
880 | * WRITE: | 881 | * WRITE: |
881 | */ | 882 | */ |
882 | /* first select target devices under spinlock and | 883 | /* first select target devices under rcu_lock and |
883 | * inc refcount on their rdev. Record them by setting | 884 | * inc refcount on their rdev. Record them by setting |
884 | * bios[x] to bio | 885 | * bios[x] to bio |
885 | */ | 886 | */ |
886 | raid10_find_phys(conf, r10_bio); | 887 | raid10_find_phys(conf, r10_bio); |
888 | retry_write: | ||
889 | blocked_rdev = 0; | ||
887 | rcu_read_lock(); | 890 | rcu_read_lock(); |
888 | for (i = 0; i < conf->copies; i++) { | 891 | for (i = 0; i < conf->copies; i++) { |
889 | int d = r10_bio->devs[i].devnum; | 892 | int d = r10_bio->devs[i].devnum; |
890 | mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[d].rdev); | 893 | mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[d].rdev); |
891 | if (rdev && | 894 | if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) { |
892 | !test_bit(Faulty, &rdev->flags)) { | 895 | atomic_inc(&rdev->nr_pending); |
896 | blocked_rdev = rdev; | ||
897 | break; | ||
898 | } | ||
899 | if (rdev && !test_bit(Faulty, &rdev->flags)) { | ||
893 | atomic_inc(&rdev->nr_pending); | 900 | atomic_inc(&rdev->nr_pending); |
894 | r10_bio->devs[i].bio = bio; | 901 | r10_bio->devs[i].bio = bio; |
895 | } else { | 902 | } else { |
@@ -899,6 +906,22 @@ static int make_request(struct request_queue *q, struct bio * bio) | |||
899 | } | 906 | } |
900 | rcu_read_unlock(); | 907 | rcu_read_unlock(); |
901 | 908 | ||
909 | if (unlikely(blocked_rdev)) { | ||
910 | /* Have to wait for this device to get unblocked, then retry */ | ||
911 | int j; | ||
912 | int d; | ||
913 | |||
914 | for (j = 0; j < i; j++) | ||
915 | if (r10_bio->devs[j].bio) { | ||
916 | d = r10_bio->devs[j].devnum; | ||
917 | rdev_dec_pending(conf->mirrors[d].rdev, mddev); | ||
918 | } | ||
919 | allow_barrier(conf); | ||
920 | md_wait_for_blocked_rdev(blocked_rdev, mddev); | ||
921 | wait_barrier(conf); | ||
922 | goto retry_write; | ||
923 | } | ||
924 | |||
902 | atomic_set(&r10_bio->remaining, 0); | 925 | atomic_set(&r10_bio->remaining, 0); |
903 | 926 | ||
904 | bio_list_init(&bl); | 927 | bio_list_init(&bl); |