Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] sparc32 rwlock fix

read_trylock() is broken on sparc32 (doesn't build and didn't work
right, actually). Proposed fix:

- make "writer holds lock" distinguishable from "reader tries to grab
lock"

- have __raw_read_trylock() try to acquire the mutex (in LSB of lock),
terminating spin if we see that there's writer holding it. Then do
the rest as we do in read_lock().

Thanks to Ingo for discussion...

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Al Viro and committed by
Linus Torvalds
7a39f522 6d24c8dc

+50 -2
+3 -1
arch/sparc/kernel/sparc_ksyms.c
··· 87 87 extern void ___clear_bit(void); 88 88 extern void ___change_bit(void); 89 89 extern void ___rw_read_enter(void); 90 + extern void ___rw_read_try(void); 90 91 extern void ___rw_read_exit(void); 91 92 extern void ___rw_write_enter(void); 92 93 ··· 105 104 EXPORT_SYMBOL(sparc_cpu_model); 106 105 EXPORT_SYMBOL(kernel_thread); 107 106 #ifdef CONFIG_SMP 108 - // XXX find what uses (or used) these. 107 + // XXX find what uses (or used) these. AV: see asm/spinlock.h 109 108 EXPORT_SYMBOL(___rw_read_enter); 109 + EXPORT_SYMBOL(___rw_read_try); 110 110 EXPORT_SYMBOL(___rw_read_exit); 111 111 EXPORT_SYMBOL(___rw_write_enter); 112 112 #endif
+20
arch/sparc/lib/locks.S
··· 25 25 ldstub [%g1 + 3], %g2 26 26 b ___rw_read_enter_spin_on_wlock 27 27 ldub [%g1 + 3], %g2 28 + ___rw_read_try_spin_on_wlock: 29 + andcc %g2, 0xff, %g0 30 + be,a ___rw_read_try 31 + ldstub [%g1 + 3], %g2 32 + xnorcc %g2, 0x0, %o0 /* if g2 is ~0, set o0 to 0 and bugger off */ 33 + bne,a ___rw_read_enter_spin_on_wlock 34 + ld [%g1], %g2 35 + retl 36 + mov %g4, %o7 28 37 ___rw_read_exit_spin_on_wlock: 29 38 orcc %g2, 0x0, %g0 30 39 be,a ___rw_read_exit ··· 66 57 ld [%g1], %g2 67 58 sub %g2, 0x1ff, %g2 68 59 st %g2, [%g1] 60 + retl 61 + mov %g4, %o7 62 + 63 + .globl ___rw_read_try 64 + ___rw_read_try: 65 + orcc %g2, 0x0, %g0 66 + bne ___rw_read_try_spin_on_wlock 67 + ld [%g1], %g2 68 + add %g2, 1, %g2 69 + st %g2, [%g1] 70 + set 1, %o1 69 71 retl 70 72 mov %g4, %o7 71 73
+27 -1
include/asm-sparc/spinlock.h
··· 129 129 : /* no outputs */ 130 130 : "r" (lp) 131 131 : "g2", "g4", "memory", "cc"); 132 + *(volatile __u32 *)&lp->lock = ~0U; 132 133 } 133 134 134 135 static inline int __raw_write_trylock(raw_rwlock_t *rw) ··· 145 144 val = rw->lock & ~0xff; 146 145 if (val) 147 146 ((volatile u8*)&rw->lock)[3] = 0; 147 + else 148 + *(volatile u32*)&rw->lock = ~0U; 148 149 } 149 150 150 151 return (val == 0); 151 152 } 152 153 154 + static inline int __read_trylock(raw_rwlock_t *rw) 155 + { 156 + register raw_rwlock_t *lp asm("g1"); 157 + register int res asm("o0"); 158 + lp = rw; 159 + __asm__ __volatile__( 160 + "mov %%o7, %%g4\n\t" 161 + "call ___rw_read_try\n\t" 162 + " ldstub [%%g1 + 3], %%g2\n" 163 + : "=r" (res) 164 + : "r" (lp) 165 + : "g2", "g4", "memory", "cc"); 166 + return res; 167 + } 168 + 169 + #define __raw_read_trylock(lock) \ 170 + ({ unsigned long flags; \ 171 + int res; \ 172 + local_irq_save(flags); \ 173 + res = __read_trylock(lock); \ 174 + local_irq_restore(flags); \ 175 + res; \ 176 + }) 177 + 153 178 #define __raw_write_unlock(rw) do { (rw)->lock = 0; } while(0) 154 179 155 180 #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) 156 - #define __raw_read_trylock(lock) generic__raw_read_trylock(lock) 157 181 158 182 #define _raw_spin_relax(lock) cpu_relax() 159 183 #define _raw_read_relax(lock) cpu_relax()