Merge branch 'parisc-3.15-4' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux

Pull parisc fixes from Helge Deller:
 "There are two patches in here:

  The first patch greatly improves latency and corrects the memory
  ordering in our light-weight atomic locking syscall.

  The second patch ratelimits printing of userspace segfaults in the
  same way as it's done on other platforms.  This fixes a possible DOS
  on parisc since it prevents the syslog to grow too fast.  For example,
  when the debian acl2 package was built on our debian buildd servers,
  this package produced lots of gigabytes in syslog in very short time
  and thus filled our harddisks, which then turned the server nearly
  completely unaccessible and unresponsive"

* 'parisc-3.15-4' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux:
  parisc: Improve LWS-CAS performance
  parisc: ratelimit userspace segfault printing
This commit is contained in:
Linus Torvalds 2014-05-20 14:35:28 +09:00
commit 6ed8bf82fe
4 changed files with 65 additions and 46 deletions

View File

@ -22,6 +22,7 @@ config PARISC
select GENERIC_SMP_IDLE_THREAD
select GENERIC_STRNCPY_FROM_USER
select SYSCTL_ARCH_UNALIGN_ALLOW
select SYSCTL_EXCEPTION_TRACE
select HAVE_MOD_ARCH_SPECIFIC
select VIRT_TO_BUS
select MODULES_USE_ELF_RELA

View File

@ -589,10 +589,13 @@ cas_nocontend:
# endif
/* ENABLE_LWS_DEBUG */
rsm PSW_SM_I, %r0 /* Disable interrupts */
/* COW breaks can cause contention on UP systems */
LDCW 0(%sr2,%r20), %r28 /* Try to acquire the lock */
cmpb,<>,n %r0, %r28, cas_action /* Did we get it? */
cas_wouldblock:
ldo 2(%r0), %r28 /* 2nd case */
ssm PSW_SM_I, %r0
b lws_exit /* Contended... */
ldo -EAGAIN(%r0), %r21 /* Spin in userspace */
@ -619,15 +622,17 @@ cas_action:
stw %r1, 4(%sr2,%r20)
#endif
/* The load and store could fail */
1: ldw 0(%sr3,%r26), %r28
1: ldw,ma 0(%sr3,%r26), %r28
sub,<> %r28, %r25, %r0
2: stw %r24, 0(%sr3,%r26)
2: stw,ma %r24, 0(%sr3,%r26)
/* Free lock */
stw %r20, 0(%sr2,%r20)
stw,ma %r20, 0(%sr2,%r20)
#if ENABLE_LWS_DEBUG
/* Clear thread register indicator */
stw %r0, 4(%sr2,%r20)
#endif
/* Enable interrupts */
ssm PSW_SM_I, %r0
/* Return to userspace, set no error */
b lws_exit
copy %r0, %r21
@ -639,6 +644,7 @@ cas_action:
#if ENABLE_LWS_DEBUG
stw %r0, 4(%sr2,%r20)
#endif
ssm PSW_SM_I, %r0
b lws_exit
ldo -EFAULT(%r0),%r21 /* set errno */
nop

View File

@ -25,6 +25,7 @@
#include <linux/interrupt.h>
#include <linux/console.h>
#include <linux/bug.h>
#include <linux/ratelimit.h>
#include <asm/assembly.h>
#include <asm/uaccess.h>
@ -42,9 +43,6 @@
#include "../math-emu/math-emu.h" /* for handle_fpe() */
#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
/* dumped to the console via printk) */
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
DEFINE_SPINLOCK(pa_dbit_lock);
#endif
@ -160,6 +158,17 @@ void show_regs(struct pt_regs *regs)
}
}
static DEFINE_RATELIMIT_STATE(_hppa_rs,
DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST);
#define parisc_printk_ratelimited(critical, regs, fmt, ...) { \
if ((critical || show_unhandled_signals) && __ratelimit(&_hppa_rs)) { \
printk(fmt, ##__VA_ARGS__); \
show_regs(regs); \
} \
}
static void do_show_stack(struct unwind_frame_info *info)
{
int i = 1;
@ -229,12 +238,10 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
if (err == 0)
return; /* STFU */
printk(KERN_CRIT "%s (pid %d): %s (code %ld) at " RFMT "\n",
parisc_printk_ratelimited(1, regs,
KERN_CRIT "%s (pid %d): %s (code %ld) at " RFMT "\n",
current->comm, task_pid_nr(current), str, err, regs->iaoq[0]);
#ifdef PRINT_USER_FAULTS
/* XXX for debugging only */
show_regs(regs);
#endif
return;
}
@ -321,14 +328,11 @@ static void handle_break(struct pt_regs *regs)
(tt == BUG_TRAP_TYPE_NONE) ? 9 : 0);
}
#ifdef PRINT_USER_FAULTS
if (unlikely(iir != GDB_BREAK_INSN)) {
printk(KERN_DEBUG "break %d,%d: pid=%d command='%s'\n",
if (unlikely(iir != GDB_BREAK_INSN))
parisc_printk_ratelimited(0, regs,
KERN_DEBUG "break %d,%d: pid=%d command='%s'\n",
iir & 31, (iir>>13) & ((1<<13)-1),
task_pid_nr(current), current->comm);
show_regs(regs);
}
#endif
/* send standard GDB signal */
handle_gdb_break(regs, TRAP_BRKPT);
@ -758,11 +762,9 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
default:
if (user_mode(regs)) {
#ifdef PRINT_USER_FAULTS
printk(KERN_DEBUG "\nhandle_interruption() pid=%d command='%s'\n",
task_pid_nr(current), current->comm);
show_regs(regs);
#endif
parisc_printk_ratelimited(0, regs, KERN_DEBUG
"handle_interruption() pid=%d command='%s'\n",
task_pid_nr(current), current->comm);
/* SIGBUS, for lack of a better one. */
si.si_signo = SIGBUS;
si.si_code = BUS_OBJERR;
@ -779,16 +781,10 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
if (user_mode(regs)) {
if ((fault_space >> SPACEID_SHIFT) != (regs->sr[7] >> SPACEID_SHIFT)) {
#ifdef PRINT_USER_FAULTS
if (fault_space == 0)
printk(KERN_DEBUG "User Fault on Kernel Space ");
else
printk(KERN_DEBUG "User Fault (long pointer) (fault %d) ",
code);
printk(KERN_CONT "pid=%d command='%s'\n",
task_pid_nr(current), current->comm);
show_regs(regs);
#endif
parisc_printk_ratelimited(0, regs, KERN_DEBUG
"User fault %d on space 0x%08lx, pid=%d command='%s'\n",
code, fault_space,
task_pid_nr(current), current->comm);
si.si_signo = SIGSEGV;
si.si_errno = 0;
si.si_code = SEGV_MAPERR;

View File

@ -19,10 +19,6 @@
#include <asm/uaccess.h>
#include <asm/traps.h>
#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */
/* dumped to the console via printk) */
/* Various important other fields */
#define bit22set(x) (x & 0x00000200)
#define bits23_25set(x) (x & 0x000001c0)
@ -34,6 +30,8 @@
DEFINE_PER_CPU(struct exception_data, exception_data);
int show_unhandled_signals = 1;
/*
* parisc_acctyp(unsigned int inst) --
* Given a PA-RISC memory access instruction, determine if the
@ -173,6 +171,32 @@ int fixup_exception(struct pt_regs *regs)
return 0;
}
/*
* Print out info about fatal segfaults, if the show_unhandled_signals
* sysctl is set:
*/
static inline void
show_signal_msg(struct pt_regs *regs, unsigned long code,
unsigned long address, struct task_struct *tsk,
struct vm_area_struct *vma)
{
if (!unhandled_signal(tsk, SIGSEGV))
return;
if (!printk_ratelimit())
return;
pr_warn("\n");
pr_warn("do_page_fault() command='%s' type=%lu address=0x%08lx",
tsk->comm, code, address);
print_vma_addr(KERN_CONT " in ", regs->iaoq[0]);
if (vma)
pr_warn(" vm_start = 0x%08lx, vm_end = 0x%08lx\n",
vma->vm_start, vma->vm_end);
show_regs(regs);
}
void do_page_fault(struct pt_regs *regs, unsigned long code,
unsigned long address)
{
@ -270,16 +294,8 @@ bad_area:
if (user_mode(regs)) {
struct siginfo si;
#ifdef PRINT_USER_FAULTS
printk(KERN_DEBUG "\n");
printk(KERN_DEBUG "do_page_fault() pid=%d command='%s' type=%lu address=0x%08lx\n",
task_pid_nr(tsk), tsk->comm, code, address);
if (vma) {
printk(KERN_DEBUG "vm_start = 0x%08lx, vm_end = 0x%08lx\n",
vma->vm_start, vma->vm_end);
}
show_regs(regs);
#endif
show_signal_msg(regs, code, address, tsk, vma);
switch (code) {
case 15: /* Data TLB miss fault/Data page fault */
/* send SIGSEGV when outside of vma */