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/raid5.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/raid5.c')
-rw-r--r-- | drivers/md/raid5.c | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 968dacaced6d..087eee0cb809 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -2607,6 +2607,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh, | |||
2607 | } | 2607 | } |
2608 | } | 2608 | } |
2609 | 2609 | ||
2610 | |||
2610 | /* | 2611 | /* |
2611 | * handle_stripe - do things to a stripe. | 2612 | * handle_stripe - do things to a stripe. |
2612 | * | 2613 | * |
@@ -2632,6 +2633,7 @@ static void handle_stripe5(struct stripe_head *sh) | |||
2632 | struct stripe_head_state s; | 2633 | struct stripe_head_state s; |
2633 | struct r5dev *dev; | 2634 | struct r5dev *dev; |
2634 | unsigned long pending = 0; | 2635 | unsigned long pending = 0; |
2636 | mdk_rdev_t *blocked_rdev = NULL; | ||
2635 | 2637 | ||
2636 | memset(&s, 0, sizeof(s)); | 2638 | memset(&s, 0, sizeof(s)); |
2637 | pr_debug("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d " | 2639 | pr_debug("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d " |
@@ -2691,6 +2693,11 @@ static void handle_stripe5(struct stripe_head *sh) | |||
2691 | if (dev->written) | 2693 | if (dev->written) |
2692 | s.written++; | 2694 | s.written++; |
2693 | rdev = rcu_dereference(conf->disks[i].rdev); | 2695 | rdev = rcu_dereference(conf->disks[i].rdev); |
2696 | if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) { | ||
2697 | blocked_rdev = rdev; | ||
2698 | atomic_inc(&rdev->nr_pending); | ||
2699 | break; | ||
2700 | } | ||
2694 | if (!rdev || !test_bit(In_sync, &rdev->flags)) { | 2701 | if (!rdev || !test_bit(In_sync, &rdev->flags)) { |
2695 | /* The ReadError flag will just be confusing now */ | 2702 | /* The ReadError flag will just be confusing now */ |
2696 | clear_bit(R5_ReadError, &dev->flags); | 2703 | clear_bit(R5_ReadError, &dev->flags); |
@@ -2705,6 +2712,11 @@ static void handle_stripe5(struct stripe_head *sh) | |||
2705 | } | 2712 | } |
2706 | rcu_read_unlock(); | 2713 | rcu_read_unlock(); |
2707 | 2714 | ||
2715 | if (unlikely(blocked_rdev)) { | ||
2716 | set_bit(STRIPE_HANDLE, &sh->state); | ||
2717 | goto unlock; | ||
2718 | } | ||
2719 | |||
2708 | if (s.to_fill && !test_and_set_bit(STRIPE_OP_BIOFILL, &sh->ops.pending)) | 2720 | if (s.to_fill && !test_and_set_bit(STRIPE_OP_BIOFILL, &sh->ops.pending)) |
2709 | sh->ops.count++; | 2721 | sh->ops.count++; |
2710 | 2722 | ||
@@ -2894,8 +2906,13 @@ static void handle_stripe5(struct stripe_head *sh) | |||
2894 | if (sh->ops.count) | 2906 | if (sh->ops.count) |
2895 | pending = get_stripe_work(sh); | 2907 | pending = get_stripe_work(sh); |
2896 | 2908 | ||
2909 | unlock: | ||
2897 | spin_unlock(&sh->lock); | 2910 | spin_unlock(&sh->lock); |
2898 | 2911 | ||
2912 | /* wait for this device to become unblocked */ | ||
2913 | if (unlikely(blocked_rdev)) | ||
2914 | md_wait_for_blocked_rdev(blocked_rdev, conf->mddev); | ||
2915 | |||
2899 | if (pending) | 2916 | if (pending) |
2900 | raid5_run_ops(sh, pending); | 2917 | raid5_run_ops(sh, pending); |
2901 | 2918 | ||
@@ -2912,6 +2929,7 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) | |||
2912 | struct stripe_head_state s; | 2929 | struct stripe_head_state s; |
2913 | struct r6_state r6s; | 2930 | struct r6_state r6s; |
2914 | struct r5dev *dev, *pdev, *qdev; | 2931 | struct r5dev *dev, *pdev, *qdev; |
2932 | mdk_rdev_t *blocked_rdev = NULL; | ||
2915 | 2933 | ||
2916 | r6s.qd_idx = raid6_next_disk(pd_idx, disks); | 2934 | r6s.qd_idx = raid6_next_disk(pd_idx, disks); |
2917 | pr_debug("handling stripe %llu, state=%#lx cnt=%d, " | 2935 | pr_debug("handling stripe %llu, state=%#lx cnt=%d, " |
@@ -2975,6 +2993,11 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) | |||
2975 | if (dev->written) | 2993 | if (dev->written) |
2976 | s.written++; | 2994 | s.written++; |
2977 | rdev = rcu_dereference(conf->disks[i].rdev); | 2995 | rdev = rcu_dereference(conf->disks[i].rdev); |
2996 | if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) { | ||
2997 | blocked_rdev = rdev; | ||
2998 | atomic_inc(&rdev->nr_pending); | ||
2999 | break; | ||
3000 | } | ||
2978 | if (!rdev || !test_bit(In_sync, &rdev->flags)) { | 3001 | if (!rdev || !test_bit(In_sync, &rdev->flags)) { |
2979 | /* The ReadError flag will just be confusing now */ | 3002 | /* The ReadError flag will just be confusing now */ |
2980 | clear_bit(R5_ReadError, &dev->flags); | 3003 | clear_bit(R5_ReadError, &dev->flags); |
@@ -2989,6 +3012,11 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) | |||
2989 | set_bit(R5_Insync, &dev->flags); | 3012 | set_bit(R5_Insync, &dev->flags); |
2990 | } | 3013 | } |
2991 | rcu_read_unlock(); | 3014 | rcu_read_unlock(); |
3015 | |||
3016 | if (unlikely(blocked_rdev)) { | ||
3017 | set_bit(STRIPE_HANDLE, &sh->state); | ||
3018 | goto unlock; | ||
3019 | } | ||
2992 | pr_debug("locked=%d uptodate=%d to_read=%d" | 3020 | pr_debug("locked=%d uptodate=%d to_read=%d" |
2993 | " to_write=%d failed=%d failed_num=%d,%d\n", | 3021 | " to_write=%d failed=%d failed_num=%d,%d\n", |
2994 | s.locked, s.uptodate, s.to_read, s.to_write, s.failed, | 3022 | s.locked, s.uptodate, s.to_read, s.to_write, s.failed, |
@@ -3094,8 +3122,13 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) | |||
3094 | !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending)) | 3122 | !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending)) |
3095 | handle_stripe_expansion(conf, sh, &r6s); | 3123 | handle_stripe_expansion(conf, sh, &r6s); |
3096 | 3124 | ||
3125 | unlock: | ||
3097 | spin_unlock(&sh->lock); | 3126 | spin_unlock(&sh->lock); |
3098 | 3127 | ||
3128 | /* wait for this device to become unblocked */ | ||
3129 | if (unlikely(blocked_rdev)) | ||
3130 | md_wait_for_blocked_rdev(blocked_rdev, conf->mddev); | ||
3131 | |||
3099 | return_io(return_bi); | 3132 | return_io(return_bi); |
3100 | 3133 | ||
3101 | for (i=disks; i-- ;) { | 3134 | for (i=disks; i-- ;) { |