summarylogtreecommitdiffstats
path: root/linux-5.5-compat-blkg_tryget.patch
blob: f636e87f805a91b617d30e0c31db583e6a6c6f63 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
From 2fcab8795c7c493845bfa277d44bc443802000b8 Mon Sep 17 00:00:00 2001
From: Brian Behlendorf <behlendorf1@llnl.gov>
Date: Fri, 28 Feb 2020 08:58:39 -0800
Subject: [PATCH] Linux 5.5 compat: blkg_tryget()

Commit https://github.com/torvalds/linux/commit/9e8d42a0f accidentally
converted the static inline function blkg_tryget() to GPL-only for
kernels built with CONFIG_PREEMPT_RCU=y and CONFIG_BLK_CGROUP=y.

Resolve the build issue by providing our own equivalent functionality
when needed which uses rcu_read_lock_sched() internally as before.

Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #9745
Closes #10072
---
 config/kernel-blkg-tryget.m4 | 37 ++++++++++++++++++++++++++++++++++++
 config/kernel.m4             |  2 ++
 module/zfs/vdev_disk.c       | 32 ++++++++++++++++++++++++++++++-
 3 files changed, 70 insertions(+), 1 deletion(-)
 create mode 100644 config/kernel-blkg-tryget.m4

diff --git a/config/kernel-blkg-tryget.m4 b/config/kernel-blkg-tryget.m4
new file mode 100644
index 00000000000..fb831ca3b3e
--- /dev/null
+++ b/config/kernel-blkg-tryget.m4
@@ -0,0 +1,37 @@
+dnl #
+dnl # Linux 5.5 API,
+dnl #
+dnl # The Linux 5.5 kernel updated percpu_ref_tryget() which is inlined by
+dnl # blkg_tryget() to use rcu_read_lock() instead of rcu_read_lock_sched().
+dnl # As a side effect the function was converted to GPL-only.
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SRC_BLKG_TRYGET], [
+	ZFS_LINUX_TEST_SRC([blkg_tryget], [
+		#include <linux/blk-cgroup.h>
+		#include <linux/bio.h>
+		#include <linux/fs.h>
+	],[
+		struct blkcg_gq blkg __attribute__ ((unused));
+		bool rc __attribute__ ((unused));
+		rc = blkg_tryget(&blkg);
+	], [], [$ZFS_META_LICENSE])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_BLKG_TRYGET], [
+	AC_MSG_CHECKING([whether blkg_tryget() is available])
+	ZFS_LINUX_TEST_RESULT([blkg_tryget], [
+		AC_MSG_RESULT(yes)
+		AC_DEFINE(HAVE_BLKG_TRYGET, 1, [blkg_tryget() is available])
+
+		AC_MSG_CHECKING([whether blkg_tryget() is GPL-only])
+		ZFS_LINUX_TEST_RESULT([blkg_tryget_license], [
+			AC_MSG_RESULT(no)
+		],[
+			AC_MSG_RESULT(yes)
+			AC_DEFINE(HAVE_BLKG_TRYGET_GPL_ONLY, 1,
+			    [blkg_tryget() GPL-only])
+		])
+	],[
+		AC_MSG_RESULT(no)
+	])
+])
diff --git a/config/kernel.m4 b/config/kernel.m4
index dce619729d4..bea6f9b1bbf 100644
--- a/config/kernel.m4
+++ b/config/kernel.m4
@@ -70,6 +70,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
 	ZFS_AC_KERNEL_SRC_BIO_BI_STATUS
 	ZFS_AC_KERNEL_SRC_BIO_RW_BARRIER
 	ZFS_AC_KERNEL_SRC_BIO_RW_DISCARD
+	ZFS_AC_KERNEL_SRC_BLKG_TRYGET
 	ZFS_AC_KERNEL_SRC_BLK_QUEUE_BDI
 	ZFS_AC_KERNEL_SRC_BLK_QUEUE_DISCARD
 	ZFS_AC_KERNEL_SRC_BLK_QUEUE_SECURE_ERASE
@@ -186,6 +187,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
 	ZFS_AC_KERNEL_BIO_BI_STATUS
 	ZFS_AC_KERNEL_BIO_RW_BARRIER
 	ZFS_AC_KERNEL_BIO_RW_DISCARD
+	ZFS_AC_KERNEL_BLKG_TRYGET
 	ZFS_AC_KERNEL_BLK_QUEUE_BDI
 	ZFS_AC_KERNEL_BLK_QUEUE_DISCARD
 	ZFS_AC_KERNEL_BLK_QUEUE_SECURE_ERASE
diff --git a/module/zfs/vdev_disk.c b/module/zfs/vdev_disk.c
index 661f0f1b727..8544bb8ffb6 100644
--- a/module/zfs/vdev_disk.c
+++ b/module/zfs/vdev_disk.c
@@ -473,6 +473,36 @@ vdev_submit_bio_impl(struct bio *bio)
 
 #ifdef HAVE_BIO_SET_DEV
 #if defined(CONFIG_BLK_CGROUP) && defined(HAVE_BIO_SET_DEV_GPL_ONLY)
+/*
+ * The Linux 5.5 kernel updated percpu_ref_tryget() which is inlined by
+ * blkg_tryget() to use rcu_read_lock() instead of rcu_read_lock_sched().
+ * As a side effect the function was converted to GPL-only.  Define our
+ * own version when needed which uses rcu_read_lock_sched().
+ */
+#if defined(HAVE_BLKG_TRYGET_GPL_ONLY)
+static inline bool
+vdev_blkg_tryget(struct blkcg_gq *blkg)
+{
+	struct percpu_ref *ref = &blkg->refcnt;
+	unsigned long __percpu *count;
+	bool rc;
+
+	rcu_read_lock_sched();
+
+	if (__ref_is_percpu(ref, &count)) {
+		this_cpu_inc(*count);
+		rc = true;
+	} else {
+		rc = atomic_long_inc_not_zero(&ref->count);
+	}
+
+	rcu_read_unlock_sched();
+
+	return (rc);
+}
+#elif defined(HAVE_BLKG_TRYGET)
+#define	vdev_blkg_tryget(bg)	blkg_tryget(bg)
+#endif
 /*
  * The Linux 5.0 kernel updated the bio_set_dev() macro so it calls the
  * GPL-only bio_associate_blkg() symbol thus inadvertently converting
@@ -487,7 +517,7 @@ vdev_bio_associate_blkg(struct bio *bio)
 	ASSERT3P(q, !=, NULL);
 	ASSERT3P(bio->bi_blkg, ==, NULL);
 
-	if (q->root_blkg && blkg_tryget(q->root_blkg))
+	if (q->root_blkg && vdev_blkg_tryget(q->root_blkg))
 		bio->bi_blkg = q->root_blkg;
 }
 #define	bio_associate_blkg vdev_bio_associate_blkg