aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/md.c71
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;
}