diff options
Diffstat (limited to 'linux-5.3-compat-retire-rw_tryupgrade.patch')
-rw-r--r-- | linux-5.3-compat-retire-rw_tryupgrade.patch | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/linux-5.3-compat-retire-rw_tryupgrade.patch b/linux-5.3-compat-retire-rw_tryupgrade.patch new file mode 100644 index 000000000000..253c35868b7e --- /dev/null +++ b/linux-5.3-compat-retire-rw_tryupgrade.patch @@ -0,0 +1,236 @@ +From ee1848356f32e31f001ca96cc68e06a445f72108 Mon Sep 17 00:00:00 2001 +From: Brian Behlendorf <behlendorf1@llnl.gov> +Date: Fri, 12 Jul 2019 14:06:36 -0700 +Subject: [PATCH] Linux 5.3 compat: retire rw_tryupgrade() + +The Linux kernel's rwsem's have never provided an interface to +allow a reader to be upgraded to a writer. Historically, this +functionality has been implemented by a SPL wrapper function. +However, this approach depends on internal knowledge of the +rw_semaphore and is therefore rather brittle. + +Since the ZFS code must always be able to fallback to rw_exit() +and rw_enter() when an rw_tryupgrade() fails; this functionality +isn't critical. Furthermore, the only potentially performance +sensitive consumer is dmu_zfetch() and no decrease in performance +was observed with this change applied. See the PR comments for +additional testing details. + +Therefore, it is being retired to make the build more robust and +to simplify the rwlock implementation. + +Reviewed-by: Tony Hutter <hutter2@llnl.gov> +Reviewed-by: Tomohiro Kusumi <kusumi.tomohiro@gmail.com> +Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> +Closes #9029 +--- + include/spl/sys/rwlock.h | 60 +++-------------------- + module/spl/spl-rwlock.c | 101 --------------------------------------- + 2 files changed, 7 insertions(+), 154 deletions(-) + +diff --git a/include/spl/sys/rwlock.h b/include/spl/sys/rwlock.h +index 5e052b532a4..89e02fa8f04 100644 +--- a/include/spl/sys/rwlock.h ++++ b/include/spl/sys/rwlock.h +@@ -29,43 +29,6 @@ + #include <linux/rwsem.h> + #include <linux/sched.h> + +-/* Linux kernel compatibility */ +-#if defined(CONFIG_PREEMPT_RT_FULL) +-#define SPL_RWSEM_SINGLE_READER_VALUE (1) +-#define SPL_RWSEM_SINGLE_WRITER_VALUE (0) +-#elif defined(CONFIG_RWSEM_GENERIC_SPINLOCK) +-#define SPL_RWSEM_SINGLE_READER_VALUE (1) +-#define SPL_RWSEM_SINGLE_WRITER_VALUE (-1) +-#elif defined(RWSEM_ACTIVE_MASK) +-#define SPL_RWSEM_SINGLE_READER_VALUE (RWSEM_ACTIVE_READ_BIAS) +-#define SPL_RWSEM_SINGLE_WRITER_VALUE (RWSEM_ACTIVE_WRITE_BIAS) +-#endif +- +-/* Linux 3.16 changed activity to count for rwsem-spinlock */ +-#if defined(CONFIG_PREEMPT_RT_FULL) +-#define RWSEM_COUNT(sem) sem->read_depth +-#elif 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 +- +-#if defined(RWSEM_SPINLOCK_IS_RAW) +-#define spl_rwsem_lock_irqsave(lk, fl) raw_spin_lock_irqsave(lk, fl) +-#define spl_rwsem_unlock_irqrestore(lk, fl) \ +- raw_spin_unlock_irqrestore(lk, fl) +-#define spl_rwsem_trylock_irqsave(lk, fl) raw_spin_trylock_irqsave(lk, fl) +-#else +-#define spl_rwsem_lock_irqsave(lk, fl) spin_lock_irqsave(lk, fl) +-#define spl_rwsem_unlock_irqrestore(lk, fl) spin_unlock_irqrestore(lk, fl) +-#define spl_rwsem_trylock_irqsave(lk, fl) spin_trylock_irqsave(lk, fl) +-#endif /* RWSEM_SPINLOCK_IS_RAW */ +- +-#define spl_rwsem_is_locked(rwsem) rwsem_is_locked(rwsem) +- + typedef enum { + RW_DRIVER = 2, + RW_DEFAULT = 4, +@@ -133,7 +96,7 @@ spl_rw_lockdep_on_maybe(krwlock_t *rwp) \ + static inline int + RW_LOCK_HELD(krwlock_t *rwp) + { +- return (spl_rwsem_is_locked(SEM(rwp))); ++ return (rwsem_is_locked(SEM(rwp))); + } + + static inline int +@@ -170,6 +133,12 @@ RW_READ_HELD(krwlock_t *rwp) + */ + #define rw_destroy(rwp) ((void) 0) + ++/* ++ * Upgrading a rwsem from a reader to a writer is not supported by the ++ * Linux kernel. The lock must be dropped and reacquired as a writer. ++ */ ++#define rw_tryupgrade(rwp) RW_WRITE_HELD(rwp) ++ + #define rw_tryenter(rwp, rw) \ + ({ \ + int _rc_ = 0; \ +@@ -228,24 +197,9 @@ RW_READ_HELD(krwlock_t *rwp) + spl_rw_lockdep_on_maybe(rwp); \ + }) + +-#define rw_tryupgrade(rwp) \ +-({ \ +- int _rc_ = 0; \ +- \ +- if (RW_WRITE_HELD(rwp)) { \ +- _rc_ = 1; \ +- } else { \ +- spl_rw_lockdep_off_maybe(rwp); \ +- if ((_rc_ = rwsem_tryupgrade(SEM(rwp)))) \ +- spl_rw_set_owner(rwp); \ +- spl_rw_lockdep_on_maybe(rwp); \ +- } \ +- _rc_; \ +-}) + /* END CSTYLED */ + + int spl_rw_init(void); + void spl_rw_fini(void); +-int rwsem_tryupgrade(struct rw_semaphore *rwsem); + + #endif /* _SPL_RWLOCK_H */ +diff --git a/module/spl/spl-rwlock.c b/module/spl/spl-rwlock.c +index 886e16924e6..10f7c38db4e 100644 +--- a/module/spl/spl-rwlock.c ++++ b/module/spl/spl-rwlock.c +@@ -24,106 +24,5 @@ + * Solaris Porting Layer (SPL) Reader/Writer Lock Implementation. + */ + +-#include <sys/rwlock.h> +-#include <linux/module.h> +- +-#if defined(CONFIG_PREEMPT_RT_FULL) +- +-#include <linux/rtmutex.h> +-#define RT_MUTEX_OWNER_MASKALL 1UL +- +-static int +-__rwsem_tryupgrade(struct rw_semaphore *rwsem) +-{ +-#if defined(READER_BIAS) && defined(WRITER_BIAS) +- /* +- * After the 4.9.20-rt16 kernel the realtime patch series lifted the +- * single reader restriction. While this could be accommodated by +- * adding additional compatibility code assume the rwsem can never +- * be upgraded. All caller must already cleanly handle this case. +- */ +- return (0); +-#else +- ASSERT((struct task_struct *) +- ((unsigned long)rwsem->lock.owner & ~RT_MUTEX_OWNER_MASKALL) == +- current); +- +- /* +- * Prior to 4.9.20-rt16 kernel the realtime patch series, rwsem is +- * implemented as a single mutex held by readers and writers alike. +- * However, this implementation would prevent a thread from taking +- * a read lock twice, as the mutex would already be locked on +- * the second attempt. Therefore the implementation allows a +- * single thread to take a rwsem as read lock multiple times +- * tracking that nesting as read_depth counter. +- */ +- if (rwsem->read_depth <= 1) { +- /* +- * In case, the current thread has not taken the lock +- * more than once as read lock, we can allow an +- * upgrade to a write lock. rwsem_rt.h implements +- * write locks as read_depth == 0. +- */ +- rwsem->read_depth = 0; +- return (1); +- } +- return (0); +-#endif +-} +-#elif defined(CONFIG_RWSEM_GENERIC_SPINLOCK) +-static int +-__rwsem_tryupgrade(struct rw_semaphore *rwsem) +-{ +- int ret = 0; +- unsigned long flags; +- spl_rwsem_lock_irqsave(&rwsem->wait_lock, flags); +- if (RWSEM_COUNT(rwsem) == SPL_RWSEM_SINGLE_READER_VALUE && +- list_empty(&rwsem->wait_list)) { +- ret = 1; +- RWSEM_COUNT(rwsem) = SPL_RWSEM_SINGLE_WRITER_VALUE; +- } +- spl_rwsem_unlock_irqrestore(&rwsem->wait_lock, flags); +- return (ret); +-} +-#elif defined(RWSEM_ACTIVE_MASK) +-#if 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) +-{ +- typeof(rwsem->count) val; +- val = cmpxchg(&rwsem->count, SPL_RWSEM_SINGLE_READER_VALUE, +- SPL_RWSEM_SINGLE_WRITER_VALUE); +- return (val == SPL_RWSEM_SINGLE_READER_VALUE); +-} +-#endif +-#else +-static int +-__rwsem_tryupgrade(struct rw_semaphore *rwsem) +-{ +- return (0); +-} +-#endif +- +-int +-rwsem_tryupgrade(struct rw_semaphore *rwsem) +-{ +- if (__rwsem_tryupgrade(rwsem)) { +- rwsem_release(&rwsem->dep_map, 1, _RET_IP_); +- rwsem_acquire(&rwsem->dep_map, 0, 1, _RET_IP_); +- return (1); +- } +- return (0); +-} +-EXPORT_SYMBOL(rwsem_tryupgrade); +- + int spl_rw_init(void) { return 0; } + void spl_rw_fini(void) { } |