diff --git a/drivers/md/md.c b/drivers/md/md.c index edf777f6fe561644a7b6699596e5f7533c8c593e..e8d238885cd2eb66bcf68ffaf1c2cda256bdaa24 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -509,9 +509,9 @@ static inline int mddev_trylock(mddev_t * mddev) 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 * an access to the files will try to take reconfig_mutex * 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 * 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_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); } else 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 */ mddev_suspend(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); /* Invalidate devices that are now superfluous */ 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->backing_dev_info.congested_fn = NULL; 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; /* tell userspace to handle 'inactive' */ sysfs_notify_dirent(mddev->sysfs_state); diff --git a/drivers/md/md.h b/drivers/md/md.h index 8e4c75c00d4628f76ca32e0aaab243e3aea70d4c..722f5dfe1953ec5a22f1b705bd06d2d24629bf43 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -305,6 +305,7 @@ struct mddev_s atomic_t max_corr_read_errors; /* max read retries */ struct list_head all_mddevs; + struct attribute_group *to_remove; /* Generic barrier handling. * If there is a pending barrier request, all other * writes are blocked while the devices are flushed. diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 70ffbd071b2e797be6f715dd40de19a93c6567d3..a361398875d0f09adce0bac4c3dedad13e233ad5 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5090,7 +5090,9 @@ static int run(mddev_t *mddev) } /* Ok, everything is just fine now */ - if (sysfs_create_group(&mddev->kobj, &raid5_attrs_group)) + if (mddev->to_remove == &raid5_attrs_group) + mddev->to_remove = NULL; + else if (sysfs_create_group(&mddev->kobj, &raid5_attrs_group)) printk(KERN_WARNING "raid5: failed to create sysfs attributes for %s\n", mdname(mddev)); @@ -5137,7 +5139,8 @@ static int stop(mddev_t *mddev) mddev->queue->backing_dev_info.congested_fn = NULL; blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/ free_conf(conf); - mddev->private = &raid5_attrs_group; + mddev->private = NULL; + mddev->to_remove = &raid5_attrs_group; return 0; }