diff options
Diffstat (limited to 'kernel/locking/rwsem.h')
| -rw-r--r-- | kernel/locking/rwsem.h | 95 |
1 files changed, 71 insertions, 24 deletions
diff --git a/kernel/locking/rwsem.h b/kernel/locking/rwsem.h index b9d0e72aa80f..bad2bca0268b 100644 --- a/kernel/locking/rwsem.h +++ b/kernel/locking/rwsem.h | |||
| @@ -1,24 +1,30 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | /* | 2 | /* |
| 3 | * The owner field of the rw_semaphore structure will be set to | 3 | * The least significant 2 bits of the owner value has the following |
| 4 | * RWSEM_READER_OWNED when a reader grabs the lock. A writer will clear | 4 | * meanings when set. |
| 5 | * the owner field when it unlocks. A reader, on the other hand, will | 5 | * - RWSEM_READER_OWNED (bit 0): The rwsem is owned by readers |
| 6 | * not touch the owner field when it unlocks. | 6 | * - RWSEM_ANONYMOUSLY_OWNED (bit 1): The rwsem is anonymously owned, |
| 7 | * i.e. the owner(s) cannot be readily determined. It can be reader | ||
| 8 | * owned or the owning writer is indeterminate. | ||
| 7 | * | 9 | * |
| 8 | * In essence, the owner field now has the following 4 states: | 10 | * When a writer acquires a rwsem, it puts its task_struct pointer |
| 9 | * 1) 0 | 11 | * into the owner field. It is cleared after an unlock. |
| 10 | * - lock is free or the owner hasn't set the field yet | 12 | * |
| 11 | * 2) RWSEM_READER_OWNED | 13 | * When a reader acquires a rwsem, it will also puts its task_struct |
| 12 | * - lock is currently or previously owned by readers (lock is free | 14 | * pointer into the owner field with both the RWSEM_READER_OWNED and |
| 13 | * or not set by owner yet) | 15 | * RWSEM_ANONYMOUSLY_OWNED bits set. On unlock, the owner field will |
| 14 | * 3) RWSEM_ANONYMOUSLY_OWNED bit set with some other bits set as well | 16 | * largely be left untouched. So for a free or reader-owned rwsem, |
| 15 | * - lock is owned by an anonymous writer, so spinning on the lock | 17 | * the owner value may contain information about the last reader that |
| 16 | * owner should be disabled. | 18 | * acquires the rwsem. The anonymous bit is set because that particular |
| 17 | * 4) Other non-zero value | 19 | * reader may or may not still own the lock. |
| 18 | * - a writer owns the lock and other writers can spin on the lock owner. | 20 | * |
| 21 | * That information may be helpful in debugging cases where the system | ||
| 22 | * seems to hang on a reader owned rwsem especially if only one reader | ||
| 23 | * is involved. Ideally we would like to track all the readers that own | ||
| 24 | * a rwsem, but the overhead is simply too big. | ||
| 19 | */ | 25 | */ |
| 20 | #define RWSEM_ANONYMOUSLY_OWNED (1UL << 0) | 26 | #define RWSEM_READER_OWNED (1UL << 0) |
| 21 | #define RWSEM_READER_OWNED ((struct task_struct *)RWSEM_ANONYMOUSLY_OWNED) | 27 | #define RWSEM_ANONYMOUSLY_OWNED (1UL << 1) |
| 22 | 28 | ||
| 23 | #ifdef CONFIG_DEBUG_RWSEMS | 29 | #ifdef CONFIG_DEBUG_RWSEMS |
| 24 | # define DEBUG_RWSEMS_WARN_ON(c) DEBUG_LOCKS_WARN_ON(c) | 30 | # define DEBUG_RWSEMS_WARN_ON(c) DEBUG_LOCKS_WARN_ON(c) |
| @@ -44,15 +50,26 @@ static inline void rwsem_clear_owner(struct rw_semaphore *sem) | |||
| 44 | WRITE_ONCE(sem->owner, NULL); | 50 | WRITE_ONCE(sem->owner, NULL); |
| 45 | } | 51 | } |
| 46 | 52 | ||
| 53 | /* | ||
| 54 | * The task_struct pointer of the last owning reader will be left in | ||
| 55 | * the owner field. | ||
| 56 | * | ||
| 57 | * Note that the owner value just indicates the task has owned the rwsem | ||
| 58 | * previously, it may not be the real owner or one of the real owners | ||
| 59 | * anymore when that field is examined, so take it with a grain of salt. | ||
| 60 | */ | ||
| 61 | static inline void __rwsem_set_reader_owned(struct rw_semaphore *sem, | ||
| 62 | struct task_struct *owner) | ||
| 63 | { | ||
| 64 | unsigned long val = (unsigned long)owner | RWSEM_READER_OWNED | ||
| 65 | | RWSEM_ANONYMOUSLY_OWNED; | ||
| 66 | |||
| 67 | WRITE_ONCE(sem->owner, (struct task_struct *)val); | ||
| 68 | } | ||
| 69 | |||
| 47 | static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) | 70 | static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) |
| 48 | { | 71 | { |
| 49 | /* | 72 | __rwsem_set_reader_owned(sem, current); |
| 50 | * We check the owner value first to make sure that we will only | ||
| 51 | * do a write to the rwsem cacheline when it is really necessary | ||
| 52 | * to minimize cacheline contention. | ||
| 53 | */ | ||
| 54 | if (READ_ONCE(sem->owner) != RWSEM_READER_OWNED) | ||
| 55 | WRITE_ONCE(sem->owner, RWSEM_READER_OWNED); | ||
| 56 | } | 73 | } |
| 57 | 74 | ||
| 58 | /* | 75 | /* |
| @@ -72,6 +89,25 @@ static inline bool rwsem_has_anonymous_owner(struct task_struct *owner) | |||
| 72 | { | 89 | { |
| 73 | return (unsigned long)owner & RWSEM_ANONYMOUSLY_OWNED; | 90 | return (unsigned long)owner & RWSEM_ANONYMOUSLY_OWNED; |
| 74 | } | 91 | } |
| 92 | |||
| 93 | #ifdef CONFIG_DEBUG_RWSEMS | ||
| 94 | /* | ||
| 95 | * With CONFIG_DEBUG_RWSEMS configured, it will make sure that if there | ||
| 96 | * is a task pointer in owner of a reader-owned rwsem, it will be the | ||
| 97 | * real owner or one of the real owners. The only exception is when the | ||
| 98 | * unlock is done by up_read_non_owner(). | ||
| 99 | */ | ||
| 100 | #define rwsem_clear_reader_owned rwsem_clear_reader_owned | ||
| 101 | static inline void rwsem_clear_reader_owned(struct rw_semaphore *sem) | ||
| 102 | { | ||
| 103 | unsigned long val = (unsigned long)current | RWSEM_READER_OWNED | ||
| 104 | | RWSEM_ANONYMOUSLY_OWNED; | ||
| 105 | if (READ_ONCE(sem->owner) == (struct task_struct *)val) | ||
| 106 | cmpxchg_relaxed((unsigned long *)&sem->owner, val, | ||
| 107 | RWSEM_READER_OWNED | RWSEM_ANONYMOUSLY_OWNED); | ||
| 108 | } | ||
| 109 | #endif | ||
| 110 | |||
| 75 | #else | 111 | #else |
| 76 | static inline void rwsem_set_owner(struct rw_semaphore *sem) | 112 | static inline void rwsem_set_owner(struct rw_semaphore *sem) |
| 77 | { | 113 | { |
| @@ -81,7 +117,18 @@ static inline void rwsem_clear_owner(struct rw_semaphore *sem) | |||
| 81 | { | 117 | { |
| 82 | } | 118 | } |
| 83 | 119 | ||
| 120 | static inline void __rwsem_set_reader_owned(struct rw_semaphore *sem, | ||
| 121 | struct task_struct *owner) | ||
| 122 | { | ||
| 123 | } | ||
| 124 | |||
| 84 | static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) | 125 | static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) |
| 85 | { | 126 | { |
| 86 | } | 127 | } |
| 87 | #endif | 128 | #endif |
| 129 | |||
| 130 | #ifndef rwsem_clear_reader_owned | ||
| 131 | static inline void rwsem_clear_reader_owned(struct rw_semaphore *sem) | ||
| 132 | { | ||
| 133 | } | ||
| 134 | #endif | ||
