diff options
author | Al Viro <viro@ZenIV.linux.org.uk> | 2012-10-20 15:52:23 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-24 05:16:45 +0300 |
commit | 3185bd26188223195dc2e659a3d00219cad71a0f (patch) | |
tree | 1363b0619f9e416b308aee3c804fab13e6efa72c /arch/alpha/kernel/osf_sys.c | |
parent | 3d0ceac129f3ea0b125289055a3aa7519d38df77 (diff) | |
download | talos-op-linux-3185bd26188223195dc2e659a3d00219cad71a0f.tar.gz talos-op-linux-3185bd26188223195dc2e659a3d00219cad71a0f.zip |
alpha: separate thread-synchronous flags
... and fix the race in updating unaligned control ones
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/alpha/kernel/osf_sys.c')
-rw-r--r-- | arch/alpha/kernel/osf_sys.c | 25 |
1 files changed, 10 insertions, 15 deletions
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 9eb090582cf1..1e6956a90608 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -793,8 +793,7 @@ SYSCALL_DEFINE5(osf_getsysinfo, unsigned long, op, void __user *, buffer, case GSI_UACPROC: if (nbytes < sizeof(unsigned int)) return -EINVAL; - w = (current_thread_info()->flags >> ALPHA_UAC_SHIFT) & - UAC_BITMASK; + w = current_thread_info()->status & UAC_BITMASK; if (put_user(w, (unsigned int __user *)buffer)) return -EFAULT; return 1; @@ -904,24 +903,20 @@ SYSCALL_DEFINE5(osf_setsysinfo, unsigned long, op, void __user *, buffer, break; case SSI_NVPAIRS: { - unsigned long v, w, i; - unsigned int old, new; + unsigned __user *p = buffer; + unsigned i; - for (i = 0; i < nbytes; ++i) { + for (i = 0, p = buffer; i < nbytes; ++i, p += 2) { + unsigned v, w, status; - if (get_user(v, 2*i + (unsigned int __user *)buffer)) - return -EFAULT; - if (get_user(w, 2*i + 1 + (unsigned int __user *)buffer)) + if (get_user(v, p) || get_user(w, p + 1)) return -EFAULT; switch (v) { case SSIN_UACPROC: - again: - old = current_thread_info()->flags; - new = old & ~(UAC_BITMASK << ALPHA_UAC_SHIFT); - new = new | (w & UAC_BITMASK) << ALPHA_UAC_SHIFT; - if (cmpxchg(¤t_thread_info()->flags, - old, new) != old) - goto again; + w &= UAC_BITMASK; + status = current_thread_info()->status; + status = (status & ~UAC_BITMASK) | w; + current_thread_info()->status = status; break; default: |