]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
md: prepare for enable raid1 io serialization
authorGuoqing Jiang <guoqing.jiang@cloud.ionos.com>
Mon, 23 Dec 2019 09:48:55 +0000 (10:48 +0100)
committerSong Liu <songliubraving@fb.com>
Mon, 13 Jan 2020 19:44:09 +0000 (11:44 -0800)
1. The related resources (spin_lock, list and waitqueue) are needed for
address raid1 reorder overlap issue too, in this case, rdev is set to
NULL for mddev_create/destroy_serial_pool which implies all rdevs need
to handle these resources.

And also add "is_suspend" to mddev_destroy_serial_pool since it will
be called under suspended situation, which also makes both create and
destroy pool have same arguments.

2. Introduce rdevs_init_serial which is called if raid1 io serialization
is enabled since all rdevs need to init related stuffs.

3. rdev_init_serial and clear_bit(CollisionCheck, &rdev->flags) should
be called between suspend and resume.

No need to export mddev_create_serial_pool since it is only called in
md-mod module.

Signed-off-by: Guoqing Jiang <guoqing.jiang@cloud.ionos.com>
Signed-off-by: Song Liu <songliubraving@fb.com>
drivers/md/md.c
drivers/md/md.h

index 8f5def0cb60a94cfa5e0c5e9e2c1f256dd6481e5..b9b041b7e196b993be3af1037851cbc097310786 100644 (file)
@@ -127,9 +127,6 @@ static inline int speed_max(struct mddev *mddev)
 
 static int rdev_init_serial(struct md_rdev *rdev)
 {
-       if (rdev->bdev->bd_queue->nr_hw_queues == 1)
-               return 0;
-
        spin_lock_init(&rdev->serial_list_lock);
        INIT_LIST_HEAD(&rdev->serial_list);
        init_waitqueue_head(&rdev->serial_io_wait);
@@ -138,17 +135,29 @@ static int rdev_init_serial(struct md_rdev *rdev)
        return 1;
 }
 
+static void rdevs_init_serial(struct mddev *mddev)
+{
+       struct md_rdev *rdev;
+
+       rdev_for_each(rdev, mddev) {
+               if (test_bit(CollisionCheck, &rdev->flags))
+                       continue;
+               rdev_init_serial(rdev);
+       }
+}
+
 /*
- * Create serial_info_pool if rdev is the first multi-queue device flaged
- * with writemostly, also write-behind mode is enabled.
+ * 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.
  */
 void mddev_create_serial_pool(struct mddev *mddev, struct md_rdev *rdev,
-                         bool is_suspend)
+                             bool is_suspend)
 {
-       if (mddev->bitmap_info.max_write_behind == 0)
-               return;
-
-       if (!test_bit(WriteMostly, &rdev->flags) || !rdev_init_serial(rdev))
+       if (rdev && (mddev->bitmap_info.max_write_behind == 0 ||
+                    rdev->bdev->bd_queue->nr_hw_queues == 1 ||
+                    !test_bit(WriteMostly, &rdev->flags)))
                return;
 
        if (mddev->serial_info_pool == NULL) {
@@ -156,6 +165,10 @@ void mddev_create_serial_pool(struct mddev *mddev, struct md_rdev *rdev,
 
                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,
@@ -167,15 +180,16 @@ void mddev_create_serial_pool(struct mddev *mddev, struct md_rdev *rdev,
                        mddev_resume(mddev);
        }
 }
-EXPORT_SYMBOL_GPL(mddev_create_serial_pool);
 
 /*
  * Destroy serial_info_pool if rdev is the last device flaged with
- * CollisionCheck.
+ * CollisionCheck, or rdev is NULL when we disable serialization
+ * for normal raid1.
  */
-static void mddev_destroy_serial_pool(struct mddev *mddev, struct md_rdev *rdev)
+static void mddev_destroy_serial_pool(struct mddev *mddev, struct md_rdev *rdev,
+                                     bool is_suspend)
 {
-       if (!test_and_clear_bit(CollisionCheck, &rdev->flags))
+       if (rdev && !test_bit(CollisionCheck, &rdev->flags))
                return;
 
        if (mddev->serial_info_pool) {
@@ -185,16 +199,27 @@ static void mddev_destroy_serial_pool(struct mddev *mddev, struct md_rdev *rdev)
                /*
                 * Check if other rdevs need serial_info_pool.
                 */
-               rdev_for_each(temp, mddev)
+               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))
                                num++;
-               if (!num) {
-                       mddev_suspend(rdev->mddev);
+               }
+
+               if (rdev)
+                       clear_bit(CollisionCheck, &rdev->flags);
+               if (!rdev || !num) {
                        mempool_destroy(mddev->serial_info_pool);
                        mddev->serial_info_pool = NULL;
-                       mddev_resume(rdev->mddev);
                }
+               if (!is_suspend)
+                       mddev_resume(mddev);
        }
 }
 
@@ -2377,7 +2402,7 @@ static void unbind_rdev_from_array(struct md_rdev *rdev)
        bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk);
        list_del_rcu(&rdev->same_set);
        pr_debug("md: unbind<%s>\n", bdevname(rdev->bdev,b));
-       mddev_destroy_serial_pool(rdev->mddev, rdev);
+       mddev_destroy_serial_pool(rdev->mddev, rdev, false);
        rdev->mddev = NULL;
        sysfs_remove_link(&rdev->kobj, "block");
        sysfs_put(rdev->sysfs_state);
@@ -2893,7 +2918,7 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len)
                mddev_create_serial_pool(rdev->mddev, rdev, false);
                err = 0;
        } else if (cmd_match(buf, "-writemostly")) {
-               mddev_destroy_serial_pool(rdev->mddev, rdev);
+               mddev_destroy_serial_pool(rdev->mddev, rdev, false);
                clear_bit(WriteMostly, &rdev->flags);
                err = 0;
        } else if (cmd_match(buf, "blocked")) {
index 7b811645cec7b52d3adc71e4bd6a91e8807a4c49..de04a8d3a67a55d4b450dd2130587e7f374dc802 100644 (file)
@@ -738,7 +738,7 @@ extern void md_reload_sb(struct mddev *mddev, int raid_disk);
 extern void md_update_sb(struct mddev *mddev, int force);
 extern void md_kick_rdev_from_array(struct md_rdev * rdev);
 extern void mddev_create_serial_pool(struct mddev *mddev, struct md_rdev *rdev,
-                                bool is_suspend);
+                                    bool is_suspend);
 struct md_rdev *md_find_rdev_nr_rcu(struct mddev *mddev, int nr);
 struct md_rdev *md_find_rdev_rcu(struct mddev *mddev, dev_t dev);