diff options
-rw-r--r-- | drivers/md/md.c | 31 | ||||
-rw-r--r-- | drivers/md/md.h | 4 |
2 files changed, 21 insertions, 14 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 00c3fde39a12..03dcbfbe250f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -580,13 +580,17 @@ static void mddev_unlock(mddev_t * mddev) * an access to the files will try to take reconfig_mutex * while holding the file unremovable, which leads to * 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; mddev->to_remove = NULL; - mutex_lock(&mddev->open_mutex); + mddev->sysfs_active = 1; mutex_unlock(&mddev->reconfig_mutex); if (mddev->kobj.sd) { @@ -600,7 +604,7 @@ static void mddev_unlock(mddev_t * mddev) mddev->sysfs_action = NULL; } } - mutex_unlock(&mddev->open_mutex); + mddev->sysfs_active = 0; } else 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. */ - if (mddev->sync_thread || mddev->reshape_position != MaxSector) + if (mddev->sync_thread || + mddev->reshape_position != MaxSector || + mddev->sysfs_active) return -EBUSY; if (!mddev->pers->quiesce) { @@ -4393,13 +4399,9 @@ int md_run(mddev_t *mddev) if (mddev->pers) 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) @@ -4770,7 +4772,8 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) mdk_rdev_t *rdev; 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)); err = -EBUSY; } else if (mddev->pers) { diff --git a/drivers/md/md.h b/drivers/md/md.h index cccbadb31bae..6f797eceae31 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -145,6 +145,10 @@ struct mddev_s int suspended; atomic_t active_io; int ro; + int sysfs_active; /* set when sysfs deletes + * are happening, so run/ + * takeover/stop are not safe + */ struct gendisk *gendisk; |