[FIX] interrupt checking from exception (for x86) 23/75623/3
authorVyacheslav Cherkashin <v.cherkashin@samsung.com>
Mon, 20 Jun 2016 15:23:04 +0000 (18:23 +0300)
committerDmitry Kovalenko <d.kovalenko@samsung.com>
Thu, 23 Jun 2016 15:00:32 +0000 (08:00 -0700)
In LINUX_VERSION_CODE >= 4.0.0 exception handlers wrapped with ist_enter()
and ist_exit() where preempt_count is incremented and decremented, so we
cannot determine interruptable state.

Solution: mask HARDIRQ_OFFSET bit.

Change-Id: If961547e3221ec27157ebc0c993f2a7a3c0e8605
Signed-off-by: Vyacheslav Cherkashin <v.cherkashin@samsung.com>
kprobe/arch/x86/swap-asm/swap_kprobes.c
kprobe/arch/x86/swap-asm/swap_kprobes.h
kprobe/swap_kprobes.c
kprobe/swap_kprobes.h

index 792ef29..79aa609 100644 (file)
@@ -323,7 +323,7 @@ static DEFINE_PER_CPU(struct regs_td, per_cpu_regs_td_st);
 
 static struct regs_td *current_regs_td(void)
 {
-       if (in_interrupt())
+       if (swap_in_interrupt())
                return &__get_cpu_var(per_cpu_regs_td_i);
        else if (switch_to_bits_get(current_kctx, SWITCH_TO_ALL))
                return &__get_cpu_var(per_cpu_regs_td_st);
index 505ab5d..2a196ce 100644 (file)
@@ -89,6 +89,10 @@ static inline int swap_user_mode(struct pt_regs *regs)
 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
 }
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
+#define swap_in_interrupt()    (in_interrupt() & ~HARDIRQ_OFFSET)
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0) */
+
 static inline unsigned long arch_get_task_pc(struct task_struct *p)
 {
        /* FIXME: Not implemented yet */
index ff9777a..918d5a6 100644 (file)
@@ -213,7 +213,7 @@ static struct kpc_data *kp_core_data(void)
 {
        struct kctx *ctx = current_kctx;
 
-       if (in_interrupt())
+       if (swap_in_interrupt())
                return &__get_cpu_var(per_cpu_kpc_data_i);
        else if (switch_to_bits_get(ctx, SWITCH_TO_ALL))
                return &__get_cpu_var(per_cpu_kpc_data_st);
index df154a6..bc662f6 100644 (file)
@@ -304,9 +304,14 @@ void switch_to_bits_set(struct kctx *ctx, unsigned long mask);
 void switch_to_bits_reset(struct kctx *ctx, unsigned long mask);
 unsigned long switch_to_bits_get(struct kctx *ctx, unsigned long mask);
 
+
+#ifndef swap_in_interrupt
+#define swap_in_interrupt()    in_interrupt()
+#endif /* swap_in_interrupt */
+
 static inline int able2resched(struct kctx *ctx)
 {
-       if (in_interrupt() || switch_to_bits_get(ctx, SWITCH_TO_ALL))
+       if (swap_in_interrupt() || switch_to_bits_get(ctx, SWITCH_TO_ALL))
                return 0;
 
        return 1;