Commit 3185bd26 authored by Al Viro's avatar Al Viro Committed by Linus Torvalds

alpha: separate thread-synchronous flags

... and fix the race in updating unaligned control ones
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 3d0ceac1
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/types.h> #include <asm/types.h>
#include <asm/hwrpb.h> #include <asm/hwrpb.h>
#include <asm/sysinfo.h>
#endif #endif
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
...@@ -21,6 +22,7 @@ struct thread_info { ...@@ -21,6 +22,7 @@ struct thread_info {
mm_segment_t addr_limit; /* thread address space */ mm_segment_t addr_limit; /* thread address space */
unsigned cpu; /* current CPU */ unsigned cpu; /* current CPU */
int preempt_count; /* 0 => preemptable, <0 => BUG */ int preempt_count; /* 0 => preemptable, <0 => BUG */
unsigned int status; /* thread-synchronous flags */
int bpt_nsaved; int bpt_nsaved;
unsigned long bpt_addr[2]; /* breakpoint handling */ unsigned long bpt_addr[2]; /* breakpoint handling */
...@@ -63,8 +65,6 @@ register struct thread_info *__current_thread_info __asm__("$8"); ...@@ -63,8 +65,6 @@ register struct thread_info *__current_thread_info __asm__("$8");
* - these are process state flags and used from assembly * - these are process state flags and used from assembly
* - pending work-to-be-done flags come first and must be assigned to be * - pending work-to-be-done flags come first and must be assigned to be
* within bits 0 to 7 to fit in and immediate operand. * within bits 0 to 7 to fit in and immediate operand.
* - ALPHA_UAC_SHIFT below must be kept consistent with the unaligned
* control flags.
* *
* TIF_SYSCALL_TRACE is known to be 0 via blbs. * TIF_SYSCALL_TRACE is known to be 0 via blbs.
*/ */
...@@ -72,18 +72,12 @@ register struct thread_info *__current_thread_info __asm__("$8"); ...@@ -72,18 +72,12 @@ register struct thread_info *__current_thread_info __asm__("$8");
#define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ #define TIF_NOTIFY_RESUME 1 /* callback before returning to user */
#define TIF_SIGPENDING 2 /* signal pending */ #define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_POLLING_NRFLAG 8 /* poll_idle is polling NEED_RESCHED */
#define TIF_DIE_IF_KERNEL 9 /* dik recursion lock */ #define TIF_DIE_IF_KERNEL 9 /* dik recursion lock */
#define TIF_UAC_NOPRINT 10 /* ! Preserve sequence of following */
#define TIF_UAC_NOFIX 11 /* ! flags as they match */
#define TIF_UAC_SIGBUS 12 /* ! userspace part of 'osf_sysinfo' */
#define TIF_MEMDIE 13 /* is terminating due to OOM killer */ #define TIF_MEMDIE 13 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 14 /* restore signal mask in do_signal */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING) #define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
/* Work to do on interrupt/exception return. */ /* Work to do on interrupt/exception return. */
...@@ -94,29 +88,63 @@ register struct thread_info *__current_thread_info __asm__("$8"); ...@@ -94,29 +88,63 @@ register struct thread_info *__current_thread_info __asm__("$8");
#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK \ #define _TIF_ALLWORK_MASK (_TIF_WORK_MASK \
| _TIF_SYSCALL_TRACE) | _TIF_SYSCALL_TRACE)
#define ALPHA_UAC_SHIFT TIF_UAC_NOPRINT #define TS_UAC_NOPRINT 0x0001 /* ! Preserve the following three */
#define ALPHA_UAC_MASK (1 << TIF_UAC_NOPRINT | 1 << TIF_UAC_NOFIX | \ #define TS_UAC_NOFIX 0x0002 /* ! flags as they match */
1 << TIF_UAC_SIGBUS) #define TS_UAC_SIGBUS 0x0004 /* ! userspace part of 'osf_sysinfo' */
#define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal() */
#define TS_POLLING 0x0010 /* idle task polling need_resched,
skip sending interrupt */
#define SET_UNALIGN_CTL(task,value) ({ \ #define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
task_thread_info(task)->flags = ((task_thread_info(task)->flags & \
~ALPHA_UAC_MASK) \ #ifndef __ASSEMBLY__
| (((value) << ALPHA_UAC_SHIFT) & (1<<TIF_UAC_NOPRINT))\ #define HAVE_SET_RESTORE_SIGMASK 1
| (((value) << (ALPHA_UAC_SHIFT + 1)) & (1<<TIF_UAC_SIGBUS)) \ static inline void set_restore_sigmask(void)
| (((value) << (ALPHA_UAC_SHIFT - 1)) & (1<<TIF_UAC_NOFIX)));\ {
struct thread_info *ti = current_thread_info();
ti->status |= TS_RESTORE_SIGMASK;
WARN_ON(!test_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags));
}
static inline void clear_restore_sigmask(void)
{
current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
}
static inline bool test_restore_sigmask(void)
{
return current_thread_info()->status & TS_RESTORE_SIGMASK;
}
static inline bool test_and_clear_restore_sigmask(void)
{
struct thread_info *ti = current_thread_info();
if (!(ti->status & TS_RESTORE_SIGMASK))
return false;
ti->status &= ~TS_RESTORE_SIGMASK;
return true;
}
#endif
#define SET_UNALIGN_CTL(task,value) ({ \
__u32 status = task_thread_info(task)->status & ~UAC_BITMASK; \
if (value & PR_UNALIGN_NOPRINT) \
status |= TS_UAC_NOPRINT; \
if (value & PR_UNALIGN_SIGBUS) \
status |= TS_UAC_SIGBUS; \
if (value & 4) /* alpha-specific */ \
status |= TS_UAC_NOFIX; \
task_thread_info(task)->status = status; \
0; }) 0; })
#define GET_UNALIGN_CTL(task,value) ({ \ #define GET_UNALIGN_CTL(task,value) ({ \
put_user((task_thread_info(task)->flags & (1 << TIF_UAC_NOPRINT))\ __u32 status = task_thread_info(task)->status & ~UAC_BITMASK; \
>> ALPHA_UAC_SHIFT \ __u32 res = 0; \
| (task_thread_info(task)->flags & (1 << TIF_UAC_SIGBUS))\ if (status & TS_UAC_NOPRINT) \
>> (ALPHA_UAC_SHIFT + 1) \ res |= PR_UNALIGN_NOPRINT; \
| (task_thread_info(task)->flags & (1 << TIF_UAC_NOFIX))\ if (status & TS_UAC_SIGBUS) \
>> (ALPHA_UAC_SHIFT - 1), \ res |= PR_UNALIGN_SIGBUS; \
(int __user *)(value)); \ if (status & TS_UAC_NOFIX) \
res |= 4; \
put_user(res, (int __user *)(value)); \
}) })
#define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG)
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _ALPHA_THREAD_INFO_H */ #endif /* _ALPHA_THREAD_INFO_H */
...@@ -793,8 +793,7 @@ SYSCALL_DEFINE5(osf_getsysinfo, unsigned long, op, void __user *, buffer, ...@@ -793,8 +793,7 @@ SYSCALL_DEFINE5(osf_getsysinfo, unsigned long, op, void __user *, buffer,
case GSI_UACPROC: case GSI_UACPROC:
if (nbytes < sizeof(unsigned int)) if (nbytes < sizeof(unsigned int))
return -EINVAL; return -EINVAL;
w = (current_thread_info()->flags >> ALPHA_UAC_SHIFT) & w = current_thread_info()->status & UAC_BITMASK;
UAC_BITMASK;
if (put_user(w, (unsigned int __user *)buffer)) if (put_user(w, (unsigned int __user *)buffer))
return -EFAULT; return -EFAULT;
return 1; return 1;
...@@ -904,24 +903,20 @@ SYSCALL_DEFINE5(osf_setsysinfo, unsigned long, op, void __user *, buffer, ...@@ -904,24 +903,20 @@ SYSCALL_DEFINE5(osf_setsysinfo, unsigned long, op, void __user *, buffer,
break; break;
case SSI_NVPAIRS: { case SSI_NVPAIRS: {
unsigned long v, w, i; unsigned __user *p = buffer;
unsigned int old, new; 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)) if (get_user(v, p) || get_user(w, p + 1))
return -EFAULT;
if (get_user(w, 2*i + 1 + (unsigned int __user *)buffer))
return -EFAULT; return -EFAULT;
switch (v) { switch (v) {
case SSIN_UACPROC: case SSIN_UACPROC:
again: w &= UAC_BITMASK;
old = current_thread_info()->flags; status = current_thread_info()->status;
new = old & ~(UAC_BITMASK << ALPHA_UAC_SHIFT); status = (status & ~UAC_BITMASK) | w;
new = new | (w & UAC_BITMASK) << ALPHA_UAC_SHIFT; current_thread_info()->status = status;
if (cmpxchg(&current_thread_info()->flags,
old, new) != old)
goto again;
break; break;
default: default:
......
...@@ -49,7 +49,7 @@ EXPORT_SYMBOL(pm_power_off); ...@@ -49,7 +49,7 @@ EXPORT_SYMBOL(pm_power_off);
void void
cpu_idle(void) cpu_idle(void)
{ {
set_thread_flag(TIF_POLLING_NRFLAG); current_thread_info()->status |= TS_POLLING;
while (1) { while (1) {
/* FIXME -- EV6 and LCA45 know how to power down /* FIXME -- EV6 and LCA45 know how to power down
......
...@@ -780,17 +780,17 @@ do_entUnaUser(void __user * va, unsigned long opcode, ...@@ -780,17 +780,17 @@ do_entUnaUser(void __user * va, unsigned long opcode,
/* Check the UAC bits to decide what the user wants us to do /* Check the UAC bits to decide what the user wants us to do
with the unaliged access. */ with the unaliged access. */
if (!test_thread_flag (TIF_UAC_NOPRINT)) { if (!(current_thread_info()->status & TS_UAC_NOPRINT)) {
if (__ratelimit(&ratelimit)) { if (__ratelimit(&ratelimit)) {
printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n", printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
current->comm, task_pid_nr(current), current->comm, task_pid_nr(current),
regs->pc - 4, va, opcode, reg); regs->pc - 4, va, opcode, reg);
} }
} }
if (test_thread_flag (TIF_UAC_SIGBUS)) if ((current_thread_info()->status & TS_UAC_SIGBUS))
goto give_sigbus; goto give_sigbus;
/* Not sure why you'd want to use this, but... */ /* Not sure why you'd want to use this, but... */
if (test_thread_flag (TIF_UAC_NOFIX)) if ((current_thread_info()->status & TS_UAC_NOFIX))
return; return;
/* Don't bother reading ds in the access check since we already /* Don't bother reading ds in the access check since we already
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment