Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: 8226/1: cacheflush: get rid of restarting block

We cannot restart cacheflush safely if a process provides user-defined
signal handler and signal is pending. In this case -EINTR is returned
and it is expected that process re-invokes syscall. However, there are
a few problems with that:
* looks like nobody bothers checking return value from cacheflush
* but if it did, we don't provide the restart address for that, so the
process has to use the same range again
* ...and again, what might lead to looping forever

So, remove cacheflush restarting code and terminate cache flushing
as early as fatal signal is pending.

Cc: stable@vger.kernel.org # 3.12+
Reported-by: Chanho Min <chanho.min@lge.com>
Signed-off-by: Vladimir Murzin <vladimir.murzin@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Vladimir Murzin and committed by
Russell King
3f4aa45c 995ab518

+2 -40
-11
arch/arm/include/asm/thread_info.h
··· 44 44 __u32 extra[2]; /* Xscale 'acc' register, etc */ 45 45 }; 46 46 47 - struct arm_restart_block { 48 - union { 49 - /* For user cache flushing */ 50 - struct { 51 - unsigned long start; 52 - unsigned long end; 53 - } cache; 54 - }; 55 - }; 56 - 57 47 /* 58 48 * low level task data that entry.S needs immediate access to. 59 49 * __switch_to() assumes cpu_context follows immediately after cpu_domain. ··· 69 79 unsigned long thumbee_state; /* ThumbEE Handler Base register */ 70 80 #endif 71 81 struct restart_block restart_block; 72 - struct arm_restart_block arm_restart_block; 73 82 }; 74 83 75 84 #define INIT_THREAD_INFO(tsk) \
+2 -29
arch/arm/kernel/traps.c
··· 533 533 return regs->ARM_r0; 534 534 } 535 535 536 - static long do_cache_op_restart(struct restart_block *); 537 - 538 536 static inline int 539 537 __do_cache_op(unsigned long start, unsigned long end) 540 538 { ··· 541 543 do { 542 544 unsigned long chunk = min(PAGE_SIZE, end - start); 543 545 544 - if (signal_pending(current)) { 545 - struct thread_info *ti = current_thread_info(); 546 - 547 - ti->restart_block = (struct restart_block) { 548 - .fn = do_cache_op_restart, 549 - }; 550 - 551 - ti->arm_restart_block = (struct arm_restart_block) { 552 - { 553 - .cache = { 554 - .start = start, 555 - .end = end, 556 - }, 557 - }, 558 - }; 559 - 560 - return -ERESTART_RESTARTBLOCK; 561 - } 546 + if (fatal_signal_pending(current)) 547 + return 0; 562 548 563 549 ret = flush_cache_user_range(start, start + chunk); 564 550 if (ret) ··· 553 571 } while (start < end); 554 572 555 573 return 0; 556 - } 557 - 558 - static long do_cache_op_restart(struct restart_block *unused) 559 - { 560 - struct arm_restart_block *restart_block; 561 - 562 - restart_block = &current_thread_info()->arm_restart_block; 563 - return __do_cache_op(restart_block->cache.start, 564 - restart_block->cache.end); 565 574 } 566 575 567 576 static inline int