mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-10 23:29:46 +00:00
md: move bitmap_destroy to the beginning of __md_stop
Since we have switched to sync way to handle METADATA_UPDATED msg for md-cluster, then process_metadata_update is depended on mddev->thread->wqueue. With the new change, clustered raid could possible hang if array received a METADATA_UPDATED msg after array unregistered mddev->thread, so we need to stop clustered raid (bitmap_destroy -> bitmap_free -> md_cluster_stop) earlier than unregister thread (mddev_detach -> md_unregister_thread). And this change should be safe for non-clustered raid since all writes are stopped before the destroy. Also in md_run, we activate the personality (pers->run()) before activating the bitmap (bitmap_create()). So it is pleasingly symmetric to stop the bitmap (bitmap_destroy()) before stopping the personality (__md_stop() calls pers->free()), we achieve this by move bitmap_destroy to the beginning of __md_stop. But we don't want to break the codes for waiting behind IO as Shaohua mentioned, so introduce bitmap_wait_behind_writes to call the codes, and call the new fun in both mddev_detach and bitmap_destroy, then we will not break original behind IO code and also fit the new condition well. Signed-off-by: Guoqing Jiang <gqjiang@suse.com> Signed-off-by: Shaohua Li <shli@fb.com>
This commit is contained in:
parent
ea17481fb4
commit
48df498daf
@ -1764,6 +1764,20 @@ void bitmap_free(struct bitmap *bitmap)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(bitmap_free);
|
EXPORT_SYMBOL(bitmap_free);
|
||||||
|
|
||||||
|
void bitmap_wait_behind_writes(struct mddev *mddev)
|
||||||
|
{
|
||||||
|
struct bitmap *bitmap = mddev->bitmap;
|
||||||
|
|
||||||
|
/* wait for behind writes to complete */
|
||||||
|
if (bitmap && atomic_read(&bitmap->behind_writes) > 0) {
|
||||||
|
pr_debug("md:%s: behind writes in progress - waiting to stop.\n",
|
||||||
|
mdname(mddev));
|
||||||
|
/* need to kick something here to make sure I/O goes? */
|
||||||
|
wait_event(bitmap->behind_wait,
|
||||||
|
atomic_read(&bitmap->behind_writes) == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void bitmap_destroy(struct mddev *mddev)
|
void bitmap_destroy(struct mddev *mddev)
|
||||||
{
|
{
|
||||||
struct bitmap *bitmap = mddev->bitmap;
|
struct bitmap *bitmap = mddev->bitmap;
|
||||||
@ -1771,6 +1785,8 @@ void bitmap_destroy(struct mddev *mddev)
|
|||||||
if (!bitmap) /* there was no bitmap */
|
if (!bitmap) /* there was no bitmap */
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
bitmap_wait_behind_writes(mddev);
|
||||||
|
|
||||||
mutex_lock(&mddev->bitmap_info.mutex);
|
mutex_lock(&mddev->bitmap_info.mutex);
|
||||||
spin_lock(&mddev->lock);
|
spin_lock(&mddev->lock);
|
||||||
mddev->bitmap = NULL; /* disconnect from the md device */
|
mddev->bitmap = NULL; /* disconnect from the md device */
|
||||||
|
@ -271,6 +271,7 @@ struct bitmap *get_bitmap_from_slot(struct mddev *mddev, int slot);
|
|||||||
int bitmap_copy_from_slot(struct mddev *mddev, int slot,
|
int bitmap_copy_from_slot(struct mddev *mddev, int slot,
|
||||||
sector_t *lo, sector_t *hi, bool clear_bits);
|
sector_t *lo, sector_t *hi, bool clear_bits);
|
||||||
void bitmap_free(struct bitmap *bitmap);
|
void bitmap_free(struct bitmap *bitmap);
|
||||||
|
void bitmap_wait_behind_writes(struct mddev *mddev);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -5675,15 +5675,7 @@ EXPORT_SYMBOL_GPL(md_stop_writes);
|
|||||||
|
|
||||||
static void mddev_detach(struct mddev *mddev)
|
static void mddev_detach(struct mddev *mddev)
|
||||||
{
|
{
|
||||||
struct bitmap *bitmap = mddev->bitmap;
|
bitmap_wait_behind_writes(mddev);
|
||||||
/* wait for behind writes to complete */
|
|
||||||
if (bitmap && atomic_read(&bitmap->behind_writes) > 0) {
|
|
||||||
pr_debug("md:%s: behind writes in progress - waiting to stop.\n",
|
|
||||||
mdname(mddev));
|
|
||||||
/* need to kick something here to make sure I/O goes? */
|
|
||||||
wait_event(bitmap->behind_wait,
|
|
||||||
atomic_read(&bitmap->behind_writes) == 0);
|
|
||||||
}
|
|
||||||
if (mddev->pers && mddev->pers->quiesce) {
|
if (mddev->pers && mddev->pers->quiesce) {
|
||||||
mddev->pers->quiesce(mddev, 1);
|
mddev->pers->quiesce(mddev, 1);
|
||||||
mddev->pers->quiesce(mddev, 0);
|
mddev->pers->quiesce(mddev, 0);
|
||||||
@ -5696,6 +5688,7 @@ static void mddev_detach(struct mddev *mddev)
|
|||||||
static void __md_stop(struct mddev *mddev)
|
static void __md_stop(struct mddev *mddev)
|
||||||
{
|
{
|
||||||
struct md_personality *pers = mddev->pers;
|
struct md_personality *pers = mddev->pers;
|
||||||
|
bitmap_destroy(mddev);
|
||||||
mddev_detach(mddev);
|
mddev_detach(mddev);
|
||||||
/* Ensure ->event_work is done */
|
/* Ensure ->event_work is done */
|
||||||
flush_workqueue(md_misc_wq);
|
flush_workqueue(md_misc_wq);
|
||||||
@ -5716,7 +5709,6 @@ void md_stop(struct mddev *mddev)
|
|||||||
* This is called from dm-raid
|
* This is called from dm-raid
|
||||||
*/
|
*/
|
||||||
__md_stop(mddev);
|
__md_stop(mddev);
|
||||||
bitmap_destroy(mddev);
|
|
||||||
if (mddev->bio_set)
|
if (mddev->bio_set)
|
||||||
bioset_free(mddev->bio_set);
|
bioset_free(mddev->bio_set);
|
||||||
}
|
}
|
||||||
@ -5854,7 +5846,6 @@ static int do_md_stop(struct mddev *mddev, int mode,
|
|||||||
if (mode == 0) {
|
if (mode == 0) {
|
||||||
pr_info("md: %s stopped.\n", mdname(mddev));
|
pr_info("md: %s stopped.\n", mdname(mddev));
|
||||||
|
|
||||||
bitmap_destroy(mddev);
|
|
||||||
if (mddev->bitmap_info.file) {
|
if (mddev->bitmap_info.file) {
|
||||||
struct file *f = mddev->bitmap_info.file;
|
struct file *f = mddev->bitmap_info.file;
|
||||||
spin_lock(&mddev->lock);
|
spin_lock(&mddev->lock);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user