Skip to content

Commit

Permalink
Linux 5.3 compat: rw_semaphore owner
Browse files Browse the repository at this point in the history
Commit torvalds/linux@94a9717b updated the
rwsem's owner field to contain additional flags describing the rwsem's
state.  Rather then update the wrappers to mask out these bits, the
code no longer relies on the owner stored by the kernel.  This does
increase the size of a krwlock_t but it makes the implementation
less sensitive to future kernel changes.

Reviewed-by: Tony Hutter <[email protected]>
Reviewed-by: Tomohiro Kusumi <[email protected]>
Signed-off-by: Brian Behlendorf <[email protected]>
Closes openzfs#9029
  • Loading branch information
behlendorf authored and tonyhutter committed Sep 16, 2019
1 parent a509fb9 commit 53b3d8f
Show file tree
Hide file tree
Showing 2 changed files with 5 additions and 66 deletions.
68 changes: 5 additions & 63 deletions include/spl/sys/rwlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,9 @@ typedef enum {
RW_READER = 2
} krw_t;

/*
* If CONFIG_RWSEM_SPIN_ON_OWNER is defined, rw_semaphore will have an owner
* field, so we don't need our own.
*/
typedef struct {
struct rw_semaphore rw_rwlock;
#ifndef CONFIG_RWSEM_SPIN_ON_OWNER
kthread_t *rw_owner;
#endif
#ifdef CONFIG_LOCKDEP
krw_type_t rw_type;
#endif /* CONFIG_LOCKDEP */
Expand All @@ -97,31 +91,19 @@ typedef struct {
static inline void
spl_rw_set_owner(krwlock_t *rwp)
{
/*
* If CONFIG_RWSEM_SPIN_ON_OWNER is defined, down_write, up_write,
* downgrade_write and __init_rwsem will set/clear owner for us.
*/
#ifndef CONFIG_RWSEM_SPIN_ON_OWNER
rwp->rw_owner = current;
#endif
}

static inline void
spl_rw_clear_owner(krwlock_t *rwp)
{
#ifndef CONFIG_RWSEM_SPIN_ON_OWNER
rwp->rw_owner = NULL;
#endif
}

static inline kthread_t *
rw_owner(krwlock_t *rwp)
{
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
return (SEM(rwp)->owner);
#else
return (rwp->rw_owner);
#endif
}

#ifdef CONFIG_LOCKDEP
Expand All @@ -148,62 +130,22 @@ spl_rw_lockdep_on_maybe(krwlock_t *rwp) \
#define spl_rw_lockdep_on_maybe(rwp)
#endif /* CONFIG_LOCKDEP */


static inline int
RW_WRITE_HELD(krwlock_t *rwp)
RW_LOCK_HELD(krwlock_t *rwp)
{
return (rw_owner(rwp) == current);
return (spl_rwsem_is_locked(SEM(rwp)));
}

static inline int
RW_LOCK_HELD(krwlock_t *rwp)
RW_WRITE_HELD(krwlock_t *rwp)
{
return (spl_rwsem_is_locked(SEM(rwp)));
return (rw_owner(rwp) == current);
}

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);
return (RW_LOCK_HELD(rwp) && rw_owner(rwp) == NULL);
}

/*
Expand Down
3 changes: 0 additions & 3 deletions module/spl/spl-rwlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,6 @@ 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_);
#ifdef CONFIG_RWSEM_SPIN_ON_OWNER
rwsem->owner = current;
#endif
return (1);
}
return (0);
Expand Down

0 comments on commit 53b3d8f

Please sign in to comment.