From d7d1104fa40f66dbe50840f05b34268144f8a17a Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 22 Jun 2009 12:08:03 +0200 Subject: [S390] time: convert from bootmem to slab The slab allocator is earlier available so convert the bootmem allocations to slab/gfp allocations. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/time.c | 16 ++++------------ arch/s390/kernel/vtime.c | 5 +---- 2 files changed, 5 insertions(+), 16 deletions(-) (limited to 'arch/s390/kernel') diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 215330a2c12..d4c8e9c47c8 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -62,9 +61,6 @@ u64 sched_clock_base_cc = -1; /* Force to data section. */ -static ext_int_info_t ext_int_info_cc; -static ext_int_info_t ext_int_etr_cc; - static DEFINE_PER_CPU(struct clock_event_device, comparators); /* @@ -255,15 +251,11 @@ void __init time_init(void) stp_reset(); /* request the clock comparator external interrupt */ - if (register_early_external_interrupt(0x1004, - clock_comparator_interrupt, - &ext_int_info_cc) != 0) + if (register_external_interrupt(0x1004, clock_comparator_interrupt)) panic("Couldn't request external interrupt 0x1004"); /* request the timing alert external interrupt */ - if (register_early_external_interrupt(0x1406, - timing_alert_interrupt, - &ext_int_etr_cc) != 0) + if (register_external_interrupt(0x1406, timing_alert_interrupt)) panic("Couldn't request external interrupt 0x1406"); if (clocksource_register(&clocksource_tod) != 0) @@ -1445,14 +1437,14 @@ static void __init stp_reset(void) { int rc; - stp_page = alloc_bootmem_pages(PAGE_SIZE); + stp_page = (void *) get_zeroed_page(GFP_ATOMIC); rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); if (rc == 0) set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags); else if (stp_online) { pr_warning("The real or virtual hardware system does " "not provide an STP interface\n"); - free_bootmem((unsigned long) stp_page, PAGE_SIZE); + free_page((unsigned long) stp_page); stp_page = NULL; stp_online = 0; } diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index c8eb7255332..ade17e771f0 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -25,8 +25,6 @@ #include #include -static ext_int_info_t ext_int_info_timer; - static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); DEFINE_PER_CPU(struct s390_idle_data, s390_idle) = { @@ -557,8 +555,7 @@ void init_cpu_vtimer(void) void __init vtime_init(void) { /* request the cpu timer external interrupt */ - if (register_early_external_interrupt(0x1005, do_cpu_timer_interrupt, - &ext_int_info_timer) != 0) + if (register_external_interrupt(0x1005, do_cpu_timer_interrupt)) panic("Couldn't request external interrupt 0x1005"); /* Enable cpu timer interrupts on the boot cpu. */ -- cgit v1.2.3-70-g09d2 From e98bbaafcd1c47d30f3245517fb585f1aaaca4db Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Mon, 22 Jun 2009 12:08:20 +0200 Subject: [S390] lockless idle time accounting Replace the spinlock used in the idle time accounting with a sequence counter mechanism analog to seqlock. Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/cputime.h | 2 +- arch/s390/kernel/smp.c | 28 +++++++++++++++++++--------- arch/s390/kernel/vtime.c | 22 +++++++++++++++------- 3 files changed, 35 insertions(+), 17 deletions(-) (limited to 'arch/s390/kernel') diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h index ec917d42ee6..7a3817a656d 100644 --- a/arch/s390/include/asm/cputime.h +++ b/arch/s390/include/asm/cputime.h @@ -178,7 +178,7 @@ cputime64_to_clock_t(cputime64_t cputime) } struct s390_idle_data { - spinlock_t lock; + unsigned int sequence; unsigned long long idle_count; unsigned long long idle_enter; unsigned long long idle_time; diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index fd8e3111a4e..2270730f535 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -856,13 +856,20 @@ static ssize_t show_idle_count(struct sys_device *dev, { struct s390_idle_data *idle; unsigned long long idle_count; + unsigned int sequence; idle = &per_cpu(s390_idle, dev->id); - spin_lock(&idle->lock); +repeat: + sequence = idle->sequence; + smp_rmb(); + if (sequence & 1) + goto repeat; idle_count = idle->idle_count; if (idle->idle_enter) idle_count++; - spin_unlock(&idle->lock); + smp_rmb(); + if (idle->sequence != sequence) + goto repeat; return sprintf(buf, "%llu\n", idle_count); } static SYSDEV_ATTR(idle_count, 0444, show_idle_count, NULL); @@ -872,15 +879,22 @@ static ssize_t show_idle_time(struct sys_device *dev, { struct s390_idle_data *idle; unsigned long long now, idle_time, idle_enter; + unsigned int sequence; idle = &per_cpu(s390_idle, dev->id); - spin_lock(&idle->lock); now = get_clock(); +repeat: + sequence = idle->sequence; + smp_rmb(); + if (sequence & 1) + goto repeat; idle_time = idle->idle_time; idle_enter = idle->idle_enter; if (idle_enter != 0ULL && idle_enter < now) idle_time += now - idle_enter; - spin_unlock(&idle->lock); + smp_rmb(); + if (idle->sequence != sequence) + goto repeat; return sprintf(buf, "%llu\n", idle_time >> 12); } static SYSDEV_ATTR(idle_time_us, 0444, show_idle_time, NULL); @@ -908,11 +922,7 @@ static int __cpuinit smp_cpu_notify(struct notifier_block *self, case CPU_ONLINE: case CPU_ONLINE_FROZEN: idle = &per_cpu(s390_idle, cpu); - spin_lock_irq(&idle->lock); - idle->idle_enter = 0; - idle->idle_time = 0; - idle->idle_count = 0; - spin_unlock_irq(&idle->lock); + memset(idle, 0, sizeof(struct s390_idle_data)); if (sysfs_create_group(&s->kobj, &cpu_online_attr_group)) return NOTIFY_BAD; break; diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index ade17e771f0..c41bb0d416e 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -27,9 +27,7 @@ static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); -DEFINE_PER_CPU(struct s390_idle_data, s390_idle) = { - .lock = __SPIN_LOCK_UNLOCKED(s390_idle.lock) -}; +DEFINE_PER_CPU(struct s390_idle_data, s390_idle); static inline __u64 get_vtimer(void) { @@ -151,11 +149,13 @@ void vtime_start_cpu(void) vq->elapsed -= vq->idle - S390_lowcore.async_enter_timer; } - spin_lock(&idle->lock); + idle->sequence++; + smp_wmb(); idle->idle_time += idle_time; idle->idle_enter = 0ULL; idle->idle_count++; - spin_unlock(&idle->lock); + smp_wmb(); + idle->sequence++; } void vtime_stop_cpu(void) @@ -242,15 +242,23 @@ cputime64_t s390_get_idle_time(int cpu) { struct s390_idle_data *idle; unsigned long long now, idle_time, idle_enter; + unsigned int sequence; idle = &per_cpu(s390_idle, cpu); - spin_lock(&idle->lock); + now = get_clock(); +repeat: + sequence = idle->sequence; + smp_rmb(); + if (sequence & 1) + goto repeat; idle_time = 0; idle_enter = idle->idle_enter; if (idle_enter != 0ULL && idle_enter < now) idle_time = now - idle_enter; - spin_unlock(&idle->lock); + smp_rmb(); + if (idle->sequence != sequence) + goto repeat; return idle_time; } -- cgit v1.2.3-70-g09d2 From acf018004f76617dbab36ef4b5480d4351f9cdff Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 22 Jun 2009 12:08:23 +0200 Subject: [S390] kprobes: defer setting of ctlblk state get_krobe_ctlblk returns a per cpu kprobe control block which holds the state of the current cpu wrt to kprobe. When inserting/removing a kprobe the state of the cpu which replaces the code is changed to KPROBE_SWAP_INST. This however is done when preemption is still enabled. So the state of the current cpu doesn't necessarily reflect the real state. To fix this move the code that changes the state to non-preemptible context. Reported-by: Ananth N Mavinakayanahalli Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/kprobes.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'arch/s390/kernel') diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 9bb2f6241d9..86783efa24e 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -154,39 +154,35 @@ void __kprobes get_instruction_type(struct arch_specific_insn *ainsn) static int __kprobes swap_instruction(void *aref) { + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + unsigned long status = kcb->kprobe_status; struct ins_replace_args *args = aref; + int rc; - return probe_kernel_write(args->ptr, &args->new, sizeof(args->new)); + kcb->kprobe_status = KPROBE_SWAP_INST; + rc = probe_kernel_write(args->ptr, &args->new, sizeof(args->new)); + kcb->kprobe_status = status; + return rc; } void __kprobes arch_arm_kprobe(struct kprobe *p) { - struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); - unsigned long status = kcb->kprobe_status; struct ins_replace_args args; args.ptr = p->addr; args.old = p->opcode; args.new = BREAKPOINT_INSTRUCTION; - - kcb->kprobe_status = KPROBE_SWAP_INST; stop_machine(swap_instruction, &args, NULL); - kcb->kprobe_status = status; } void __kprobes arch_disarm_kprobe(struct kprobe *p) { - struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); - unsigned long status = kcb->kprobe_status; struct ins_replace_args args; args.ptr = p->addr; args.old = BREAKPOINT_INSTRUCTION; args.new = p->opcode; - - kcb->kprobe_status = KPROBE_SWAP_INST; stop_machine(swap_instruction, &args, NULL); - kcb->kprobe_status = status; } void __kprobes arch_remove_kprobe(struct kprobe *p) -- cgit v1.2.3-70-g09d2