1/* 2 * Copyright (2004) Linus Torvalds 3 * 4 * Author: Zwane Mwaikambo <zwane@fsmlabs.com> 5 */ 6 7#include <linux/config.h> 8#include <linux/linkage.h> 9#include <linux/preempt.h> 10#include <linux/spinlock.h> 11#include <linux/interrupt.h> 12#include <linux/module.h> 13 14int __lockfunc _spin_trylock(spinlock_t *lock) 15{ 16 preempt_disable(); 17 if (_raw_spin_trylock(lock)) 18 return 1; 19 20 preempt_enable(); 21 return 0; 22} 23EXPORT_SYMBOL(_spin_trylock); 24 25int __lockfunc _write_trylock(rwlock_t *lock) 26{ 27 preempt_disable(); 28 if (_raw_write_trylock(lock)) 29 return 1; 30 31 preempt_enable(); 32 return 0; 33} 34EXPORT_SYMBOL(_write_trylock); 35 36#ifdef CONFIG_PREEMPT 37/* 38 * This could be a long-held lock. If another CPU holds it for a long time, 39 * and that CPU is not asked to reschedule then *this* CPU will spin on the 40 * lock for a long time, even if *this* CPU is asked to reschedule. 41 * 42 * So what we do here, in the slow (contended) path is to spin on the lock by 43 * hand while permitting preemption. 44 * 45 * Called inside preempt_disable(). 46 */ 47static inline void __preempt_spin_lock(spinlock_t *lock) 48{ 49 if (preempt_count() > 1) { 50 _raw_spin_lock(lock); 51 return; 52 } 53 54 do { 55 preempt_enable(); 56 while (spin_is_locked(lock)) 57 cpu_relax(); 58 preempt_disable(); 59 } while (!_raw_spin_trylock(lock)); 60} 61 62void __lockfunc _spin_lock(spinlock_t *lock) 63{ 64 preempt_disable(); 65 if (unlikely(!_raw_spin_trylock(lock))) 66 __preempt_spin_lock(lock); 67} 68 69static inline void __preempt_write_lock(rwlock_t *lock) 70{ 71 if (preempt_count() > 1) { 72 _raw_write_lock(lock); 73 return; 74 } 75 76 do { 77 preempt_enable(); 78 while (rwlock_is_locked(lock)) 79 cpu_relax(); 80 preempt_disable(); 81 } while (!_raw_write_trylock(lock)); 82} 83 84void __lockfunc _write_lock(rwlock_t *lock) 85{ 86 preempt_disable(); 87 if (unlikely(!_raw_write_trylock(lock))) 88 __preempt_write_lock(lock); 89} 90#else 91void __lockfunc _spin_lock(spinlock_t *lock) 92{ 93 preempt_disable(); 94 _raw_spin_lock(lock); 95} 96 97void __lockfunc _write_lock(rwlock_t *lock) 98{ 99 preempt_disable(); 100 _raw_write_lock(lock); 101} 102#endif 103EXPORT_SYMBOL(_spin_lock); 104EXPORT_SYMBOL(_write_lock); 105 106void __lockfunc _read_lock(rwlock_t *lock) 107{ 108 preempt_disable(); 109 _raw_read_lock(lock); 110} 111EXPORT_SYMBOL(_read_lock); 112 113void __lockfunc _spin_unlock(spinlock_t *lock) 114{ 115 _raw_spin_unlock(lock); 116 preempt_enable(); 117} 118EXPORT_SYMBOL(_spin_unlock); 119 120void __lockfunc _write_unlock(rwlock_t *lock) 121{ 122 _raw_write_unlock(lock); 123 preempt_enable(); 124} 125EXPORT_SYMBOL(_write_unlock); 126 127void __lockfunc _read_unlock(rwlock_t *lock) 128{ 129 _raw_read_unlock(lock); 130 preempt_enable(); 131} 132EXPORT_SYMBOL(_read_unlock); 133 134unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock) 135{ 136 unsigned long flags; 137 138 local_irq_save(flags); 139 preempt_disable(); 140 _raw_spin_lock_flags(lock, flags); 141 return flags; 142} 143EXPORT_SYMBOL(_spin_lock_irqsave); 144 145void __lockfunc _spin_lock_irq(spinlock_t *lock) 146{ 147 local_irq_disable(); 148 preempt_disable(); 149 _raw_spin_lock(lock); 150} 151EXPORT_SYMBOL(_spin_lock_irq); 152 153void __lockfunc _spin_lock_bh(spinlock_t *lock) 154{ 155 local_bh_disable(); 156 preempt_disable(); 157 _raw_spin_lock(lock); 158} 159EXPORT_SYMBOL(_spin_lock_bh); 160 161unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock) 162{ 163 unsigned long flags; 164 165 local_irq_save(flags); 166 preempt_disable(); 167 _raw_read_lock(lock); 168 return flags; 169} 170EXPORT_SYMBOL(_read_lock_irqsave); 171 172void __lockfunc _read_lock_irq(rwlock_t *lock) 173{ 174 local_irq_disable(); 175 preempt_disable(); 176 _raw_read_lock(lock); 177} 178EXPORT_SYMBOL(_read_lock_irq); 179 180void __lockfunc _read_lock_bh(rwlock_t *lock) 181{ 182 local_bh_disable(); 183 preempt_disable(); 184 _raw_read_lock(lock); 185} 186EXPORT_SYMBOL(_read_lock_bh); 187 188unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock) 189{ 190 unsigned long flags; 191 192 local_irq_save(flags); 193 preempt_disable(); 194 _raw_write_lock(lock); 195 return flags; 196} 197EXPORT_SYMBOL(_write_lock_irqsave); 198 199void __lockfunc _write_lock_irq(rwlock_t *lock) 200{ 201 local_irq_disable(); 202 preempt_disable(); 203 _raw_write_lock(lock); 204} 205EXPORT_SYMBOL(_write_lock_irq); 206 207void __lockfunc _write_lock_bh(rwlock_t *lock) 208{ 209 local_bh_disable(); 210 preempt_disable(); 211 _raw_write_lock(lock); 212} 213EXPORT_SYMBOL(_write_lock_bh); 214 215void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) 216{ 217 _raw_spin_unlock(lock); 218 local_irq_restore(flags); 219 preempt_enable(); 220} 221EXPORT_SYMBOL(_spin_unlock_irqrestore); 222 223void __lockfunc _spin_unlock_irq(spinlock_t *lock) 224{ 225 _raw_spin_unlock(lock); 226 local_irq_enable(); 227 preempt_enable(); 228} 229EXPORT_SYMBOL(_spin_unlock_irq); 230 231void __lockfunc _spin_unlock_bh(spinlock_t *lock) 232{ 233 _raw_spin_unlock(lock); 234 preempt_enable(); 235 local_bh_enable(); 236} 237EXPORT_SYMBOL(_spin_unlock_bh); 238 239void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) 240{ 241 _raw_read_unlock(lock); 242 local_irq_restore(flags); 243 preempt_enable(); 244} 245EXPORT_SYMBOL(_read_unlock_irqrestore); 246 247void __lockfunc _read_unlock_irq(rwlock_t *lock) 248{ 249 _raw_read_unlock(lock); 250 local_irq_enable(); 251 preempt_enable(); 252} 253EXPORT_SYMBOL(_read_unlock_irq); 254 255void __lockfunc _read_unlock_bh(rwlock_t *lock) 256{ 257 _raw_read_unlock(lock); 258 preempt_enable(); 259 local_bh_enable(); 260} 261EXPORT_SYMBOL(_read_unlock_bh); 262 263void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) 264{ 265 _raw_write_unlock(lock); 266 local_irq_restore(flags); 267 preempt_enable(); 268} 269EXPORT_SYMBOL(_write_unlock_irqrestore); 270 271void __lockfunc _write_unlock_irq(rwlock_t *lock) 272{ 273 _raw_write_unlock(lock); 274 local_irq_enable(); 275 preempt_enable(); 276} 277EXPORT_SYMBOL(_write_unlock_irq); 278 279void __lockfunc _write_unlock_bh(rwlock_t *lock) 280{ 281 _raw_write_unlock(lock); 282 preempt_enable(); 283 local_bh_enable(); 284} 285EXPORT_SYMBOL(_write_unlock_bh); 286 287int __lockfunc _spin_trylock_bh(spinlock_t *lock) 288{ 289 local_bh_disable(); 290 preempt_disable(); 291 if (_raw_spin_trylock(lock)) 292 return 1; 293 294 preempt_enable(); 295 local_bh_enable(); 296 return 0; 297} 298EXPORT_SYMBOL(_spin_trylock_bh); 299 300int in_lock_functions(unsigned long addr) 301{ 302 /* Linker adds these: start and end of __lockfunc functions */ 303 extern char __lock_text_start[], __lock_text_end[]; 304 305 return addr >= (unsigned long)__lock_text_start 306 && addr < (unsigned long)__lock_text_end; 307} 308EXPORT_SYMBOL(in_lock_functions); 309

