diff options
| author | Al Viro <viro@ZenIV.linux.org.uk> | 2012-10-20 10:52:23 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-23 22:16:45 -0400 |
| commit | 3185bd26188223195dc2e659a3d00219cad71a0f (patch) | |
| tree | 1363b0619f9e416b308aee3c804fab13e6efa72c | |
| parent | 3d0ceac129f3ea0b125289055a3aa7519d38df77 (diff) | |
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>
| -rw-r--r-- | arch/alpha/include/asm/thread_info.h | 80 | ||||
| -rw-r--r-- | arch/alpha/kernel/osf_sys.c | 25 | ||||
| -rw-r--r-- | arch/alpha/kernel/process.c | 2 | ||||
| -rw-r--r-- | arch/alpha/kernel/traps.c | 6 |
4 files changed, 68 insertions, 45 deletions
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h index 4554ecbff7c6..1f8c72959fb6 100644 --- a/arch/alpha/include/asm/thread_info.h +++ b/arch/alpha/include/asm/thread_info.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <asm/processor.h> | 7 | #include <asm/processor.h> |
| 8 | #include <asm/types.h> | 8 | #include <asm/types.h> |
| 9 | #include <asm/hwrpb.h> | 9 | #include <asm/hwrpb.h> |
| 10 | #include <asm/sysinfo.h> | ||
| 10 | #endif | 11 | #endif |
| 11 | 12 | ||
| 12 | #ifndef __ASSEMBLY__ | 13 | #ifndef __ASSEMBLY__ |
| @@ -21,6 +22,7 @@ struct thread_info { | |||
| 21 | mm_segment_t addr_limit; /* thread address space */ | 22 | mm_segment_t addr_limit; /* thread address space */ |
| 22 | unsigned cpu; /* current CPU */ | 23 | unsigned cpu; /* current CPU */ |
| 23 | int preempt_count; /* 0 => preemptable, <0 => BUG */ | 24 | int preempt_count; /* 0 => preemptable, <0 => BUG */ |
| 25 | unsigned int status; /* thread-synchronous flags */ | ||
| 24 | 26 | ||
| 25 | int bpt_nsaved; | 27 | int bpt_nsaved; |
| 26 | unsigned long bpt_addr[2]; /* breakpoint handling */ | 28 | unsigned long bpt_addr[2]; /* breakpoint handling */ |
| @@ -63,8 +65,6 @@ register struct thread_info *__current_thread_info __asm__("$8"); | |||
| 63 | * - these are process state flags and used from assembly | 65 | * - these are process state flags and used from assembly |
| 64 | * - pending work-to-be-done flags come first and must be assigned to be | 66 | * - pending work-to-be-done flags come first and must be assigned to be |
| 65 | * within bits 0 to 7 to fit in and immediate operand. | 67 | * within bits 0 to 7 to fit in and immediate operand. |
| 66 | * - ALPHA_UAC_SHIFT below must be kept consistent with the unaligned | ||
| 67 | * control flags. | ||
| 68 | * | 68 | * |
| 69 | * TIF_SYSCALL_TRACE is known to be 0 via blbs. | 69 | * TIF_SYSCALL_TRACE is known to be 0 via blbs. |
| 70 | */ | 70 | */ |
| @@ -72,18 +72,12 @@ register struct thread_info *__current_thread_info __asm__("$8"); | |||
| 72 | #define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ | 72 | #define TIF_NOTIFY_RESUME 1 /* callback before returning to user */ |
| 73 | #define TIF_SIGPENDING 2 /* signal pending */ | 73 | #define TIF_SIGPENDING 2 /* signal pending */ |
| 74 | #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ | 74 | #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ |
| 75 | #define TIF_POLLING_NRFLAG 8 /* poll_idle is polling NEED_RESCHED */ | ||
| 76 | #define TIF_DIE_IF_KERNEL 9 /* dik recursion lock */ | 75 | #define TIF_DIE_IF_KERNEL 9 /* dik recursion lock */ |
| 77 | #define TIF_UAC_NOPRINT 10 /* ! Preserve sequence of following */ | ||
| 78 | #define TIF_UAC_NOFIX 11 /* ! flags as they match */ | ||
| 79 | #define TIF_UAC_SIGBUS 12 /* ! userspace part of 'osf_sysinfo' */ | ||
| 80 | #define TIF_MEMDIE 13 /* is terminating due to OOM killer */ | 76 | #define TIF_MEMDIE 13 /* is terminating due to OOM killer */ |
| 81 | #define TIF_RESTORE_SIGMASK 14 /* restore signal mask in do_signal */ | ||
| 82 | 77 | ||
| 83 | #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) | 78 | #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) |
| 84 | #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) | 79 | #define _TIF_SIGPENDING (1<<TIF_SIGPENDING) |
| 85 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) | 80 | #define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED) |
| 86 | #define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG) | ||
| 87 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) | 81 | #define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME) |
| 88 | 82 | ||
| 89 | /* Work to do on interrupt/exception return. */ | 83 | /* Work to do on interrupt/exception return. */ |
| @@ -94,29 +88,63 @@ register struct thread_info *__current_thread_info __asm__("$8"); | |||
| 94 | #define _TIF_ALLWORK_MASK (_TIF_WORK_MASK \ | 88 | #define _TIF_ALLWORK_MASK (_TIF_WORK_MASK \ |
| 95 | | _TIF_SYSCALL_TRACE) | 89 | | _TIF_SYSCALL_TRACE) |
| 96 | 90 | ||
| 97 | #define ALPHA_UAC_SHIFT TIF_UAC_NOPRINT | 91 | #define TS_UAC_NOPRINT 0x0001 /* ! Preserve the following three */ |
| 98 | #define ALPHA_UAC_MASK (1 << TIF_UAC_NOPRINT | 1 << TIF_UAC_NOFIX | \ | 92 | #define TS_UAC_NOFIX 0x0002 /* ! flags as they match */ |
| 99 | 1 << TIF_UAC_SIGBUS) | 93 | #define TS_UAC_SIGBUS 0x0004 /* ! userspace part of 'osf_sysinfo' */ |
| 94 | #define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal() */ | ||
| 95 | #define TS_POLLING 0x0010 /* idle task polling need_resched, | ||
| 96 | skip sending interrupt */ | ||
| 100 | 97 | ||
| 101 | #define SET_UNALIGN_CTL(task,value) ({ \ | 98 | #define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING) |
| 102 | task_thread_info(task)->flags = ((task_thread_info(task)->flags & \ | 99 | |
| 103 | ~ALPHA_UAC_MASK) \ | 100 | #ifndef __ASSEMBLY__ |
| 104 | | (((value) << ALPHA_UAC_SHIFT) & (1<<TIF_UAC_NOPRINT))\ | 101 | #define HAVE_SET_RESTORE_SIGMASK 1 |
| 105 | | (((value) << (ALPHA_UAC_SHIFT + 1)) & (1<<TIF_UAC_SIGBUS)) \ | 102 | static inline void set_restore_sigmask(void) |
| 106 | | (((value) << (ALPHA_UAC_SHIFT - 1)) & (1<<TIF_UAC_NOFIX)));\ | 103 | { |
| 104 | struct thread_info *ti = current_thread_info(); | ||
| 105 | ti->status |= TS_RESTORE_SIGMASK; | ||
| 106 | WARN_ON(!test_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags)); | ||
| 107 | } | ||
| 108 | static inline void clear_restore_sigmask(void) | ||
| 109 | { | ||
| 110 | current_thread_info()->status &= ~TS_RESTORE_SIGMASK; | ||
| 111 | } | ||
| 112 | static inline bool test_restore_sigmask(void) | ||
| 113 | { | ||
| 114 | return current_thread_info()->status & TS_RESTORE_SIGMASK; | ||
| 115 | } | ||
| 116 | static inline bool test_and_clear_restore_sigmask(void) | ||
| 117 | { | ||
| 118 | struct thread_info *ti = current_thread_info(); | ||
| 119 | if (!(ti->status & TS_RESTORE_SIGMASK)) | ||
| 120 | return false; | ||
| 121 | ti->status &= ~TS_RESTORE_SIGMASK; | ||
| 122 | return true; | ||
| 123 | } | ||
| 124 | #endif | ||
| 125 | |||
| 126 | #define SET_UNALIGN_CTL(task,value) ({ \ | ||
| 127 | __u32 status = task_thread_info(task)->status & ~UAC_BITMASK; \ | ||
| 128 | if (value & PR_UNALIGN_NOPRINT) \ | ||
| 129 | status |= TS_UAC_NOPRINT; \ | ||
| 130 | if (value & PR_UNALIGN_SIGBUS) \ | ||
| 131 | status |= TS_UAC_SIGBUS; \ | ||
| 132 | if (value & 4) /* alpha-specific */ \ | ||
| 133 | status |= TS_UAC_NOFIX; \ | ||
| 134 | task_thread_info(task)->status = status; \ | ||
| 107 | 0; }) | 135 | 0; }) |
| 108 | 136 | ||
| 109 | #define GET_UNALIGN_CTL(task,value) ({ \ | 137 | #define GET_UNALIGN_CTL(task,value) ({ \ |
| 110 | put_user((task_thread_info(task)->flags & (1 << TIF_UAC_NOPRINT))\ | 138 | __u32 status = task_thread_info(task)->status & ~UAC_BITMASK; \ |
| 111 | >> ALPHA_UAC_SHIFT \ | 139 | __u32 res = 0; \ |
| 112 | | (task_thread_info(task)->flags & (1 << TIF_UAC_SIGBUS))\ | 140 | if (status & TS_UAC_NOPRINT) \ |
| 113 | >> (ALPHA_UAC_SHIFT + 1) \ | 141 | res |= PR_UNALIGN_NOPRINT; \ |
| 114 | | (task_thread_info(task)->flags & (1 << TIF_UAC_NOFIX))\ | 142 | if (status & TS_UAC_SIGBUS) \ |
| 115 | >> (ALPHA_UAC_SHIFT - 1), \ | 143 | res |= PR_UNALIGN_SIGBUS; \ |
| 116 | (int __user *)(value)); \ | 144 | if (status & TS_UAC_NOFIX) \ |
| 145 | res |= 4; \ | ||
| 146 | put_user(res, (int __user *)(value)); \ | ||
| 117 | }) | 147 | }) |
| 118 | 148 | ||
| 119 | #define tsk_is_polling(t) test_tsk_thread_flag(t, TIF_POLLING_NRFLAG) | ||
| 120 | |||
| 121 | #endif /* __KERNEL__ */ | 149 | #endif /* __KERNEL__ */ |
| 122 | #endif /* _ALPHA_THREAD_INFO_H */ | 150 | #endif /* _ALPHA_THREAD_INFO_H */ |
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, | |||
| 793 | case GSI_UACPROC: | 793 | case GSI_UACPROC: |
| 794 | if (nbytes < sizeof(unsigned int)) | 794 | if (nbytes < sizeof(unsigned int)) |
| 795 | return -EINVAL; | 795 | return -EINVAL; |
| 796 | w = (current_thread_info()->flags >> ALPHA_UAC_SHIFT) & | 796 | w = current_thread_info()->status & UAC_BITMASK; |
| 797 | UAC_BITMASK; | ||
| 798 | if (put_user(w, (unsigned int __user *)buffer)) | 797 | if (put_user(w, (unsigned int __user *)buffer)) |
| 799 | return -EFAULT; | 798 | return -EFAULT; |
| 800 | return 1; | 799 | return 1; |
| @@ -904,24 +903,20 @@ SYSCALL_DEFINE5(osf_setsysinfo, unsigned long, op, void __user *, buffer, | |||
| 904 | break; | 903 | break; |
| 905 | 904 | ||
| 906 | case SSI_NVPAIRS: { | 905 | case SSI_NVPAIRS: { |
| 907 | unsigned long v, w, i; | 906 | unsigned __user *p = buffer; |
| 908 | unsigned int old, new; | 907 | unsigned i; |
| 909 | 908 | ||
| 910 | for (i = 0; i < nbytes; ++i) { | 909 | for (i = 0, p = buffer; i < nbytes; ++i, p += 2) { |
| 910 | unsigned v, w, status; | ||
| 911 | 911 | ||
| 912 | if (get_user(v, 2*i + (unsigned int __user *)buffer)) | 912 | if (get_user(v, p) || get_user(w, p + 1)) |
| 913 | return -EFAULT; | ||
| 914 | if (get_user(w, 2*i + 1 + (unsigned int __user *)buffer)) | ||
| 915 | return -EFAULT; | 913 | return -EFAULT; |
| 916 | switch (v) { | 914 | switch (v) { |
| 917 | case SSIN_UACPROC: | 915 | case SSIN_UACPROC: |
| 918 | again: | 916 | w &= UAC_BITMASK; |
| 919 | old = current_thread_info()->flags; | 917 | status = current_thread_info()->status; |
| 920 | new = old & ~(UAC_BITMASK << ALPHA_UAC_SHIFT); | 918 | status = (status & ~UAC_BITMASK) | w; |
| 921 | new = new | (w & UAC_BITMASK) << ALPHA_UAC_SHIFT; | 919 | current_thread_info()->status = status; |
| 922 | if (cmpxchg(¤t_thread_info()->flags, | ||
| 923 | old, new) != old) | ||
| 924 | goto again; | ||
| 925 | break; | 920 | break; |
| 926 | 921 | ||
| 927 | default: | 922 | default: |
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 4054e0ffe2b2..51987dcf79b8 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c | |||
| @@ -49,7 +49,7 @@ EXPORT_SYMBOL(pm_power_off); | |||
| 49 | void | 49 | void |
| 50 | cpu_idle(void) | 50 | cpu_idle(void) |
| 51 | { | 51 | { |
| 52 | set_thread_flag(TIF_POLLING_NRFLAG); | 52 | current_thread_info()->status |= TS_POLLING; |
| 53 | 53 | ||
| 54 | while (1) { | 54 | while (1) { |
| 55 | /* FIXME -- EV6 and LCA45 know how to power down | 55 | /* FIXME -- EV6 and LCA45 know how to power down |
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 80d987c0e9aa..272666d006df 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c | |||
| @@ -780,17 +780,17 @@ do_entUnaUser(void __user * va, unsigned long opcode, | |||
| 780 | /* Check the UAC bits to decide what the user wants us to do | 780 | /* Check the UAC bits to decide what the user wants us to do |
| 781 | with the unaliged access. */ | 781 | with the unaliged access. */ |
| 782 | 782 | ||
| 783 | if (!test_thread_flag (TIF_UAC_NOPRINT)) { | 783 | if (!(current_thread_info()->status & TS_UAC_NOPRINT)) { |
| 784 | if (__ratelimit(&ratelimit)) { | 784 | if (__ratelimit(&ratelimit)) { |
| 785 | printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n", | 785 | printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n", |
| 786 | current->comm, task_pid_nr(current), | 786 | current->comm, task_pid_nr(current), |
| 787 | regs->pc - 4, va, opcode, reg); | 787 | regs->pc - 4, va, opcode, reg); |
| 788 | } | 788 | } |
| 789 | } | 789 | } |
| 790 | if (test_thread_flag (TIF_UAC_SIGBUS)) | 790 | if ((current_thread_info()->status & TS_UAC_SIGBUS)) |
| 791 | goto give_sigbus; | 791 | goto give_sigbus; |
| 792 | /* Not sure why you'd want to use this, but... */ | 792 | /* Not sure why you'd want to use this, but... */ |
| 793 | if (test_thread_flag (TIF_UAC_NOFIX)) | 793 | if ((current_thread_info()->status & TS_UAC_NOFIX)) |
| 794 | return; | 794 | return; |
| 795 | 795 | ||
| 796 | /* Don't bother reading ds in the access check since we already | 796 | /* Don't bother reading ds in the access check since we already |
