aboutsummaryrefslogtreecommitdiff
path: root/arch/s390
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/appldata/appldata_base.c2
-rw-r--r--arch/s390/hypfs/inode.c17
-rw-r--r--arch/s390/kernel/compat_linux.c5
-rw-r--r--arch/s390/kernel/head31.S11
-rw-r--r--arch/s390/kernel/head64.S11
-rw-r--r--arch/s390/kernel/kprobes.c9
-rw-r--r--arch/s390/kernel/sys_s390.c20
-rw-r--r--arch/s390/kernel/time.c16
-rw-r--r--arch/s390/lib/spinlock.c62
-rw-r--r--arch/s390/mm/fault.c2
10 files changed, 114 insertions, 41 deletions
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index 9a8f6ff2165..2b1e6c9a6e0 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -16,7 +16,7 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
-#include <linux/page-flags.h>
+#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/pagemap.h>
#include <linux/sysctl.h>
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index 813fc21358f..cd702ae45d6 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -134,12 +134,20 @@ static int hypfs_open(struct inode *inode, struct file *filp)
return 0;
}
-static ssize_t hypfs_aio_read(struct kiocb *iocb, __user char *buf,
- size_t count, loff_t offset)
+static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset)
{
char *data;
size_t len;
struct file *filp = iocb->ki_filp;
+ /* XXX: temporary */
+ char __user *buf = iov[0].iov_base;
+ size_t count = iov[0].iov_len;
+
+ if (nr_segs != 1) {
+ count = -EINVAL;
+ goto out;
+ }
data = filp->private_data;
len = strlen(data);
@@ -158,12 +166,13 @@ static ssize_t hypfs_aio_read(struct kiocb *iocb, __user char *buf,
out:
return count;
}
-static ssize_t hypfs_aio_write(struct kiocb *iocb, const char __user *buf,
- size_t count, loff_t pos)
+static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset)
{
int rc;
struct super_block *sb;
struct hypfs_sb_info *fs_info;
+ size_t count = iov_length(iov, nr_segs);
sb = iocb->ki_filp->f_dentry->d_inode->i_sb;
fs_info = sb->s_fs_info;
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index c46e3d48e41..e15e1489aef 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -357,11 +357,16 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned
int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
{
+ compat_ino_t ino;
int err;
if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
return -EOVERFLOW;
+ ino = stat->ino;
+ if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
+ return -EOVERFLOW;
+
err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
err |= put_user(stat->ino, &statbuf->st_ino);
err |= put_user(stat->mode, &statbuf->st_mode);
diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S
index 1fa9fa1ca74..1b952a3664e 100644
--- a/arch/s390/kernel/head31.S
+++ b/arch/s390/kernel/head31.S
@@ -254,6 +254,16 @@ startup_continue:
oi 3(%r12),0x80 # set IDTE flag
.Lchkidte:
+#
+# find out if the diag 0x9c is available
+#
+ mvc __LC_PGM_NEW_PSW(8),.Lpcdiag9c-.LPG1(%r13)
+ stap __LC_CPUID+4 # store cpu address
+ lh %r1,__LC_CPUID+4
+ diag %r1,0,0x9c # test diag 0x9c
+ oi 2(%r12),1 # set diag9c flag
+.Lchkdiag9c:
+
lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space,
# virtual and never return ...
.align 8
@@ -281,6 +291,7 @@ startup_continue:
.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp
.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
.Lpcidte:.long 0x00080000,0x80000000 + .Lchkidte
+.Lpcdiag9c:.long 0x00080000,0x80000000 + .Lchkdiag9c
.Lmemsize:.long memory_size
.Lmchunk:.long memory_chunk
.Lmflags:.long machine_flags
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index 48998d50b00..b30e5897cdf 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -251,6 +251,17 @@ startup_continue:
0:
#
+# find out if the diag 0x9c is available
+#
+ la %r1,0f-.LPG1(%r13) # set program check address
+ stg %r1,__LC_PGM_NEW_PSW+8
+ stap __LC_CPUID+4 # store cpu address
+ lh %r1,__LC_CPUID+4
+ diag %r1,0,0x9c # test diag 0x9c
+ oi 6(%r12),1 # set diag9c flag
+0:
+
+#
# find out if we have the MVCOS instruction
#
la %r1,0f-.LPG1(%r13) # set program check address
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index ca28fb0b379..4d9ff5ce4cb 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -369,11 +369,12 @@ void __kprobes kretprobe_trampoline_holder(void)
int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{
struct kretprobe_instance *ri = NULL;
- struct hlist_head *head;
+ struct hlist_head *head, empty_rp;
struct hlist_node *node, *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
+ INIT_HLIST_HEAD(&empty_rp);
spin_lock_irqsave(&kretprobe_lock, flags);
head = kretprobe_inst_table_head(current);
@@ -399,7 +400,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
ri->rp->handler(ri, regs);
orig_ret_address = (unsigned long)ri->ret_addr;
- recycle_rp_inst(ri);
+ recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address) {
/*
@@ -417,6 +418,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
spin_unlock_irqrestore(&kretprobe_lock, flags);
preempt_enable_no_resched();
+ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
+ hlist_del(&ri->hlist);
+ kfree(ri);
+ }
/*
* By returning a non-zero value, we are telling
* kprobe_handler() that we don't want the post_handler
diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c
index e351780bb66..584ed95f338 100644
--- a/arch/s390/kernel/sys_s390.c
+++ b/arch/s390/kernel/sys_s390.c
@@ -27,6 +27,7 @@
#include <linux/file.h>
#include <linux/utsname.h>
#include <linux/personality.h>
+#include <linux/unistd.h>
#include <asm/uaccess.h>
#include <asm/ipc.h>
@@ -266,3 +267,22 @@ s390_fadvise64_64(struct fadvise64_64_args __user *args)
return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice);
}
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ register const char *__arg1 asm("2") = filename;
+ register char *const*__arg2 asm("3") = argv;
+ register char *const*__arg3 asm("4") = envp;
+ register long __svcres asm("2");
+ asm volatile(
+ "svc %b1"
+ : "=d" (__svcres)
+ : "i" (__NR_execve),
+ "0" (__arg1),
+ "d" (__arg2),
+ "d" (__arg3) : "memory");
+ return __svcres;
+}
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 1981c6199fa..4bf66cc4a26 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -53,8 +53,6 @@ static u64 init_timer_cc;
static u64 jiffies_timer_cc;
static u64 xtime_cc;
-extern unsigned long wall_jiffies;
-
/*
* Scheduler clock - returns current time in nanosec units.
*/
@@ -87,9 +85,8 @@ static inline unsigned long do_gettimeoffset(void)
{
__u64 now;
- now = (get_clock() - jiffies_timer_cc) >> 12;
- /* We require the offset from the latest update of xtime */
- now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
+ now = (get_clock() - jiffies_timer_cc) >> 12;
+ now -= (__u64) jiffies * USECS_PER_JIFFY;
return (unsigned long) now;
}
@@ -166,7 +163,7 @@ EXPORT_SYMBOL(do_settimeofday);
void account_ticks(struct pt_regs *regs)
{
__u64 tmp;
- __u32 ticks, xticks;
+ __u32 ticks;
/* Calculate how many ticks have passed. */
if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) {
@@ -204,6 +201,7 @@ void account_ticks(struct pt_regs *regs)
*/
write_seqlock(&xtime_lock);
if (S390_lowcore.jiffy_timer > xtime_cc) {
+ __u32 xticks;
tmp = S390_lowcore.jiffy_timer - xtime_cc;
if (tmp >= 2*CLK_TICKS_PER_JIFFY) {
xticks = __div(tmp, CLK_TICKS_PER_JIFFY);
@@ -212,13 +210,11 @@ void account_ticks(struct pt_regs *regs)
xticks = 1;
xtime_cc += CLK_TICKS_PER_JIFFY;
}
- while (xticks--)
- do_timer(regs);
+ do_timer(xticks);
}
write_sequnlock(&xtime_lock);
#else
- for (xticks = ticks; xticks > 0; xticks--)
- do_timer(regs);
+ do_timer(ticks);
#endif
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c
index b9b7958a226..8d76403fcf8 100644
--- a/arch/s390/lib/spinlock.c
+++ b/arch/s390/lib/spinlock.c
@@ -24,57 +24,76 @@ static int __init spin_retry_setup(char *str)
}
__setup("spin_retry=", spin_retry_setup);
-static inline void
-_diag44(void)
+static inline void _raw_yield(void)
{
-#ifdef CONFIG_64BIT
if (MACHINE_HAS_DIAG44)
-#endif
asm volatile("diag 0,0,0x44");
}
-void
-_raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
+static inline void _raw_yield_cpu(int cpu)
+{
+ if (MACHINE_HAS_DIAG9C)
+ asm volatile("diag %0,0,0x9c"
+ : : "d" (__cpu_logical_map[cpu]));
+ else
+ _raw_yield();
+}
+
+void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
{
int count = spin_retry;
+ unsigned int cpu = ~smp_processor_id();
while (1) {
if (count-- <= 0) {
- _diag44();
+ unsigned int owner = lp->owner_cpu;
+ if (owner != 0)
+ _raw_yield_cpu(~owner);
count = spin_retry;
}
if (__raw_spin_is_locked(lp))
continue;
- if (_raw_compare_and_swap(&lp->lock, 0, pc) == 0)
+ if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
+ lp->owner_pc = pc;
return;
+ }
}
}
EXPORT_SYMBOL(_raw_spin_lock_wait);
-int
-_raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
+int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
{
- int count = spin_retry;
+ unsigned int cpu = ~smp_processor_id();
+ int count;
- while (count-- > 0) {
+ for (count = spin_retry; count > 0; count--) {
if (__raw_spin_is_locked(lp))
continue;
- if (_raw_compare_and_swap(&lp->lock, 0, pc) == 0)
+ if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
+ lp->owner_pc = pc;
return 1;
+ }
}
return 0;
}
EXPORT_SYMBOL(_raw_spin_trylock_retry);
-void
-_raw_read_lock_wait(raw_rwlock_t *rw)
+void _raw_spin_relax(raw_spinlock_t *lock)
+{
+ unsigned int cpu = lock->owner_cpu;
+ if (cpu != 0)
+ _raw_yield_cpu(~cpu);
+}
+EXPORT_SYMBOL(_raw_spin_relax);
+
+void _raw_read_lock_wait(raw_rwlock_t *rw)
{
unsigned int old;
int count = spin_retry;
while (1) {
if (count-- <= 0) {
- _diag44();
+ _raw_yield();
count = spin_retry;
}
if (!__raw_read_can_lock(rw))
@@ -86,8 +105,7 @@ _raw_read_lock_wait(raw_rwlock_t *rw)
}
EXPORT_SYMBOL(_raw_read_lock_wait);
-int
-_raw_read_trylock_retry(raw_rwlock_t *rw)
+int _raw_read_trylock_retry(raw_rwlock_t *rw)
{
unsigned int old;
int count = spin_retry;
@@ -103,14 +121,13 @@ _raw_read_trylock_retry(raw_rwlock_t *rw)
}
EXPORT_SYMBOL(_raw_read_trylock_retry);
-void
-_raw_write_lock_wait(raw_rwlock_t *rw)
+void _raw_write_lock_wait(raw_rwlock_t *rw)
{
int count = spin_retry;
while (1) {
if (count-- <= 0) {
- _diag44();
+ _raw_yield();
count = spin_retry;
}
if (!__raw_write_can_lock(rw))
@@ -121,8 +138,7 @@ _raw_write_lock_wait(raw_rwlock_t *rw)
}
EXPORT_SYMBOL(_raw_write_lock_wait);
-int
-_raw_write_trylock_retry(raw_rwlock_t *rw)
+int _raw_write_trylock_retry(raw_rwlock_t *rw)
{
int count = spin_retry;
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index f2b9a84dc2b..9c3c19fe62f 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -353,7 +353,7 @@ no_context:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (tsk->pid == 1) {
+ if (is_init(tsk)) {
yield();
down_read(&mm->mmap_sem);
goto survive;