aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/md/md.c43
-rw-r--r--drivers/md/md.h1
-rw-r--r--drivers/md/raid5.c7
3 files changed, 38 insertions, 13 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);
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 8e4c75c00d46..722f5dfe1953 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -305,6 +305,7 @@ struct mddev_s
305 atomic_t max_corr_read_errors; /* max read retries */ 305 atomic_t max_corr_read_errors; /* max read retries */
306 struct list_head all_mddevs; 306 struct list_head all_mddevs;
307 307
308 struct attribute_group *to_remove;
308 /* Generic barrier handling. 309 /* Generic barrier handling.
309 * If there is a pending barrier request, all other 310 * If there is a pending barrier request, all other
310 * writes are blocked while the devices are flushed. 311 * writes are blocked while the devices are flushed.
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 70ffbd071b2e..a361398875d0 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -5090,7 +5090,9 @@ static int run(mddev_t *mddev)
5090 } 5090 }
5091 5091
5092 /* Ok, everything is just fine now */ 5092 /* Ok, everything is just fine now */
5093 if (sysfs_create_group(&mddev->kobj, &raid5_attrs_group)) 5093 if (mddev->to_remove == &raid5_attrs_group)
5094 mddev->to_remove = NULL;
5095 else if (sysfs_create_group(&mddev->kobj, &raid5_attrs_group))
5094 printk(KERN_WARNING 5096 printk(KERN_WARNING
5095 "raid5: failed to create sysfs attributes for %s\n", 5097 "raid5: failed to create sysfs attributes for %s\n",
5096 mdname(mddev)); 5098 mdname(mddev));
@@ -5137,7 +5139,8 @@ static int stop(mddev_t *mddev)
5137 mddev->queue->backing_dev_info.congested_fn = NULL; 5139 mddev->queue->backing_dev_info.congested_fn = NULL;
5138 blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ 5140 blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
5139 free_conf(conf); 5141 free_conf(conf);
5140 mddev->private = &raid5_attrs_group; 5142 mddev->private = NULL;
5143 mddev->to_remove = &raid5_attrs_group;
5141 return 0; 5144 return 0;
5142} 5145}
5143 5146