|
@@ -580,13 +580,17 @@ static void mddev_unlock(mddev_t * mddev)
|
|
* 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
|
|
* a deadlock.
|
|
* a deadlock.
|
|
- * So hold open_mutex instead - we are allowed to take
|
|
|
|
- * it while holding reconfig_mutex, and md_run can
|
|
|
|
- * use it to wait for the remove to complete.
|
|
|
|
|
|
+ * So hold set sysfs_active while the remove in happeing,
|
|
|
|
+ * and anything else which might set ->to_remove or my
|
|
|
|
+ * otherwise change the sysfs namespace will fail with
|
|
|
|
+ * -EBUSY if sysfs_active is still set.
|
|
|
|
+ * We set sysfs_active under reconfig_mutex and elsewhere
|
|
|
|
+ * test it under the same mutex to ensure its correct value
|
|
|
|
+ * is seen.
|
|
*/
|
|
*/
|
|
struct attribute_group *to_remove = mddev->to_remove;
|
|
struct attribute_group *to_remove = mddev->to_remove;
|
|
mddev->to_remove = NULL;
|
|
mddev->to_remove = NULL;
|
|
- mutex_lock(&mddev->open_mutex);
|
|
|
|
|
|
+ mddev->sysfs_active = 1;
|
|
mutex_unlock(&mddev->reconfig_mutex);
|
|
mutex_unlock(&mddev->reconfig_mutex);
|
|
|
|
|
|
if (mddev->kobj.sd) {
|
|
if (mddev->kobj.sd) {
|
|
@@ -600,7 +604,7 @@ static void mddev_unlock(mddev_t * mddev)
|
|
mddev->sysfs_action = NULL;
|
|
mddev->sysfs_action = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- mutex_unlock(&mddev->open_mutex);
|
|
|
|
|
|
+ mddev->sysfs_active = 0;
|
|
} else
|
|
} else
|
|
mutex_unlock(&mddev->reconfig_mutex);
|
|
mutex_unlock(&mddev->reconfig_mutex);
|
|
|
|
|
|
@@ -3008,7 +3012,9 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
|
|
* - new personality will access other array.
|
|
* - new personality will access other array.
|
|
*/
|
|
*/
|
|
|
|
|
|
- if (mddev->sync_thread || mddev->reshape_position != MaxSector)
|
|
|
|
|
|
+ if (mddev->sync_thread ||
|
|
|
|
+ mddev->reshape_position != MaxSector ||
|
|
|
|
+ mddev->sysfs_active)
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
|
|
|
|
if (!mddev->pers->quiesce) {
|
|
if (!mddev->pers->quiesce) {
|
|
@@ -4393,13 +4399,9 @@ int md_run(mddev_t *mddev)
|
|
|
|
|
|
if (mddev->pers)
|
|
if (mddev->pers)
|
|
return -EBUSY;
|
|
return -EBUSY;
|
|
-
|
|
|
|
- /* These two calls synchronise us with the
|
|
|
|
- * sysfs_remove_group calls in mddev_unlock,
|
|
|
|
- * so they must have completed.
|
|
|
|
- */
|
|
|
|
- mutex_lock(&mddev->open_mutex);
|
|
|
|
- mutex_unlock(&mddev->open_mutex);
|
|
|
|
|
|
+ /* Cannot run until previous stop completes properly */
|
|
|
|
+ if (mddev->sysfs_active)
|
|
|
|
+ return -EBUSY;
|
|
|
|
|
|
/*
|
|
/*
|
|
* Analyze all RAID superblock(s)
|
|
* Analyze all RAID superblock(s)
|
|
@@ -4770,7 +4772,8 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
|
|
mdk_rdev_t *rdev;
|
|
mdk_rdev_t *rdev;
|
|
|
|
|
|
mutex_lock(&mddev->open_mutex);
|
|
mutex_lock(&mddev->open_mutex);
|
|
- if (atomic_read(&mddev->openers) > is_open) {
|
|
|
|
|
|
+ if (atomic_read(&mddev->openers) > is_open ||
|
|
|
|
+ mddev->sysfs_active) {
|
|
printk("md: %s still in use.\n",mdname(mddev));
|
|
printk("md: %s still in use.\n",mdname(mddev));
|
|
err = -EBUSY;
|
|
err = -EBUSY;
|
|
} else if (mddev->pers) {
|
|
} else if (mddev->pers) {
|