1 /* kernel/rwsem.c: R/W semaphores, public implementation 2 * 3 * Written by David Howells (dhowells@redhat.com). 4 * Derived from asm-i386/semaphore.h 5 */ 6 7 #include <linux/types.h> 8 #include <linux/kernel.h> 9 #include <linux/sched.h> 10 #include <linux/sched/debug.h> 11 #include <linux/export.h> 12 #include <linux/rwsem.h> 13 #include <linux/atomic.h> 14 15 #include "rwsem.h" 16 17 /* 18 * lock for reading 19 */ 20 void __sched down_read(struct rw_semaphore *sem) 21 { 22 might_sleep(); 23 rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_); 24 25 LOCK_CONTENDED(sem, __down_read_trylock, __down_read); 26 rwsem_set_reader_owned(sem); 27 } 28 29 EXPORT_SYMBOL(down_read); 30 31 int __sched down_read_killable(struct rw_semaphore *sem) 32 { 33 might_sleep(); 34 rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_); 35 36 if (LOCK_CONTENDED_RETURN(sem, __down_read_trylock, __down_read_killable)) { 37 rwsem_release(&sem->dep_map, 1, _RET_IP_); 38 return -EINTR; 39 } 40 41 rwsem_set_reader_owned(sem); 42 return 0; 43 } 44 45 EXPORT_SYMBOL(down_read_killable); 46 47 /* 48 * trylock for reading -- returns 1 if successful, 0 if contention 49 */ 50 int down_read_trylock(struct rw_semaphore *sem) 51 { 52 int ret = __down_read_trylock(sem); 53 54 if (ret == 1) { 55 rwsem_acquire_read(&sem->dep_map, 0, 1, _RET_IP_); 56 rwsem_set_reader_owned(sem); 57 } 58 return ret; 59 } 60 61 EXPORT_SYMBOL(down_read_trylock); 62 63 /* 64 * lock for writing 65 */ 66 void __sched down_write(struct rw_semaphore *sem) 67 { 68 might_sleep(); 69 rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_); 70 71 LOCK_CONTENDED(sem, __down_write_trylock, __down_write); 72 rwsem_set_owner(sem); 73 } 74 75 EXPORT_SYMBOL(down_write); 76 77 /* 78 * lock for writing 79 */ 80 int __sched down_write_killable(struct rw_semaphore *sem) 81 { 82 might_sleep(); 83 rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_); 84 85 if (LOCK_CONTENDED_RETURN(sem, __down_write_trylock, __down_write_killable)) { 86 rwsem_release(&sem->dep_map, 1, _RET_IP_); 87 return -EINTR; 88 } 89 90 rwsem_set_owner(sem); 91 return 0; 92 } 93 94 EXPORT_SYMBOL(down_write_killable); 95 96 /* 97 * trylock for writing -- returns 1 if successful, 0 if contention 98 */ 99 int down_write_trylock(struct rw_semaphore *sem) 100 { 101 int ret = __down_write_trylock(sem); 102 103 if (ret == 1) { 104 rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_); 105 rwsem_set_owner(sem); 106 } 107 108 return ret; 109 } 110 111 EXPORT_SYMBOL(down_write_trylock); 112 113 /* 114 * release a read lock 115 */ 116 void up_read(struct rw_semaphore *sem) 117 { 118 rwsem_release(&sem->dep_map, 1, _RET_IP_); 119 120 __up_read(sem); 121 } 122 123 EXPORT_SYMBOL(up_read); 124 125 /* 126 * release a write lock 127 */ 128 void up_write(struct rw_semaphore *sem) 129 { 130 rwsem_release(&sem->dep_map, 1, _RET_IP_); 131 132 rwsem_clear_owner(sem); 133 __up_write(sem); 134 } 135 136 EXPORT_SYMBOL(up_write); 137 138 /* 139 * downgrade write lock to read lock 140 */ 141 void downgrade_write(struct rw_semaphore *sem) 142 { 143 lock_downgrade(&sem->dep_map, _RET_IP_); 144 145 rwsem_set_reader_owned(sem); 146 __downgrade_write(sem); 147 } 148 149 EXPORT_SYMBOL(downgrade_write); 150 151 #ifdef CONFIG_DEBUG_LOCK_ALLOC 152 153 void down_read_nested(struct rw_semaphore *sem, int subclass) 154 { 155 might_sleep(); 156 rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_); 157 158 LOCK_CONTENDED(sem, __down_read_trylock, __down_read); 159 rwsem_set_reader_owned(sem); 160 } 161 162 EXPORT_SYMBOL(down_read_nested); 163 164 void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest) 165 { 166 might_sleep(); 167 rwsem_acquire_nest(&sem->dep_map, 0, 0, nest, _RET_IP_); 168 169 LOCK_CONTENDED(sem, __down_write_trylock, __down_write); 170 rwsem_set_owner(sem); 171 } 172 173 EXPORT_SYMBOL(_down_write_nest_lock); 174 175 void down_read_non_owner(struct rw_semaphore *sem) 176 { 177 might_sleep(); 178 179 __down_read(sem); 180 } 181 182 EXPORT_SYMBOL(down_read_non_owner); 183 184 void down_write_nested(struct rw_semaphore *sem, int subclass) 185 { 186 might_sleep(); 187 rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_); 188 189 LOCK_CONTENDED(sem, __down_write_trylock, __down_write); 190 rwsem_set_owner(sem); 191 } 192 193 EXPORT_SYMBOL(down_write_nested); 194 195 int __sched down_write_killable_nested(struct rw_semaphore *sem, int subclass) 196 { 197 might_sleep(); 198 rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_); 199 200 if (LOCK_CONTENDED_RETURN(sem, __down_write_trylock, __down_write_killable)) { 201 rwsem_release(&sem->dep_map, 1, _RET_IP_); 202 return -EINTR; 203 } 204 205 rwsem_set_owner(sem); 206 return 0; 207 } 208 209 EXPORT_SYMBOL(down_write_killable_nested); 210 211 void up_read_non_owner(struct rw_semaphore *sem) 212 { 213 __up_read(sem); 214 } 215 216 EXPORT_SYMBOL(up_read_non_owner); 217 218 #endif 219 220 221