diff --git a/config/spl-build.m4 b/config/spl-build.m4 index d705c653..e9eb7786 100644 --- a/config/spl-build.m4 +++ b/config/spl-build.m4 @@ -40,6 +40,7 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [ SPL_AC_SHRINK_CONTROL_STRUCT SPL_AC_RWSEM_SPINLOCK_IS_RAW SPL_AC_RWSEM_ACTIVITY + SPL_AC_RWSEM_ATOMIC_LONG_COUNT SPL_AC_SCHED_RT_HEADER SPL_AC_2ARGS_VFS_GETATTR SPL_AC_USLEEP_RANGE @@ -1341,6 +1342,31 @@ AC_DEFUN([SPL_AC_RWSEM_ACTIVITY], [ EXTRA_KCFLAGS="$tmp_flags" ]) +dnl # +dnl # 4.8 API Change +dnl # +dnl # rwsem "->count" changed to atomic_long_t type +dnl # +AC_DEFUN([SPL_AC_RWSEM_ATOMIC_LONG_COUNT], [ + AC_MSG_CHECKING( + [whether struct rw_semaphore has atomic_long_t member count]) + tmp_flags="$EXTRA_KCFLAGS" + EXTRA_KCFLAGS="-Werror" + SPL_LINUX_TRY_COMPILE([ + #include + ],[ + DECLARE_RWSEM(dummy_semaphore); + (void) atomic_long_read(&dummy_semaphore.count); + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_RWSEM_ATOMIC_LONG_COUNT, 1, + [struct rw_semaphore has atomic_long_t member count]) + ],[ + AC_MSG_RESULT(no) + ]) + EXTRA_KCFLAGS="$tmp_flags" +]) + dnl # dnl # 3.9 API change, dnl # Moved things from linux/sched.h to linux/sched/rt.h diff --git a/include/linux/rwsem_compat.h b/include/linux/rwsem_compat.h index 9a4df267..c874885b 100644 --- a/include/linux/rwsem_compat.h +++ b/include/linux/rwsem_compat.h @@ -35,9 +35,12 @@ #define SPL_RWSEM_SINGLE_WRITER_VALUE (RWSEM_ACTIVE_WRITE_BIAS) #endif -/* Linux 3.16 change activity to count for rwsem-spinlock */ -#ifdef HAVE_RWSEM_ACTIVITY +/* Linux 3.16 changed activity to count for rwsem-spinlock */ +#if defined(HAVE_RWSEM_ACTIVITY) #define RWSEM_COUNT(sem) sem->activity +/* Linux 4.8 changed count to an atomic_long_t for !rwsem-spinlock */ +#elif defined(HAVE_RWSEM_ATOMIC_LONG_COUNT) +#define RWSEM_COUNT(sem) atomic_long_read(&(sem)->count) #else #define RWSEM_COUNT(sem) sem->count #endif diff --git a/module/spl/spl-rwlock.c b/module/spl/spl-rwlock.c index 9b356a84..77f46f2d 100644 --- a/module/spl/spl-rwlock.c +++ b/module/spl/spl-rwlock.c @@ -32,7 +32,7 @@ #define DEBUG_SUBSYSTEM S_RWLOCK -#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK +#if defined(CONFIG_RWSEM_GENERIC_SPINLOCK) static int __rwsem_tryupgrade(struct rw_semaphore *rwsem) { @@ -47,6 +47,15 @@ __rwsem_tryupgrade(struct rw_semaphore *rwsem) spl_rwsem_unlock_irqrestore(&rwsem->wait_lock, flags); return (ret); } +#elif defined(HAVE_RWSEM_ATOMIC_LONG_COUNT) +static int +__rwsem_tryupgrade(struct rw_semaphore *rwsem) +{ + long val; + val = atomic_long_cmpxchg(&rwsem->count, SPL_RWSEM_SINGLE_READER_VALUE, + SPL_RWSEM_SINGLE_WRITER_VALUE); + return (val == SPL_RWSEM_SINGLE_READER_VALUE); +} #else static int __rwsem_tryupgrade(struct rw_semaphore *rwsem)