diff options
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r-- | drivers/md/md.c | 71 |
1 files changed, 42 insertions, 29 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 796cf70e1c9f..788559f42d43 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -147,28 +147,40 @@ static void rdevs_init_serial(struct mddev *mddev) } /* - * Create serial_info_pool for raid1 under conditions: - * 1. rdev is the first multi-queue device flaged with writemostly, - * also write-behind mode is enabled. - * 2. rdev is NULL, means want to enable serialization for all rdevs. + * rdev needs to enable serial stuffs if it meets the conditions: + * 1. it is multi-queue device flaged with writemostly. + * 2. the write-behind mode is enabled. + */ +static int rdev_need_serial(struct md_rdev *rdev) +{ + return (rdev && rdev->mddev->bitmap_info.max_write_behind > 0 && + rdev->bdev->bd_queue->nr_hw_queues != 1 && + test_bit(WriteMostly, &rdev->flags)); +} + +/* + * Init resource for rdev(s), then create serial_info_pool if: + * 1. rdev is the first device which return true from rdev_enable_serial. + * 2. rdev is NULL, means we want to enable serialization for all rdevs. */ void mddev_create_serial_pool(struct mddev *mddev, struct md_rdev *rdev, bool is_suspend) { - if (rdev && (mddev->bitmap_info.max_write_behind == 0 || - rdev->bdev->bd_queue->nr_hw_queues == 1 || - !test_bit(WriteMostly, &rdev->flags))) + if (rdev && !rdev_need_serial(rdev) && + !test_bit(CollisionCheck, &rdev->flags)) return; + if (!is_suspend) + mddev_suspend(mddev); + + if (!rdev) + rdevs_init_serial(mddev); + else + rdev_init_serial(rdev); + if (mddev->serial_info_pool == NULL) { unsigned int noio_flag; - if (!is_suspend) - mddev_suspend(mddev); - if (!rdev) - rdevs_init_serial(mddev); - else - rdev_init_serial(rdev); noio_flag = memalloc_noio_save(); mddev->serial_info_pool = mempool_create_kmalloc_pool(NR_SERIAL_INFOS, @@ -176,15 +188,16 @@ void mddev_create_serial_pool(struct mddev *mddev, struct md_rdev *rdev, memalloc_noio_restore(noio_flag); if (!mddev->serial_info_pool) pr_err("can't alloc memory pool for serialization\n"); - if (!is_suspend) - mddev_resume(mddev); } + if (!is_suspend) + mddev_resume(mddev); } /* - * Destroy serial_info_pool if rdev is the last device flaged with - * CollisionCheck, or rdev is NULL when we disable serialization - * for normal raid1. + * Free resource from rdev(s), and destroy serial_info_pool under conditions: + * 1. rdev is the last device flaged with CollisionCheck. + * 2. when bitmap is destroyed while policy is not enabled. + * 3. for disable policy, the pool is destroyed only when no rdev needs it. */ static void mddev_destroy_serial_pool(struct mddev *mddev, struct md_rdev *rdev, bool is_suspend) @@ -194,27 +207,27 @@ static void mddev_destroy_serial_pool(struct mddev *mddev, struct md_rdev *rdev, if (mddev->serial_info_pool) { struct md_rdev *temp; - int num = 0; + int num = 0; /* used to track if other rdevs need the pool */ - /* - * Check if other rdevs need serial_info_pool. - */ if (!is_suspend) mddev_suspend(mddev); rdev_for_each(temp, mddev) { if (!rdev) { - clear_bit(CollisionCheck, &temp->flags); - continue; - } - - if (temp != rdev && - test_bit(CollisionCheck, &temp->flags)) + if (!rdev_need_serial(temp)) + clear_bit(CollisionCheck, &temp->flags); + else + num++; + } else if (temp != rdev && + test_bit(CollisionCheck, &temp->flags)) num++; } if (rdev) clear_bit(CollisionCheck, &rdev->flags); - if (!rdev || !num) { + + if (num) + pr_info("The mempool could be used by other devices\n"); + else { mempool_destroy(mddev->serial_info_pool); mddev->serial_info_pool = NULL; } |