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