aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/raid5.c
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2008-04-30 03:52:32 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-30 11:29:33 -0400
commit6bfe0b499082fd3950429017cd8ebf2a6c458aa5 (patch)
tree81476cf7f7ddbea135bdb93729e0bffae0e7c163 /drivers/md/raid5.c
parent11e2ede0228ee0f81ccacd15894908c3bf241f73 (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.c33
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-- ;) {