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.
Unified · Split
| @@ -44,16 +44,6 @@ struct cpu_context_save { · 43 unmodified lines | ||
| 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. |
| @@ -79,7 +69,6 @@ struct thread_info { · 19 unmodified lines | ||
| 79 | 69 | unsigned long thumbee_state; /* ThumbEE Handler Base register */ |
| 80 | 70 | #endif |
| 81 | 71 | struct restart_block restart_block; |
| 82 | − struct arm_restart_block arm_restart_block; | |
| 83 | 72 | }; |
| 84 | 73 | |
| 85 | 74 | #define INIT_THREAD_INFO(tsk) \ |
| @@ -533,8 +533,6 @@ static int bad_syscall(int n, struct pt_regs *regs) · 532 unmodified lines | ||
| 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 | { |
| @@ -543,24 +541,8 @@ __do_cache_op(unsigned long start, unsigned long end) · 2 unmodified lines | ||
| 543 | 541 | do { |
| 544 | 542 | unsigned long chunk = min(PAGE_SIZE, end - start); |
| 545 | 543 | |
| 546 | − if (signal_pending(current)) { | |
| 547 | − struct thread_info *ti = current_thread_info(); | |
| 548 | − | |
| 549 | − ti->restart_block = (struct restart_block) { | |
| 550 | − .fn = do_cache_op_restart, | |
| 551 | − }; | |
| 552 | − | |
| 553 | − ti->arm_restart_block = (struct arm_restart_block) { | |
| 554 | − { | |
| 555 | − .cache = { | |
| 556 | − .start = start, | |
| 557 | − .end = end, | |
| 558 | − }, | |
| 559 | − }, | |
| 560 | − }; | |
| 561 | − | |
| 562 | − return -ERESTART_RESTARTBLOCK; | |
| 563 | − } | |
| 544 | + if (fatal_signal_pending(current)) | |
| 545 | + return 0; | |
| 564 | 546 | |
| 565 | 547 | ret = flush_cache_user_range(start, start + chunk); |
| 566 | 548 | if (ret) |
| @@ -573,15 +555,6 @@ __do_cache_op(unsigned long start, unsigned long end) · 6 unmodified lines | ||
| 573 | 555 | return 0; |
| 574 | 556 | } |
| 575 | 557 | |
| 576 | −static long do_cache_op_restart(struct restart_block *unused) | |
| 577 | −{ | |
| 578 | − struct arm_restart_block *restart_block; | |
| 579 | − | |
| 580 | − restart_block = ¤t_thread_info()->arm_restart_block; | |
| 581 | − return __do_cache_op(restart_block->cache.start, | |
| 582 | − restart_block->cache.end); | |
| 583 | −} | |
| 584 | − | |
| 585 | 558 | static inline int |
| 586 | 559 | do_cache_op(unsigned long start, unsigned long end, int flags) |
| 587 | 560 | { |