aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/md.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2010-04-14 03:15:37 -0400
committerNeilBrown <neilb@suse.de>2010-05-17 00:45:40 -0400
commita64c876fd357906a1f7193723866562ad290654c (patch)
tree077fcdab730d40227585025bf15bf8e027949a29 /drivers/md/md.c
parentb6eb127d274385d81ce8dd45c98190f097bce1b4 (diff)
md: manage redundancy group in sysfs when changing level.
Some levels expect the 'redundancy group' to be present, others don't. So when we change level of an array we might need to add or remove this group. This requires fixing up the current practice of overloading ->private to indicate (when ->pers == NULL) that something needs to be removed. So create a new ->to_remove to fill that role. When changing levels, we may need to add or remove attributes. When changing RAID5 -> RAID6, we both add and remove the same thing. It is important to catch this and optimise it out as the removal is delayed until a lock is released, so trying to add immediately would cause problems. Cc: stable@kernel.org Signed-off-by: NeilBrown <neilb@suse.de>
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r--drivers/md/md.c43
1 files changed, 32 insertions, 11 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index edf777f6fe56..e8d238885cd2 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -509,9 +509,9 @@ static inline int mddev_trylock(mddev_t * mddev)
509 509
510static struct attribute_group md_redundancy_group; 510static struct attribute_group md_redundancy_group;
511 511
512static inline void mddev_unlock(mddev_t * mddev) 512static void mddev_unlock(mddev_t * mddev)
513{ 513{
514 if (mddev->pers == NULL && mddev->private) { 514 if (mddev->to_remove) {
515 /* These cannot be removed under reconfig_mutex as 515 /* These cannot be removed under reconfig_mutex as
516 * an access to the files will try to take reconfig_mutex 516 * an access to the files will try to take reconfig_mutex
517 * while holding the file unremovable, which leads to 517 * while holding the file unremovable, which leads to
@@ -520,16 +520,20 @@ static inline void mddev_unlock(mddev_t * mddev)
520 * it while holding reconfig_mutex, and md_run can 520 * it while holding reconfig_mutex, and md_run can
521 * use it to wait for the remove to complete. 521 * use it to wait for the remove to complete.
522 */ 522 */
523 struct attribute_group *to_remove = mddev->to_remove;
524 mddev->to_remove = NULL;
523 mutex_lock(&mddev->open_mutex); 525 mutex_lock(&mddev->open_mutex);
524 mutex_unlock(&mddev->reconfig_mutex); 526 mutex_unlock(&mddev->reconfig_mutex);
525 527
526 sysfs_remove_group(&mddev->kobj, &md_redundancy_group); 528 if (to_remove != &md_redundancy_group)
527 if (mddev->private != (void*)1) 529 sysfs_remove_group(&mddev->kobj, to_remove);
528 sysfs_remove_group(&mddev->kobj, mddev->private); 530 if (mddev->pers == NULL ||
529 if (mddev->sysfs_action) 531 mddev->pers->sync_request == NULL) {
530 sysfs_put(mddev->sysfs_action); 532 sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
531 mddev->sysfs_action = NULL; 533 if (mddev->sysfs_action)
532 mddev->private = NULL; 534 sysfs_put(mddev->sysfs_action);
535 mddev->sysfs_action = NULL;
536 }
533 mutex_unlock(&mddev->open_mutex); 537 mutex_unlock(&mddev->open_mutex);
534 } else 538 } else
535 mutex_unlock(&mddev->reconfig_mutex); 539 mutex_unlock(&mddev->reconfig_mutex);
@@ -2996,6 +3000,23 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
2996 /* Looks like we have a winner */ 3000 /* Looks like we have a winner */
2997 mddev_suspend(mddev); 3001 mddev_suspend(mddev);
2998 mddev->pers->stop(mddev); 3002 mddev->pers->stop(mddev);
3003
3004 if (mddev->pers->sync_request == NULL &&
3005 pers->sync_request != NULL) {
3006 /* need to add the md_redundancy_group */
3007 if (sysfs_create_group(&mddev->kobj, &md_redundancy_group))
3008 printk(KERN_WARNING
3009 "md: cannot register extra attributes for %s\n",
3010 mdname(mddev));
3011 mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action");
3012 }
3013 if (mddev->pers->sync_request != NULL &&
3014 pers->sync_request == NULL) {
3015 /* need to remove the md_redundancy_group */
3016 if (mddev->to_remove == NULL)
3017 mddev->to_remove = &md_redundancy_group;
3018 }
3019
2999 module_put(mddev->pers->owner); 3020 module_put(mddev->pers->owner);
3000 /* Invalidate devices that are now superfluous */ 3021 /* Invalidate devices that are now superfluous */
3001 list_for_each_entry(rdev, &mddev->disks, same_set) 3022 list_for_each_entry(rdev, &mddev->disks, same_set)
@@ -4550,8 +4571,8 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
4550 mddev->queue->unplug_fn = NULL; 4571 mddev->queue->unplug_fn = NULL;
4551 mddev->queue->backing_dev_info.congested_fn = NULL; 4572 mddev->queue->backing_dev_info.congested_fn = NULL;
4552 module_put(mddev->pers->owner); 4573 module_put(mddev->pers->owner);
4553 if (mddev->pers->sync_request && mddev->private == NULL) 4574 if (mddev->pers->sync_request && mddev->to_remove == NULL)
4554 mddev->private = (void*)1; 4575 mddev->to_remove = &md_redundancy_group;
4555 mddev->pers = NULL; 4576 mddev->pers = NULL;
4556 /* tell userspace to handle 'inactive' */ 4577 /* tell userspace to handle 'inactive' */
4557 sysfs_notify_dirent(mddev->sysfs_state); 4578 sysfs_notify_dirent(mddev->sysfs_state);