From 2fcab8795c7c493845bfa277d44bc443802000b8 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf 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 Signed-off-by: Brian Behlendorf 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 + #include + #include + ],[ + 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