diff --git a/drivers/md/md.c b/drivers/md/md.c index 2920fd0048657e2869f25af0f368b710d5837c44..58f531f8dcc2e6d2f6e8fd7b79bbcb2d06c50f60 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 */