diff options
| author | Hirokazu Takata <takata@linux-m32r.org> | 2004-10-18 09:05:18 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-10-18 09:05:18 -0700 |
| commit | d37fcff52a9f98abcad1c7d671fe4b49bd0c726a (patch) | |
| tree | 9d077fcef1a0a361b83987ac60c08bbb0058f8c0 /arch/m32r/kernel/sys_m32r.c | |
| parent | [PATCH] m32r: SIO driver (diff) | |
| download | history-d37fcff52a9f98abcad1c7d671fe4b49bd0c726a.tar.gz history-d37fcff52a9f98abcad1c7d671fe4b49bd0c726a.zip | |
[PATCH] m32r: fix sys_tas system call for m32r
This patch fixes a sys_tas system call for m32r.
- This patch fixes an Oops at sys_tas() in case CONFIG_SMP && CONFIG_PREEMPT.
> Unable to handle kernel paging request at virtual address XXXXXXXX
It is because a page fault happens at the spin_locked region in sys_tas()
and in_atomic() checks preempt_count, but spin_lock() already counts up
the preemt_count.
arch/m32r/kernel/sys_m32r.c:
32 /*
33 * sys_tas() - test-and-set
34 * linuxthreads testing version
35 */
36 #ifndef CONFIG_SMP
37 asmlinkage int sys_tas(int *addr)
38 {
39 int oldval;
40 unsigned long flags;
41
42 if (!access_ok(VERIFY_WRITE, addr, sizeof (int)))
43 return -EFAULT;
44 local_irq_save(flags);
45 oldval = *addr;
46 *addr = 1;
47 local_irq_restore(flags);
48 return oldval;
49 }
50 #else /* CONFIG_SMP */
51 #include <linux/spinlock.h>
52
53 static spinlock_t tas_lock = SPIN_LOCK_UNLOCKED;
54
55 asmlinkage int sys_tas(int *addr)
56 {
57 int oldval;
58
59 if (!access_ok(VERIFY_WRITE, addr, sizeof (int)))
60 return -EFAULT;
61
62 spin_lock(&tas_lock);
63 oldval = *addr;
/* <<< ATTENTION >>>
* A page fault may happen here, because "addr" points an
* user-space area.
*/
64 *addr = 1;
65 spin_unlock(&tas_lock);
66
67 return oldval;
68 }
69 #endif /* CONFIG_SMP */
arch/mm/fault.c:
137 /*
138 * If we're in an interrupt or have no user context or are runni
ng in an
139 * atomic region then we must not take the fault..
140 */
141 if (in_atomic() || !mm)
142 goto bad_area_nosemaphore;
- sys_tas() is used for user-level mutual exclusion for the m32r,
which is prepared to implement a linuxthreads library.
The above problem may be happened in a program, which uses
pthread_mutex_lock(), calls sys_tas().
The current m32r instruction set has no user-level locking
functions for mutual exclusion.
# I hope it will be fixed in the future...
- This patch fixes the problem by using _raw_spin_lock() instead of
spin_lock(). spin_lock() increments up preemt_count, on the contrary,
_raw_sping_lock() does not.
# I think this fix is just a temporary work around, and
# it is preferable to be rewrite to make it simpler by using
# asm() function or something...
* arch/m32r/kernel/sys_m32r.c:
- Fix sys_tas() for CONFIG_SMP && CONFIG_PREEMPT.
Signed-off-by: Hayato Fujiwara <fujiwara@linux-m32r.org>
Signed-off-by: Hirokazu Takata <takata@linux-m32r.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to '')
| -rw-r--r-- | arch/m32r/kernel/sys_m32r.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c index f34fa19ac1..435619e436 100644 --- a/arch/m32r/kernel/sys_m32r.c +++ b/arch/m32r/kernel/sys_m32r.c @@ -57,10 +57,10 @@ asmlinkage int sys_tas(int *addr) if (!access_ok(VERIFY_WRITE, addr, sizeof (int))) return -EFAULT; - spin_lock(&tas_lock); + _raw_spin_lock(&tas_lock); oldval = *addr; *addr = 1; - spin_unlock(&tas_lock); + _raw_spin_unlock(&tas_lock); return oldval; } |
