diff options
author | NeilBrown <neilb@suse.de> | 2006-10-03 04:15:53 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-03 11:04:18 -0400 |
commit | c04be0aa82ff535e3676ab3e573957bdeef41879 (patch) | |
tree | 8481ab270218bed246eb02b3ba04a4b84d4e90d0 /drivers | |
parent | 11ce99e625fe2718ad2682bfdd99070b337e6252 (diff) |
[PATCH] md: Improve locking around error handling
The error handling routines don't use proper locking, and so two concurrent
errors could trigger a problem.
So:
- use test-and-set and test-and-clear to synchonise
the In_sync bits with the ->degraded count
- use the spinlock to protect updates to the
degraded count (could use an atomic_t but that
would be a bigger change in code, and isn't
really justified)
- remove un-necessary locking in raid5
Signed-off-by: Neil Brown <neilb@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/md/raid1.c | 16 | ||||
-rw-r--r-- | drivers/md/raid10.c | 12 | ||||
-rw-r--r-- | drivers/md/raid5.c | 20 |
3 files changed, 31 insertions, 17 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 3fc9ec239478..99c4e031c7f1 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c | |||
@@ -959,14 +959,16 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) | |||
959 | * normal single drive | 959 | * normal single drive |
960 | */ | 960 | */ |
961 | return; | 961 | return; |
962 | if (test_bit(In_sync, &rdev->flags)) { | 962 | if (test_and_clear_bit(In_sync, &rdev->flags)) { |
963 | unsigned long flags; | ||
964 | spin_lock_irqsave(&conf->device_lock, flags); | ||
963 | mddev->degraded++; | 965 | mddev->degraded++; |
966 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
964 | /* | 967 | /* |
965 | * if recovery is running, make sure it aborts. | 968 | * if recovery is running, make sure it aborts. |
966 | */ | 969 | */ |
967 | set_bit(MD_RECOVERY_ERR, &mddev->recovery); | 970 | set_bit(MD_RECOVERY_ERR, &mddev->recovery); |
968 | } | 971 | } |
969 | clear_bit(In_sync, &rdev->flags); | ||
970 | set_bit(Faulty, &rdev->flags); | 972 | set_bit(Faulty, &rdev->flags); |
971 | set_bit(MD_CHANGE_DEVS, &mddev->flags); | 973 | set_bit(MD_CHANGE_DEVS, &mddev->flags); |
972 | printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n" | 974 | printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n" |
@@ -1022,9 +1024,11 @@ static int raid1_spare_active(mddev_t *mddev) | |||
1022 | mdk_rdev_t *rdev = conf->mirrors[i].rdev; | 1024 | mdk_rdev_t *rdev = conf->mirrors[i].rdev; |
1023 | if (rdev | 1025 | if (rdev |
1024 | && !test_bit(Faulty, &rdev->flags) | 1026 | && !test_bit(Faulty, &rdev->flags) |
1025 | && !test_bit(In_sync, &rdev->flags)) { | 1027 | && !test_and_set_bit(In_sync, &rdev->flags)) { |
1028 | unsigned long flags; | ||
1029 | spin_lock_irqsave(&conf->device_lock, flags); | ||
1026 | mddev->degraded--; | 1030 | mddev->degraded--; |
1027 | set_bit(In_sync, &rdev->flags); | 1031 | spin_unlock_irqrestore(&conf->device_lock, flags); |
1028 | } | 1032 | } |
1029 | } | 1033 | } |
1030 | 1034 | ||
@@ -2048,7 +2052,7 @@ static int raid1_reshape(mddev_t *mddev) | |||
2048 | mirror_info_t *newmirrors; | 2052 | mirror_info_t *newmirrors; |
2049 | conf_t *conf = mddev_to_conf(mddev); | 2053 | conf_t *conf = mddev_to_conf(mddev); |
2050 | int cnt, raid_disks; | 2054 | int cnt, raid_disks; |
2051 | 2055 | unsigned long flags; | |
2052 | int d, d2; | 2056 | int d, d2; |
2053 | 2057 | ||
2054 | /* Cannot change chunk_size, layout, or level */ | 2058 | /* Cannot change chunk_size, layout, or level */ |
@@ -2107,7 +2111,9 @@ static int raid1_reshape(mddev_t *mddev) | |||
2107 | kfree(conf->poolinfo); | 2111 | kfree(conf->poolinfo); |
2108 | conf->poolinfo = newpoolinfo; | 2112 | conf->poolinfo = newpoolinfo; |
2109 | 2113 | ||
2114 | spin_lock_irqsave(&conf->device_lock, flags); | ||
2110 | mddev->degraded += (raid_disks - conf->raid_disks); | 2115 | mddev->degraded += (raid_disks - conf->raid_disks); |
2116 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
2111 | conf->raid_disks = mddev->raid_disks = raid_disks; | 2117 | conf->raid_disks = mddev->raid_disks = raid_disks; |
2112 | mddev->delta_disks = 0; | 2118 | mddev->delta_disks = 0; |
2113 | 2119 | ||
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 233a4faede94..64f8016ab740 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c | |||
@@ -950,14 +950,16 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) | |||
950 | * really dead" tests... | 950 | * really dead" tests... |
951 | */ | 951 | */ |
952 | return; | 952 | return; |
953 | if (test_bit(In_sync, &rdev->flags)) { | 953 | if (test_and_clear_bit(In_sync, &rdev->flags)) { |
954 | unsigned long flags; | ||
955 | spin_lock_irqsave(&conf->device_lock, flags); | ||
954 | mddev->degraded++; | 956 | mddev->degraded++; |
957 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
955 | /* | 958 | /* |
956 | * if recovery is running, make sure it aborts. | 959 | * if recovery is running, make sure it aborts. |
957 | */ | 960 | */ |
958 | set_bit(MD_RECOVERY_ERR, &mddev->recovery); | 961 | set_bit(MD_RECOVERY_ERR, &mddev->recovery); |
959 | } | 962 | } |
960 | clear_bit(In_sync, &rdev->flags); | ||
961 | set_bit(Faulty, &rdev->flags); | 963 | set_bit(Faulty, &rdev->flags); |
962 | set_bit(MD_CHANGE_DEVS, &mddev->flags); | 964 | set_bit(MD_CHANGE_DEVS, &mddev->flags); |
963 | printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n" | 965 | printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n" |
@@ -1033,9 +1035,11 @@ static int raid10_spare_active(mddev_t *mddev) | |||
1033 | tmp = conf->mirrors + i; | 1035 | tmp = conf->mirrors + i; |
1034 | if (tmp->rdev | 1036 | if (tmp->rdev |
1035 | && !test_bit(Faulty, &tmp->rdev->flags) | 1037 | && !test_bit(Faulty, &tmp->rdev->flags) |
1036 | && !test_bit(In_sync, &tmp->rdev->flags)) { | 1038 | && !test_and_set_bit(In_sync, &tmp->rdev->flags)) { |
1039 | unsigned long flags; | ||
1040 | spin_lock_irqsave(&conf->device_lock, flags); | ||
1037 | mddev->degraded--; | 1041 | mddev->degraded--; |
1038 | set_bit(In_sync, &tmp->rdev->flags); | 1042 | spin_unlock_irqrestore(&conf->device_lock, flags); |
1039 | } | 1043 | } |
1040 | } | 1044 | } |
1041 | 1045 | ||
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 46fd651539fe..6cea9c9a98e2 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -636,7 +636,6 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done, | |||
636 | struct stripe_head *sh = bi->bi_private; | 636 | struct stripe_head *sh = bi->bi_private; |
637 | raid5_conf_t *conf = sh->raid_conf; | 637 | raid5_conf_t *conf = sh->raid_conf; |
638 | int disks = sh->disks, i; | 638 | int disks = sh->disks, i; |
639 | unsigned long flags; | ||
640 | int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); | 639 | int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags); |
641 | 640 | ||
642 | if (bi->bi_size) | 641 | if (bi->bi_size) |
@@ -654,7 +653,6 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done, | |||
654 | return 0; | 653 | return 0; |
655 | } | 654 | } |
656 | 655 | ||
657 | spin_lock_irqsave(&conf->device_lock, flags); | ||
658 | if (!uptodate) | 656 | if (!uptodate) |
659 | md_error(conf->mddev, conf->disks[i].rdev); | 657 | md_error(conf->mddev, conf->disks[i].rdev); |
660 | 658 | ||
@@ -662,8 +660,7 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done, | |||
662 | 660 | ||
663 | clear_bit(R5_LOCKED, &sh->dev[i].flags); | 661 | clear_bit(R5_LOCKED, &sh->dev[i].flags); |
664 | set_bit(STRIPE_HANDLE, &sh->state); | 662 | set_bit(STRIPE_HANDLE, &sh->state); |
665 | __release_stripe(conf, sh); | 663 | release_stripe(sh); |
666 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
667 | return 0; | 664 | return 0; |
668 | } | 665 | } |
669 | 666 | ||
@@ -697,9 +694,11 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) | |||
697 | 694 | ||
698 | if (!test_bit(Faulty, &rdev->flags)) { | 695 | if (!test_bit(Faulty, &rdev->flags)) { |
699 | set_bit(MD_CHANGE_DEVS, &mddev->flags); | 696 | set_bit(MD_CHANGE_DEVS, &mddev->flags); |
700 | if (test_bit(In_sync, &rdev->flags)) { | 697 | if (test_and_clear_bit(In_sync, &rdev->flags)) { |
698 | unsigned long flags; | ||
699 | spin_lock_irqsave(&conf->device_lock, flags); | ||
701 | mddev->degraded++; | 700 | mddev->degraded++; |
702 | clear_bit(In_sync, &rdev->flags); | 701 | spin_unlock_irqrestore(&conf->device_lock, flags); |
703 | /* | 702 | /* |
704 | * if recovery was running, make sure it aborts. | 703 | * if recovery was running, make sure it aborts. |
705 | */ | 704 | */ |
@@ -3418,9 +3417,11 @@ static int raid5_spare_active(mddev_t *mddev) | |||
3418 | tmp = conf->disks + i; | 3417 | tmp = conf->disks + i; |
3419 | if (tmp->rdev | 3418 | if (tmp->rdev |
3420 | && !test_bit(Faulty, &tmp->rdev->flags) | 3419 | && !test_bit(Faulty, &tmp->rdev->flags) |
3421 | && !test_bit(In_sync, &tmp->rdev->flags)) { | 3420 | && !test_and_set_bit(In_sync, &tmp->rdev->flags)) { |
3421 | unsigned long flags; | ||
3422 | spin_lock_irqsave(&conf->device_lock, flags); | ||
3422 | mddev->degraded--; | 3423 | mddev->degraded--; |
3423 | set_bit(In_sync, &tmp->rdev->flags); | 3424 | spin_unlock_irqrestore(&conf->device_lock, flags); |
3424 | } | 3425 | } |
3425 | } | 3426 | } |
3426 | print_raid5_conf(conf); | 3427 | print_raid5_conf(conf); |
@@ -3556,6 +3557,7 @@ static int raid5_start_reshape(mddev_t *mddev) | |||
3556 | struct list_head *rtmp; | 3557 | struct list_head *rtmp; |
3557 | int spares = 0; | 3558 | int spares = 0; |
3558 | int added_devices = 0; | 3559 | int added_devices = 0; |
3560 | unsigned long flags; | ||
3559 | 3561 | ||
3560 | if (mddev->degraded || | 3562 | if (mddev->degraded || |
3561 | test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) | 3563 | test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) |
@@ -3597,7 +3599,9 @@ static int raid5_start_reshape(mddev_t *mddev) | |||
3597 | break; | 3599 | break; |
3598 | } | 3600 | } |
3599 | 3601 | ||
3602 | spin_lock_irqsave(&conf->device_lock, flags); | ||
3600 | mddev->degraded = (conf->raid_disks - conf->previous_raid_disks) - added_devices; | 3603 | mddev->degraded = (conf->raid_disks - conf->previous_raid_disks) - added_devices; |
3604 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
3601 | mddev->raid_disks = conf->raid_disks; | 3605 | mddev->raid_disks = conf->raid_disks; |
3602 | mddev->reshape_position = 0; | 3606 | mddev->reshape_position = 0; |
3603 | set_bit(MD_CHANGE_DEVS, &mddev->flags); | 3607 | set_bit(MD_CHANGE_DEVS, &mddev->flags); |