Blob Blame History Raw
From: Mike Snitzer <snitzer@redhat.com>
Date: Mon, 11 Dec 2017 11:02:29 -0500
Subject: [PATCH] dm mpath: factor out SCSI vs NVMe path selection
Git-commit: 0001ec565db7ed01a6cc9575453900801bd0841b
Patch-mainline: v4.16-rc1
References: bsc#1104967,FATE#325924

Trying to do both SCSI and NVMe bio-based handling with branching in the
same common code has proven too tedious on a code maintenance level.  In
addition it slightly hurts IO performance.

Fix this by factoring out __map_bio() and __map_bio_nvme().

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Acked-by: Hannes Reinecke <hare@suse.com>
---
 drivers/md/dm-mpath.c |   69 ++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 56 insertions(+), 13 deletions(-)

--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -555,38 +555,81 @@ static void multipath_release_clone(stru
 /*
  * Map cloned bios (bio-based multipath)
  */
-static int __multipath_map_bio(struct multipath *m, struct bio *bio, struct dm_mpath_io *mpio)
+
+static struct pgpath *__map_bio(struct multipath *m, struct bio *bio)
 {
 	struct pgpath *pgpath;
 	unsigned long flags;
 	bool queue_io;
 
 	/* Do we need to select a new pgpath? */
-	pgpath = READ_ONCE(m->current_pgpath);
+	pgpath = lockless_dereference(m->current_pgpath);
 	/* MPATHF_QUEUE_IO will never be set for NVMe */
 	queue_io = test_bit(MPATHF_QUEUE_IO, &m->flags);
 	if (!pgpath || !queue_io)
-		pgpath = choose_pgpath(m, mpio->nr_bytes);
+		pgpath = choose_pgpath(m, bio->bi_iter.bi_size);
 
-	if ((!pgpath && test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) ||
-	    (pgpath && queue_io)) {
+	if ((pgpath && queue_io) ||
+	    (!pgpath && test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags))) {
 		/* Queue for the daemon to resubmit */
 		spin_lock_irqsave(&m->lock, flags);
 		bio_list_add(&m->queued_bios, bio);
 		spin_unlock_irqrestore(&m->lock, flags);
 
-		if (m->queue_mode == DM_TYPE_NVME_BIO_BASED) {
+		/* PG_INIT_REQUIRED cannot be set without QUEUE_IO */
+		if (queue_io || test_bit(MPATHF_PG_INIT_REQUIRED, &m->flags))
+			pg_init_all_paths(m);
+		else if (!queue_io)
 			queue_work(kmultipathd, &m->process_queued_bios);
-		} else {
-			/* PG_INIT_REQUIRED cannot be set without QUEUE_IO */
-			if (queue_io || test_bit(MPATHF_PG_INIT_REQUIRED, &m->flags))
-				pg_init_all_paths(m);
-			else if (!queue_io)
-				queue_work(kmultipathd, &m->process_queued_bios);
+
+		return ERR_PTR(-EAGAIN);
+	}
+
+	return pgpath;
+}
+
+static struct pgpath *__map_bio_nvme(struct multipath *m, struct bio *bio)
+{
+	struct pgpath *pgpath;
+	unsigned long flags;
+
+	/* Do we need to select a new pgpath? */
+	/*
+	 * FIXME: currently only switching path if no path (due to failure, etc)
+	 * - which negates the point of using a path selector
+	 */
+	pgpath = lockless_dereference(m->current_pgpath);
+	if (!pgpath)
+		pgpath = choose_pgpath(m, bio->bi_iter.bi_size);
+
+	if (!pgpath) {
+		if (test_bit(MPATHF_QUEUE_IF_NO_PATH, &m->flags)) {
+			/* Queue for the daemon to resubmit */
+			spin_lock_irqsave(&m->lock, flags);
+			bio_list_add(&m->queued_bios, bio);
+			spin_unlock_irqrestore(&m->lock, flags);
+			queue_work(kmultipathd, &m->process_queued_bios);
+
+			return ERR_PTR(-EAGAIN);
 		}
+		return NULL;
+	}
+
+	return pgpath;
+}
 
+static int __multipath_map_bio(struct multipath *m, struct bio *bio,
+			       struct dm_mpath_io *mpio)
+{
+	struct pgpath *pgpath;
+
+	if (m->queue_mode == DM_TYPE_NVME_BIO_BASED)
+		pgpath = __map_bio_nvme(m, bio);
+	else
+		pgpath = __map_bio(m, bio);
+
+	if (IS_ERR(pgpath))
 		return DM_MAPIO_SUBMITTED;
-	}
 
 	if (!pgpath) {
 		if (must_push_back_bio(m))