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