|
@@ -509,9 +509,9 @@ static inline int mddev_trylock(mddev_t * mddev)
|
|
|
|
|
|
static struct attribute_group md_redundancy_group;
|
|
static struct attribute_group md_redundancy_group;
|
|
|
|
|
|
-static inline void mddev_unlock(mddev_t * mddev)
|
|
|
|
|
|
+static void mddev_unlock(mddev_t * mddev)
|
|
{
|
|
{
|
|
- if (mddev->pers == NULL && mddev->private) {
|
|
|
|
|
|
+ if (mddev->to_remove) {
|
|
/* These cannot be removed under reconfig_mutex as
|
|
/* These cannot be removed under reconfig_mutex as
|
|
* an access to the files will try to take reconfig_mutex
|
|
* an access to the files will try to take reconfig_mutex
|
|
* while holding the file unremovable, which leads to
|
|
* while holding the file unremovable, which leads to
|
|
@@ -520,16 +520,20 @@ static inline void mddev_unlock(mddev_t * mddev)
|
|
* it while holding reconfig_mutex, and md_run can
|
|
* it while holding reconfig_mutex, and md_run can
|
|
* use it to wait for the remove to complete.
|
|
* use it to wait for the remove to complete.
|
|
*/
|
|
*/
|
|
|
|
+ struct attribute_group *to_remove = mddev->to_remove;
|
|
|
|
+ mddev->to_remove = NULL;
|
|
mutex_lock(&mddev->open_mutex);
|
|
mutex_lock(&mddev->open_mutex);
|
|
mutex_unlock(&mddev->reconfig_mutex);
|
|
mutex_unlock(&mddev->reconfig_mutex);
|
|
|
|
|
|
- sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
|
|
|
|
- if (mddev->private != (void*)1)
|
|
|
|
- sysfs_remove_group(&mddev->kobj, mddev->private);
|
|
|
|
- if (mddev->sysfs_action)
|
|
|
|
- sysfs_put(mddev->sysfs_action);
|
|
|
|
- mddev->sysfs_action = NULL;
|
|
|
|
- mddev->private = NULL;
|
|
|
|
|
|
+ if (to_remove != &md_redundancy_group)
|
|
|
|
+ sysfs_remove_group(&mddev->kobj, to_remove);
|
|
|
|
+ if (mddev->pers == NULL ||
|
|
|
|
+ mddev->pers->sync_request == NULL) {
|
|
|
|
+ sysfs_remove_group(&mddev->kobj, &md_redundancy_group);
|
|
|
|
+ if (mddev->sysfs_action)
|
|
|
|
+ sysfs_put(mddev->sysfs_action);
|
|
|
|
+ mddev->sysfs_action = NULL;
|
|
|
|
+ }
|
|
mutex_unlock(&mddev->open_mutex);
|
|
mutex_unlock(&mddev->open_mutex);
|
|
} else
|
|
} else
|
|
mutex_unlock(&mddev->reconfig_mutex);
|
|
mutex_unlock(&mddev->reconfig_mutex);
|
|
@@ -2996,6 +3000,23 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
|
|
/* Looks like we have a winner */
|
|
/* Looks like we have a winner */
|
|
mddev_suspend(mddev);
|
|
mddev_suspend(mddev);
|
|
mddev->pers->stop(mddev);
|
|
mddev->pers->stop(mddev);
|
|
|
|
+
|
|
|
|
+ if (mddev->pers->sync_request == NULL &&
|
|
|
|
+ pers->sync_request != NULL) {
|
|
|
|
+ /* need to add the md_redundancy_group */
|
|
|
|
+ if (sysfs_create_group(&mddev->kobj, &md_redundancy_group))
|
|
|
|
+ printk(KERN_WARNING
|
|
|
|
+ "md: cannot register extra attributes for %s\n",
|
|
|
|
+ mdname(mddev));
|
|
|
|
+ mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action");
|
|
|
|
+ }
|
|
|
|
+ if (mddev->pers->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;
|
|
|
|
+ }
|
|
|
|
+
|
|
module_put(mddev->pers->owner);
|
|
module_put(mddev->pers->owner);
|
|
/* Invalidate devices that are now superfluous */
|
|
/* Invalidate devices that are now superfluous */
|
|
list_for_each_entry(rdev, &mddev->disks, same_set)
|
|
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)
|
|
mddev->queue->unplug_fn = NULL;
|
|
mddev->queue->unplug_fn = NULL;
|
|
mddev->queue->backing_dev_info.congested_fn = NULL;
|
|
mddev->queue->backing_dev_info.congested_fn = NULL;
|
|
module_put(mddev->pers->owner);
|
|
module_put(mddev->pers->owner);
|
|
- if (mddev->pers->sync_request && mddev->private == NULL)
|
|
|
|
- mddev->private = (void*)1;
|
|
|
|
|
|
+ if (mddev->pers->sync_request && mddev->to_remove == NULL)
|
|
|
|
+ mddev->to_remove = &md_redundancy_group;
|
|
mddev->pers = NULL;
|
|
mddev->pers = NULL;
|
|
/* tell userspace to handle 'inactive' */
|
|
/* tell userspace to handle 'inactive' */
|
|
sysfs_notify_dirent(mddev->sysfs_state);
|
|
sysfs_notify_dirent(mddev->sysfs_state);
|