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/md/raid5.c | |
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/md/raid5.c')
-rw-r--r-- | drivers/md/raid5.c | 20 |
1 files changed, 12 insertions, 8 deletions
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); |