summaryrefslogtreecommitdiffstats
path: root/arch/mips64/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-10-19 21:42:00 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-10-19 21:42:00 +0000
commit794d6411d976253c1761e3dcc0008bd63f79dc99 (patch)
treecf9bdbd07ac3ed6e0d8a875d869cc2ff0f8f34f1 /arch/mips64/kernel
parent69ec55a8553c83add3eafe0e2bf0305f2219ca6a (diff)
Fix sysmips32(MIPS_ATOMIC_SET, ...). In case of a page fault on SMP
this might freeze the entire machine which killed my work several times ...
Diffstat (limited to 'arch/mips64/kernel')
-rw-r--r--arch/mips64/kernel/syscall.c44
1 files changed, 35 insertions, 9 deletions
diff --git a/arch/mips64/kernel/syscall.c b/arch/mips64/kernel/syscall.c
index a69558792..8b36b6e5e 100644
--- a/arch/mips64/kernel/syscall.c
+++ b/arch/mips64/kernel/syscall.c
@@ -31,6 +31,8 @@
#include <asm/sysmips.h>
#include <asm/uaccess.h>
+extern asmlinkage void syscall_trace(void);
+
asmlinkage int sys_pipe(abi64_no_regargs, struct pt_regs regs)
{
int fd[2];
@@ -131,7 +133,7 @@ sys_sysmips(int cmd, long arg1, int arg2, int arg3)
{
int *p;
char *name;
- int flags, tmp, len, errno;
+ int tmp, len, errno;
switch(cmd) {
case SETNAME: {
@@ -154,8 +156,6 @@ sys_sysmips(int cmd, long arg1, int arg2, int arg3)
}
case MIPS_ATOMIC_SET: {
- /* This is broken in case of page faults and SMP ...
- Risc/OS faults after maximum 20 tries with EAGAIN. */
unsigned int tmp;
p = (int *) arg1;
@@ -163,15 +163,41 @@ sys_sysmips(int cmd, long arg1, int arg2, int arg3)
if (errno)
return errno;
errno = 0;
- save_and_cli(flags);
- errno |= __get_user(tmp, p);
- errno |= __put_user(arg2, p);
- restore_flags(flags);
+
+ __asm__(".set\tpush\t\t\t# sysmips(MIPS_ATOMIC, ...)\n\t"
+ ".set\tnoreorder\n\t"
+ ".set\tnoat\n\t"
+ "1:\tll\t%0, %4\n\t"
+ "2:\tmove\t$1, %3\n\t"
+ "3:\tsc\t$1, %1\n\t"
+ "beqzl\t$1, 2b\n\t"
+ "4:\t ll\t%0, %4\n\t"
+ ".set\tpop\n\t"
+ ".section\t.fixup,\"ax\"\n"
+ "5:\tli\t%2, 1\t\t\t# error\n\t"
+ ".previous\n\t"
+ ".section\t__ex_table,\"a\"\n\t"
+ ".dword\t1b, 5b\n\t"
+ ".dword\t3b, 5b\n\t"
+ ".dword\t4b, 5b\n\t"
+ ".previous\n\t"
+ : "=&r" (tmp), "=o" (* (u32 *) p), "=r" (errno)
+ : "r" (arg2), "o" (* (u32 *) p), "2" (errno)
+ : "$1");
if (errno)
- return tmp;
+ return -EFAULT;
+
+ /* We're skipping error handling etc. */
+ if (current->ptrace & PT_TRACESYS)
+ syscall_trace();
- return tmp; /* This is broken ... */
+ __asm__ __volatile__(
+ "move\t$29, %0\n\t"
+ "j\tret_from_sys_call"
+ : /* No outputs */
+ : "r" (&cmd));
+ /* Unreached */
}
case MIPS_FIXADE: