diff options
-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) | |||
3280 | { | 3280 | { |
3281 | char clevel[16]; | 3281 | char clevel[16]; |
3282 | ssize_t rv = len; | 3282 | ssize_t rv = len; |
3283 | struct md_personality *pers; | 3283 | struct md_personality *pers, *oldpers; |
3284 | long level; | 3284 | long level; |
3285 | void *priv; | 3285 | void *priv, *oldpriv; |
3286 | struct md_rdev *rdev; | 3286 | struct md_rdev *rdev; |
3287 | 3287 | ||
3288 | if (mddev->pers == NULL) { | 3288 | if (mddev->pers == NULL) { |
@@ -3374,9 +3374,35 @@ level_store(struct mddev *mddev, const char *buf, size_t len) | |||
3374 | /* Looks like we have a winner */ | 3374 | /* Looks like we have a winner */ |
3375 | mddev_suspend(mddev); | 3375 | mddev_suspend(mddev); |
3376 | mddev_detach(mddev); | 3376 | mddev_detach(mddev); |
3377 | mddev->pers->free(mddev, mddev->private); | 3377 | oldpers = mddev->pers; |
3378 | oldpriv = mddev->private; | ||
3379 | mddev->pers = pers; | ||
3380 | mddev->private = priv; | ||
3381 | strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel)); | ||
3382 | mddev->level = mddev->new_level; | ||
3383 | mddev->layout = mddev->new_layout; | ||
3384 | mddev->chunk_sectors = mddev->new_chunk_sectors; | ||
3385 | mddev->delta_disks = 0; | ||
3386 | mddev->reshape_backwards = 0; | ||
3387 | mddev->degraded = 0; | ||
3388 | |||
3389 | if (oldpers->sync_request == NULL && | ||
3390 | mddev->external) { | ||
3391 | /* We are converting from a no-redundancy array | ||
3392 | * to a redundancy array and metadata is managed | ||
3393 | * externally so we need to be sure that writes | ||
3394 | * won't block due to a need to transition | ||
3395 | * clean->dirty | ||
3396 | * until external management is started. | ||
3397 | */ | ||
3398 | mddev->in_sync = 0; | ||
3399 | mddev->safemode_delay = 0; | ||
3400 | mddev->safemode = 0; | ||
3401 | } | ||
3378 | 3402 | ||
3379 | if (mddev->pers->sync_request == NULL && | 3403 | oldpers->free(mddev, oldpriv); |
3404 | |||
3405 | if (oldpers->sync_request == NULL && | ||
3380 | pers->sync_request != NULL) { | 3406 | pers->sync_request != NULL) { |
3381 | /* need to add the md_redundancy_group */ | 3407 | /* need to add the md_redundancy_group */ |
3382 | if (sysfs_create_group(&mddev->kobj, &md_redundancy_group)) | 3408 | if (sysfs_create_group(&mddev->kobj, &md_redundancy_group)) |
@@ -3385,27 +3411,13 @@ level_store(struct mddev *mddev, const char *buf, size_t len) | |||
3385 | mdname(mddev)); | 3411 | mdname(mddev)); |
3386 | mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action"); | 3412 | mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action"); |
3387 | } | 3413 | } |
3388 | if (mddev->pers->sync_request != NULL && | 3414 | if (oldpers->sync_request != NULL && |
3389 | pers->sync_request == NULL) { | 3415 | pers->sync_request == NULL) { |
3390 | /* need to remove the md_redundancy_group */ | 3416 | /* need to remove the md_redundancy_group */ |
3391 | if (mddev->to_remove == NULL) | 3417 | if (mddev->to_remove == NULL) |
3392 | mddev->to_remove = &md_redundancy_group; | 3418 | mddev->to_remove = &md_redundancy_group; |
3393 | } | 3419 | } |
3394 | 3420 | ||
3395 | if (mddev->pers->sync_request == NULL && | ||
3396 | mddev->external) { | ||
3397 | /* We are converting from a no-redundancy array | ||
3398 | * to a redundancy array and metadata is managed | ||
3399 | * externally so we need to be sure that writes | ||
3400 | * won't block due to a need to transition | ||
3401 | * clean->dirty | ||
3402 | * until external management is started. | ||
3403 | */ | ||
3404 | mddev->in_sync = 0; | ||
3405 | mddev->safemode_delay = 0; | ||
3406 | mddev->safemode = 0; | ||
3407 | } | ||
3408 | |||
3409 | rdev_for_each(rdev, mddev) { | 3421 | rdev_for_each(rdev, mddev) { |
3410 | if (rdev->raid_disk < 0) | 3422 | if (rdev->raid_disk < 0) |
3411 | continue; | 3423 | continue; |
@@ -3431,17 +3443,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len) | |||
3431 | } | 3443 | } |
3432 | } | 3444 | } |
3433 | 3445 | ||
3434 | module_put(mddev->pers->owner); | 3446 | if (pers->sync_request == NULL) { |
3435 | mddev->pers = pers; | ||
3436 | mddev->private = priv; | ||
3437 | strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel)); | ||
3438 | mddev->level = mddev->new_level; | ||
3439 | mddev->layout = mddev->new_layout; | ||
3440 | mddev->chunk_sectors = mddev->new_chunk_sectors; | ||
3441 | mddev->delta_disks = 0; | ||
3442 | mddev->reshape_backwards = 0; | ||
3443 | mddev->degraded = 0; | ||
3444 | if (mddev->pers->sync_request == NULL) { | ||
3445 | /* this is now an array without redundancy, so | 3447 | /* this is now an array without redundancy, so |
3446 | * it must always be in_sync | 3448 | * it must always be in_sync |
3447 | */ | 3449 | */ |