diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/md/md.c | 62 | 
1 files changed, 32 insertions, 30 deletions
| diff --git a/drivers/md/md.c b/drivers/md/md.c index 2920fd004865..58f531f8dcc2 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3280,9 +3280,9 @@ level_store(struct mddev *mddev, const char *buf, size_t len)  {  	char clevel[16];  	ssize_t rv = len; -	struct md_personality *pers; +	struct md_personality *pers, *oldpers;  	long level; -	void *priv; +	void *priv, *oldpriv;  	struct md_rdev *rdev;  	if (mddev->pers == NULL) { @@ -3374,9 +3374,35 @@ level_store(struct mddev *mddev, const char *buf, size_t len)  	/* Looks like we have a winner */  	mddev_suspend(mddev);  	mddev_detach(mddev); -	mddev->pers->free(mddev, mddev->private); +	oldpers = mddev->pers; +	oldpriv = mddev->private; +	mddev->pers = pers; +	mddev->private = priv; +	strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel)); +	mddev->level = mddev->new_level; +	mddev->layout = mddev->new_layout; +	mddev->chunk_sectors = mddev->new_chunk_sectors; +	mddev->delta_disks = 0; +	mddev->reshape_backwards = 0; +	mddev->degraded = 0; + +	if (oldpers->sync_request == NULL && +	    mddev->external) { +		/* We are converting from a no-redundancy array +		 * to a redundancy array and metadata is managed +		 * externally so we need to be sure that writes +		 * won't block due to a need to transition +		 *      clean->dirty +		 * until external management is started. +		 */ +		mddev->in_sync = 0; +		mddev->safemode_delay = 0; +		mddev->safemode = 0; +	} -	if (mddev->pers->sync_request == NULL && +	oldpers->free(mddev, oldpriv); + +	if (oldpers->sync_request == NULL &&  	    pers->sync_request != NULL) {  		/* need to add the md_redundancy_group */  		if (sysfs_create_group(&mddev->kobj, &md_redundancy_group)) @@ -3385,27 +3411,13 @@ level_store(struct mddev *mddev, const char *buf, size_t len)  			       mdname(mddev));  		mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action");  	} -	if (mddev->pers->sync_request != NULL && +	if (oldpers->sync_request != NULL &&  	    pers->sync_request == NULL) {  		/* need to remove the md_redundancy_group */  		if (mddev->to_remove == NULL)  			mddev->to_remove = &md_redundancy_group;  	} -	if (mddev->pers->sync_request == NULL && -	    mddev->external) { -		/* We are converting from a no-redundancy array -		 * to a redundancy array and metadata is managed -		 * externally so we need to be sure that writes -		 * won't block due to a need to transition -		 *      clean->dirty -		 * until external management is started. -		 */ -		mddev->in_sync = 0; -		mddev->safemode_delay = 0; -		mddev->safemode = 0; -	} -  	rdev_for_each(rdev, mddev) {  		if (rdev->raid_disk < 0)  			continue; @@ -3431,17 +3443,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)  		}  	} -	module_put(mddev->pers->owner); -	mddev->pers = pers; -	mddev->private = priv; -	strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel)); -	mddev->level = mddev->new_level; -	mddev->layout = mddev->new_layout; -	mddev->chunk_sectors = mddev->new_chunk_sectors; -	mddev->delta_disks = 0; -	mddev->reshape_backwards = 0; -	mddev->degraded = 0; -	if (mddev->pers->sync_request == NULL) { +	if (pers->sync_request == NULL) {  		/* this is now an array without redundancy, so  		 * it must always be in_sync  		 */ | 
