aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/md.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2010-06-15 04:36:03 -0400
committerNeilBrown <neilb@suse.de>2010-06-23 23:33:24 -0400
commite93f68a1fc6244c05ad8fae28e75835ec74ab34e (patch)
treed282978aac8f6fcec512be2a6e61287bbb6241b1 /drivers/md/md.c
parent0544a21db02c1d8883158fd6f323364f830a120a (diff)
md: fix handling of array level takeover that re-arranges devices.
Most array level changes leave the list of devices largely unchanged, possibly causing one at the end to become redundant. However conversions between RAID0 and RAID10 need to renumber all devices (except 0). This renumbering is currently being done in the ->run method when the new personality takes over. However this is too late as the common code in md.c might already have invalidated some of the devices if they had a ->raid_disk number that appeared to high. Moving it into the ->takeover method is too early as the array is still active at that time and wrong ->raid_disk numbers could cause confusion. So add a ->new_raid_disk field to mdk_rdev_s and use it to communicate the new raid_disk number. Now the common code knows exactly which devices need to be renumbered, and which can be invalidated, and can do it all at a convenient time when the array is suspend. It can also update some symlinks in sysfs which previously were not be updated correctly. Reported-by: Maciej Trela <maciej.trela@intel.com> Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r--drivers/md/md.c35
1 files changed, 30 insertions, 5 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 4edcda8f4869..4869128bf742 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3001,6 +3001,9 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
3001 return -EINVAL; 3001 return -EINVAL;
3002 } 3002 }
3003 3003
3004 list_for_each_entry(rdev, &mddev->disks, same_set)
3005 rdev->new_raid_disk = rdev->raid_disk;
3006
3004 /* ->takeover must set new_* and/or delta_disks 3007 /* ->takeover must set new_* and/or delta_disks
3005 * if it succeeds, and may set them when it fails. 3008 * if it succeeds, and may set them when it fails.
3006 */ 3009 */
@@ -3051,13 +3054,35 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
3051 mddev->safemode = 0; 3054 mddev->safemode = 0;
3052 } 3055 }
3053 3056
3054 module_put(mddev->pers->owner); 3057 list_for_each_entry(rdev, &mddev->disks, same_set) {
3055 /* Invalidate devices that are now superfluous */ 3058 char nm[20];
3056 list_for_each_entry(rdev, &mddev->disks, same_set) 3059 if (rdev->raid_disk < 0)
3057 if (rdev->raid_disk >= mddev->raid_disks) { 3060 continue;
3058 rdev->raid_disk = -1; 3061 if (rdev->new_raid_disk > mddev->raid_disks)
3062 rdev->new_raid_disk = -1;
3063 if (rdev->new_raid_disk == rdev->raid_disk)
3064 continue;
3065 sprintf(nm, "rd%d", rdev->raid_disk);
3066 sysfs_remove_link(&mddev->kobj, nm);
3067 }
3068 list_for_each_entry(rdev, &mddev->disks, same_set) {
3069 if (rdev->raid_disk < 0)
3070 continue;
3071 if (rdev->new_raid_disk == rdev->raid_disk)
3072 continue;
3073 rdev->raid_disk = rdev->new_raid_disk;
3074 if (rdev->raid_disk < 0)
3059 clear_bit(In_sync, &rdev->flags); 3075 clear_bit(In_sync, &rdev->flags);
3076 else {
3077 char nm[20];
3078 sprintf(nm, "rd%d", rdev->raid_disk);
3079 if(sysfs_create_link(&mddev->kobj, &rdev->kobj, nm))
3080 printk("md: cannot register %s for %s after level change\n",
3081 nm, mdname(mddev));
3060 } 3082 }
3083 }
3084
3085 module_put(mddev->pers->owner);
3061 mddev->pers = pers; 3086 mddev->pers = pers;
3062 mddev->private = priv; 3087 mddev->private = priv;
3063 strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel)); 3088 strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));