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 /* 16 * lock for reading 17 */ 18 void __sched down_read(struct rw_semaphore *sem) 19 { 20 might_sleep(); 21 rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_); 22 23 LOCK_CONTENDED(sem, __down_read_trylock, __down_read); 24 } 25 26 EXPORT_SYMBOL(down_read); 27 28 /* 29 * trylock for reading -- returns 1 if successful, 0 if contention 30 */ 31 int down_read_trylock(struct rw_semaphore *sem) 32 { 33 int ret = __down_read_trylock(sem); 34 35 if (ret == 1) 36 rwsem_acquire_read(&sem->dep_map, 0, 1, _RET_IP_); 37 return ret; 38 } 39 40 EXPORT_SYMBOL(down_read_trylock); 41 42 /* 43 * lock for writing 44 */ 45 void __sched down_write(struct rw_semaphore *sem) 46 { 47 might_sleep(); 48 rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_); 49 50 LOCK_CONTENDED(sem, __down_write_trylock, __down_write); 51 } 52 53 EXPORT_SYMBOL(down_write); 54 55 /* 56 * trylock for writing -- returns 1 if successful, 0 if contention 57 */ 58 int down_write_trylock(struct rw_semaphore *sem) 59 { 60 int ret = __down_write_trylock(sem); 61 62 if (ret == 1) 63 rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_); 64 return ret; 65 } 66 67 EXPORT_SYMBOL(down_write_trylock); 68 69 /* 70 * release a read lock 71 */ 72 void up_read(struct rw_semaphore *sem) 73 { 74 rwsem_release(&sem->dep_map, 1, _RET_IP_); 75 76 __up_read(sem); 77 } 78 79 EXPORT_SYMBOL(up_read); 80 81 /* 82 * release a write lock 83 */ 84 void up_write(struct rw_semaphore *sem) 85 { 86 rwsem_release(&sem->dep_map, 1, _RET_IP_); 87 88 __up_write(sem); 89 } 90 91 EXPORT_SYMBOL(up_write); 92 93 /* 94 * downgrade write lock to read lock 95 */ 96 void downgrade_write(struct rw_semaphore *sem) 97 { 98 /* 99 * lockdep: a downgraded write will live on as a write 100 * dependency. 101 */ 102 __downgrade_write(sem); 103 } 104 105 EXPORT_SYMBOL(downgrade_write); 106 107 #ifdef CONFIG_DEBUG_LOCK_ALLOC 108 109 void down_read_nested(struct rw_semaphore *sem, int subclass) 110 { 111 might_sleep(); 112 rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_); 113 114 LOCK_CONTENDED(sem, __down_read_trylock, __down_read); 115 } 116 117 EXPORT_SYMBOL(down_read_nested); 118 119 void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest) 120 { 121 might_sleep(); 122 rwsem_acquire_nest(&sem->dep_map, 0, 0, nest, _RET_IP_); 123 124 LOCK_CONTENDED(sem, __down_write_trylock, __down_write); 125 } 126 127 EXPORT_SYMBOL(_down_write_nest_lock); 128 129 void down_read_non_owner(struct rw_semaphore *sem) 130 { 131 might_sleep(); 132 133 __down_read(sem); 134 } 135 136 EXPORT_SYMBOL(down_read_non_owner); 137 138 void down_write_nested(struct rw_semaphore *sem, int subclass) 139 { 140 might_sleep(); 141 rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_); 142 143 LOCK_CONTENDED(sem, __down_write_trylock, __down_write); 144 } 145 146 EXPORT_SYMBOL(down_write_nested); 147 148 void up_read_non_owner(struct rw_semaphore *sem) 149 { 150 __up_read(sem); 151 } 152 153 EXPORT_SYMBOL(up_read_non_owner); 154 155 #endif 156 157 158