diff options
| -rw-r--r-- | drivers/md/raid5.c | 79 |
1 files changed, 75 insertions, 4 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index ab40529bdabe..d29215d966da 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
| @@ -4823,11 +4823,40 @@ static raid5_conf_t *setup_conf(mddev_t *mddev) | |||
| 4823 | return ERR_PTR(-ENOMEM); | 4823 | return ERR_PTR(-ENOMEM); |
| 4824 | } | 4824 | } |
| 4825 | 4825 | ||
| 4826 | |||
| 4827 | static int only_parity(int raid_disk, int algo, int raid_disks, int max_degraded) | ||
| 4828 | { | ||
| 4829 | switch (algo) { | ||
| 4830 | case ALGORITHM_PARITY_0: | ||
| 4831 | if (raid_disk < max_degraded) | ||
| 4832 | return 1; | ||
| 4833 | break; | ||
| 4834 | case ALGORITHM_PARITY_N: | ||
| 4835 | if (raid_disk >= raid_disks - max_degraded) | ||
| 4836 | return 1; | ||
| 4837 | break; | ||
| 4838 | case ALGORITHM_PARITY_0_6: | ||
| 4839 | if (raid_disk == 0 || | ||
| 4840 | raid_disk == raid_disks - 1) | ||
| 4841 | return 1; | ||
| 4842 | break; | ||
| 4843 | case ALGORITHM_LEFT_ASYMMETRIC_6: | ||
| 4844 | case ALGORITHM_RIGHT_ASYMMETRIC_6: | ||
| 4845 | case ALGORITHM_LEFT_SYMMETRIC_6: | ||
| 4846 | case ALGORITHM_RIGHT_SYMMETRIC_6: | ||
| 4847 | if (raid_disk == raid_disks - 1) | ||
| 4848 | return 1; | ||
| 4849 | } | ||
| 4850 | return 0; | ||
| 4851 | } | ||
| 4852 | |||
| 4826 | static int run(mddev_t *mddev) | 4853 | static int run(mddev_t *mddev) |
| 4827 | { | 4854 | { |
| 4828 | raid5_conf_t *conf; | 4855 | raid5_conf_t *conf; |
| 4829 | int working_disks = 0, chunk_size; | 4856 | int working_disks = 0, chunk_size; |
| 4857 | int dirty_parity_disks = 0; | ||
| 4830 | mdk_rdev_t *rdev; | 4858 | mdk_rdev_t *rdev; |
| 4859 | sector_t reshape_offset = 0; | ||
| 4831 | 4860 | ||
| 4832 | if (mddev->recovery_cp != MaxSector) | 4861 | if (mddev->recovery_cp != MaxSector) |
| 4833 | printk(KERN_NOTICE "raid5: %s is not clean" | 4862 | printk(KERN_NOTICE "raid5: %s is not clean" |
| @@ -4861,6 +4890,7 @@ static int run(mddev_t *mddev) | |||
| 4861 | "on a stripe boundary\n"); | 4890 | "on a stripe boundary\n"); |
| 4862 | return -EINVAL; | 4891 | return -EINVAL; |
| 4863 | } | 4892 | } |
| 4893 | reshape_offset = here_new * mddev->new_chunk_sectors; | ||
| 4864 | /* here_new is the stripe we will write to */ | 4894 | /* here_new is the stripe we will write to */ |
| 4865 | here_old = mddev->reshape_position; | 4895 | here_old = mddev->reshape_position; |
| 4866 | sector_div(here_old, mddev->chunk_sectors * | 4896 | sector_div(here_old, mddev->chunk_sectors * |
| @@ -4916,10 +4946,51 @@ static int run(mddev_t *mddev) | |||
| 4916 | /* | 4946 | /* |
| 4917 | * 0 for a fully functional array, 1 or 2 for a degraded array. | 4947 | * 0 for a fully functional array, 1 or 2 for a degraded array. |
| 4918 | */ | 4948 | */ |
| 4919 | list_for_each_entry(rdev, &mddev->disks, same_set) | 4949 | list_for_each_entry(rdev, &mddev->disks, same_set) { |
| 4920 | if (rdev->raid_disk >= 0 && | 4950 | if (rdev->raid_disk < 0) |
| 4921 | test_bit(In_sync, &rdev->flags)) | 4951 | continue; |
| 4952 | if (test_bit(In_sync, &rdev->flags)) | ||
| 4922 | working_disks++; | 4953 | working_disks++; |
| 4954 | /* This disc is not fully in-sync. However if it | ||
| 4955 | * just stored parity (beyond the recovery_offset), | ||
| 4956 | * when we don't need to be concerned about the | ||
| 4957 | * array being dirty. | ||
| 4958 | * When reshape goes 'backwards', we never have | ||
| 4959 | * partially completed devices, so we only need | ||
| 4960 | * to worry about reshape going forwards. | ||
| 4961 | */ | ||
| 4962 | /* Hack because v0.91 doesn't store recovery_offset properly. */ | ||
| 4963 | if (mddev->major_version == 0 && | ||
| 4964 | mddev->minor_version > 90) | ||
| 4965 | rdev->recovery_offset = reshape_offset; | ||
| 4966 | |||
| 4967 | printk("%d: w=%d pa=%d pr=%d m=%d a=%d r=%d op1=%d op2=%d\n", | ||
| 4968 | rdev->raid_disk, working_disks, conf->prev_algo, | ||
| 4969 | conf->previous_raid_disks, conf->max_degraded, | ||
| 4970 | conf->algorithm, conf->raid_disks, | ||
| 4971 | only_parity(rdev->raid_disk, | ||
| 4972 | conf->prev_algo, | ||
| 4973 | conf->previous_raid_disks, | ||
| 4974 | conf->max_degraded), | ||
| 4975 | only_parity(rdev->raid_disk, | ||
| 4976 | conf->algorithm, | ||
| 4977 | conf->raid_disks, | ||
| 4978 | conf->max_degraded)); | ||
| 4979 | if (rdev->recovery_offset < reshape_offset) { | ||
| 4980 | /* We need to check old and new layout */ | ||
| 4981 | if (!only_parity(rdev->raid_disk, | ||
| 4982 | conf->algorithm, | ||
| 4983 | conf->raid_disks, | ||
| 4984 | conf->max_degraded)) | ||
| 4985 | continue; | ||
| 4986 | } | ||
| 4987 | if (!only_parity(rdev->raid_disk, | ||
| 4988 | conf->prev_algo, | ||
| 4989 | conf->previous_raid_disks, | ||
| 4990 | conf->max_degraded)) | ||
| 4991 | continue; | ||
| 4992 | dirty_parity_disks++; | ||
| 4993 | } | ||
| 4923 | 4994 | ||
| 4924 | mddev->degraded = (max(conf->raid_disks, conf->previous_raid_disks) | 4995 | mddev->degraded = (max(conf->raid_disks, conf->previous_raid_disks) |
| 4925 | - working_disks); | 4996 | - working_disks); |
| @@ -4935,7 +5006,7 @@ static int run(mddev_t *mddev) | |||
| 4935 | mddev->dev_sectors &= ~(mddev->chunk_sectors - 1); | 5006 | mddev->dev_sectors &= ~(mddev->chunk_sectors - 1); |
| 4936 | mddev->resync_max_sectors = mddev->dev_sectors; | 5007 | mddev->resync_max_sectors = mddev->dev_sectors; |
| 4937 | 5008 | ||
| 4938 | if (mddev->degraded > 0 && | 5009 | if (mddev->degraded > dirty_parity_disks && |
| 4939 | mddev->recovery_cp != MaxSector) { | 5010 | mddev->recovery_cp != MaxSector) { |
| 4940 | if (mddev->ok_start_degraded) | 5011 | if (mddev->ok_start_degraded) |
| 4941 | printk(KERN_WARNING | 5012 | printk(KERN_WARNING |
