diff options
author | Tony Hutter <[email protected]> | 2019-02-15 12:37:20 -0800 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2019-02-15 12:37:20 -0800 |
commit | e73ab1b38cd099f3416eed0ab5576639383bbdcc (patch) | |
tree | fae3550e9b449d2601da9153e695f54cba89c352 | |
parent | 2d76ab9e422286b4e97fbd014a2efb05804d4181 (diff) |
Linux 4.20 compat: Fix VERIFY(RW_READ_HELD(&hash->mh_contents))
The 4.20 kernel changed the meaning of the rw_semaphore.owner bits,
causing an assertion when loading the module under the 4.20 kernel.
This patch fixes the issue.
Reviewed-by: Chunwei Chen <[email protected]>
Reviewed-by: Brian Behlendorf <[email protected]>
Signed-off-by: Tony Hutter <[email protected]>
Closes #8360
Closes #8389
-rw-r--r-- | include/spl/sys/rwlock.h | 55 |
1 files changed, 45 insertions, 10 deletions
diff --git a/include/spl/sys/rwlock.h b/include/spl/sys/rwlock.h index 0ac528e16..a1c1fd469 100644 --- a/include/spl/sys/rwlock.h +++ b/include/spl/sys/rwlock.h @@ -148,16 +148,6 @@ spl_rw_lockdep_on_maybe(krwlock_t *rwp) \ #define spl_rw_lockdep_on_maybe(rwp) #endif /* CONFIG_LOCKDEP */ -static inline int -RW_READ_HELD(krwlock_t *rwp) -{ - /* - * Linux 4.8 will set owner to 1 when read held instead of leave it - * NULL. So we check whether owner <= 1. - */ - return (spl_rwsem_is_locked(SEM(rwp)) && - (unsigned long)rw_owner(rwp) <= 1); -} static inline int RW_WRITE_HELD(krwlock_t *rwp) @@ -171,6 +161,51 @@ RW_LOCK_HELD(krwlock_t *rwp) return (spl_rwsem_is_locked(SEM(rwp))); } +static inline int +RW_READ_HELD(krwlock_t *rwp) +{ + if (!RW_LOCK_HELD(rwp)) + return (0); + + /* + * rw_semaphore cheat sheet: + * + * < 3.16: + * There's no rw_semaphore.owner, so use rwp.owner instead. + * If rwp.owner == NULL then it's a reader + * + * 3.16 - 4.7: + * rw_semaphore.owner added (https://lwn.net/Articles/596656/) + * and CONFIG_RWSEM_SPIN_ON_OWNER introduced. + * If rw_semaphore.owner == NULL then it's a reader + * + * 4.8 - 4.16.16: + * RWSEM_READER_OWNED added as an internal #define. + * (https://lore.kernel.org/patchwork/patch/678590/) + * If rw_semaphore.owner == 1 then it's a reader + * + * 4.16.17 - 4.19: + * RWSEM_OWNER_UNKNOWN introduced as ((struct task_struct *)-1L) + * (https://do-db2.lkml.org/lkml/2018/5/15/985) + * If rw_semaphore.owner == 1 then it's a reader. + * + * 4.20+: + * RWSEM_OWNER_UNKNOWN changed to ((struct task_struct *)-2L) + * (https://lkml.org/lkml/2018/9/6/986) + * If rw_semaphore.owner & 1 then it's a reader, and also the reader's + * task_struct may be embedded in rw_semaphore->owner. + */ +#if defined(CONFIG_RWSEM_SPIN_ON_OWNER) && defined(RWSEM_OWNER_UNKNOWN) + if (RWSEM_OWNER_UNKNOWN == (struct task_struct *)-2L) { + /* 4.20+ kernels with CONFIG_RWSEM_SPIN_ON_OWNER */ + return ((unsigned long) SEM(rwp)->owner & 1); + } +#endif + + /* < 4.20 kernel or !CONFIG_RWSEM_SPIN_ON_OWNER */ + return (rw_owner(rwp) == NULL || (unsigned long) rw_owner(rwp) == 1); +} + /* * The following functions must be a #define and not static inline. * This ensures that the native linux semaphore functions (down/up) |