From d817c17100183b266aa6bf8b868e016805d51d16 Mon Sep 17 00:00:00 2001
From: Coleman Kane <ckane@colemankane.org>
Date: Sun, 9 Aug 2020 12:12:25 -0400
Subject: [PATCH] Linux 5.9 compat: make_request_fn replaced with submit_bio
 interface

The make_request_fn and associated API was replaced recently in a
Linux 5.9 merge, to replace its functionality with a new submit_bio
member in struct block_device_operations.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Coleman Kane <ckane@colemankane.org>
Closes #10696
---
 config/kernel-make-request-fn.m4              | 92 +++++++++++--------
 include/os/linux/kernel/linux/blkdev_compat.h |  2 +
 module/os/linux/zfs/zvol_os.c                 | 18 +++-
 3 files changed, 74 insertions(+), 38 deletions(-)

diff --git a/config/kernel-make-request-fn.m4 b/config/kernel-make-request-fn.m4
index 609926c1b7..1576fece13 100644
--- a/config/kernel-make-request-fn.m4
+++ b/config/kernel-make-request-fn.m4
@@ -26,57 +26,75 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_MAKE_REQUEST_FN], [
 		struct request_queue *q __attribute__ ((unused));
 		q = blk_alloc_queue(make_request, NUMA_NO_NODE);
 	])
+
+	ZFS_LINUX_TEST_SRC([block_device_operations_submit_bio], [
+		#include <linux/blkdev.h>
+	],[
+		struct block_device_operations o;
+		o.submit_bio = NULL;
+	])
 ])
 
 AC_DEFUN([ZFS_AC_KERNEL_MAKE_REQUEST_FN], [
+	dnl # Checked as part of the blk_alloc_queue_request_fn test
 	dnl #
-	dnl # Linux 5.7 API Change
-	dnl # blk_alloc_queue() expects request function.
+	dnl # Linux 5.9 API Change
+	dnl # make_request_fn was moved into block_device_operations->submit_bio
 	dnl #
-	AC_MSG_CHECKING([whether blk_alloc_queue() expects request function])
-	ZFS_LINUX_TEST_RESULT([blk_alloc_queue_request_fn], [
+	AC_MSG_CHECKING([whether submit_bio is member of struct block_device_operations])
+	ZFS_LINUX_TEST_RESULT([block_device_operations_submit_bio], [
 		AC_MSG_RESULT(yes)
 
-		dnl # Checked as part of the blk_alloc_queue_request_fn test
-		AC_MSG_CHECKING([whether make_request_fn() returns blk_qc_t])
-		AC_MSG_RESULT(yes)
-
-		AC_DEFINE(HAVE_BLK_ALLOC_QUEUE_REQUEST_FN, 1,
-		    [blk_alloc_queue() expects request function])
-		AC_DEFINE(MAKE_REQUEST_FN_RET, blk_qc_t,
-		    [make_request_fn() return type])
-		AC_DEFINE(HAVE_MAKE_REQUEST_FN_RET_QC, 1,
-		    [Noting that make_request_fn() returns blk_qc_t])
-	],[
-		dnl #
-		dnl # Linux 3.2 API Change
-		dnl # make_request_fn returns void.
-		dnl #
-		AC_MSG_CHECKING([whether make_request_fn() returns void])
-		ZFS_LINUX_TEST_RESULT([make_request_fn_void], [
-			AC_MSG_RESULT(yes)
-			AC_DEFINE(MAKE_REQUEST_FN_RET, void,
-			    [make_request_fn() return type])
-			AC_DEFINE(HAVE_MAKE_REQUEST_FN_RET_VOID, 1,
-			    [Noting that make_request_fn() returns void])
+		AC_DEFINE(HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS, 1,
+		    [submit_bio is member of struct block_device_operations])
 		],[
-			AC_MSG_RESULT(no)
+		dnl # Checked as part of the blk_alloc_queue_request_fn test
+		dnl #
+		dnl # Linux 5.7 API Change
+		dnl # blk_alloc_queue() expects request function.
+		dnl #
+		AC_MSG_CHECKING([whether blk_alloc_queue() expects request function])
+		ZFS_LINUX_TEST_RESULT([blk_alloc_queue_request_fn], [
+			AC_MSG_CHECKING([whether make_request_fn() returns blk_qc_t])
+			AC_MSG_RESULT(yes)
 
+			AC_DEFINE(HAVE_BLK_ALLOC_QUEUE_REQUEST_FN, 1,
+			    [blk_alloc_queue() expects request function])
+			AC_DEFINE(MAKE_REQUEST_FN_RET, blk_qc_t,
+			    [make_request_fn() return type])
+			AC_DEFINE(HAVE_MAKE_REQUEST_FN_RET_QC, 1,
+			    [Noting that make_request_fn() returns blk_qc_t])
+		],[
 			dnl #
-			dnl # Linux 4.4 API Change
-			dnl # make_request_fn returns blk_qc_t.
+			dnl # Linux 3.2 API Change
+			dnl # make_request_fn returns void.
 			dnl #
-			AC_MSG_CHECKING(
-			    [whether make_request_fn() returns blk_qc_t])
-			ZFS_LINUX_TEST_RESULT([make_request_fn_blk_qc_t], [
+			AC_MSG_CHECKING([whether make_request_fn() returns void])
+			ZFS_LINUX_TEST_RESULT([make_request_fn_void], [
 				AC_MSG_RESULT(yes)
-				AC_DEFINE(MAKE_REQUEST_FN_RET, blk_qc_t,
+				AC_DEFINE(MAKE_REQUEST_FN_RET, void,
 				    [make_request_fn() return type])
-				AC_DEFINE(HAVE_MAKE_REQUEST_FN_RET_QC, 1,
-				    [Noting that make_request_fn() ]
-				    [returns blk_qc_t])
+				AC_DEFINE(HAVE_MAKE_REQUEST_FN_RET_VOID, 1,
+				    [Noting that make_request_fn() returns void])
 			],[
-				ZFS_LINUX_TEST_ERROR([make_request_fn])
+				AC_MSG_RESULT(no)
+
+				dnl #
+				dnl # Linux 4.4 API Change
+				dnl # make_request_fn returns blk_qc_t.
+				dnl #
+				AC_MSG_CHECKING(
+				    [whether make_request_fn() returns blk_qc_t])
+				ZFS_LINUX_TEST_RESULT([make_request_fn_blk_qc_t], [
+					AC_MSG_RESULT(yes)
+					AC_DEFINE(MAKE_REQUEST_FN_RET, blk_qc_t,
+					    [make_request_fn() return type])
+					AC_DEFINE(HAVE_MAKE_REQUEST_FN_RET_QC, 1,
+					    [Noting that make_request_fn() ]
+					    [returns blk_qc_t])
+				],[
+					ZFS_LINUX_TEST_ERROR([make_request_fn])
+				])
 			])
 		])
 	])
diff --git a/include/os/linux/kernel/linux/blkdev_compat.h b/include/os/linux/kernel/linux/blkdev_compat.h
index b46a6e40af..1cdc300a6f 100644
--- a/include/os/linux/kernel/linux/blkdev_compat.h
+++ b/include/os/linux/kernel/linux/blkdev_compat.h
@@ -487,6 +487,7 @@ blk_generic_end_io_acct(struct request_queue *q, int rw,
 #endif
 }
 
+#ifndef HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS
 static inline struct request_queue *
 blk_generic_alloc_queue(make_request_fn make_request, int node_id)
 {
@@ -500,5 +501,6 @@ blk_generic_alloc_queue(make_request_fn make_request, int node_id)
 	return (q);
 #endif
 }
+#endif /* !HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS */
 
 #endif /* _ZFS_BLKDEV_H */
diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c
index d1ce86c89b..218e1101ed 100644
--- a/module/os/linux/zfs/zvol_os.c
+++ b/module/os/linux/zfs/zvol_os.c
@@ -295,9 +295,17 @@ zvol_read(void *arg)
 	kmem_free(zvr, sizeof (zv_request_t));
 }
 
+#ifdef HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS
+static blk_qc_t
+zvol_submit_bio(struct bio *bio)
+#else
 static MAKE_REQUEST_FN_RET
 zvol_request(struct request_queue *q, struct bio *bio)
+#endif
 {
+#ifdef HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS
+	struct request_queue *q = bio->bi_disk->queue;
+#endif
 	zvol_state_t *zv = q->queuedata;
 	fstrans_cookie_t cookie = spl_fstrans_mark();
 	uint64_t offset = BIO_BI_SECTOR(bio) << 9;
@@ -425,7 +433,8 @@ zvol_request(struct request_queue *q, struct bio *bio)
 
 out:
 	spl_fstrans_unmark(cookie);
-#if defined(HAVE_MAKE_REQUEST_FN_RET_QC)
+#if defined(HAVE_MAKE_REQUEST_FN_RET_QC) || \
+	defined(HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS)
 	return (BLK_QC_T_NONE);
 #endif
 }
@@ -737,6 +746,9 @@ static struct block_device_operations zvol_ops = {
 	.revalidate_disk	= zvol_revalidate_disk,
 	.getgeo			= zvol_getgeo,
 	.owner			= THIS_MODULE,
+#ifdef HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS
+    .submit_bio		= zvol_submit_bio,
+#endif
 };
 
 /*
@@ -766,7 +778,11 @@ zvol_alloc(dev_t dev, const char *name)
 	list_link_init(&zv->zv_next);
 	mutex_init(&zv->zv_state_lock, NULL, MUTEX_DEFAULT, NULL);
 
+#ifdef HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS
+	zso->zvo_queue = blk_alloc_queue(NUMA_NO_NODE);
+#else
 	zso->zvo_queue = blk_generic_alloc_queue(zvol_request, NUMA_NO_NODE);
+#endif
 	if (zso->zvo_queue == NULL)
 		goto out_kmem;