diff options
author | Grygorii Strashko <grygorii.strashko@linaro.org> | 2017-04-25 16:20:52 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@armlinux.org.uk> | 2017-04-26 05:59:36 -0400 |
commit | 11ce4b33aedc65198d7bc9669344ebca5ee36a41 (patch) | |
tree | aaf3cd02fea50db3c289bebf9f3a42fbad56f2cd /arch/arm/mm/init.c | |
parent | b70cd406d7fe9976962d621d8c60d324eb47d284 (diff) |
ARM: 8672/1: mm: remove tasklist locking from update_sections_early()
The below backtrace can be observed on -rt kernel with
CONFIG_DEBUG_MODULE_RONX (4.9 kernel CONFIG_DEBUG_RODATA) option enabled:
BUG: sleeping function called from invalid context at kernel/locking/rtmutex.c:993
in_atomic(): 1, irqs_disabled(): 128, pid: 14, name: migration/0
1 lock held by migration/0/14:
#0: (tasklist_lock){+.+...}, at: [<c01183e8>] update_sections_early+0x24/0xdc
irq event stamp: 38
hardirqs last enabled at (37): [<c08f6f7c>] _raw_spin_unlock_irq+0x24/0x68
hardirqs last disabled at (38): [<c01fdfe8>] multi_cpu_stop+0xd8/0x138
softirqs last enabled at (0): [<c01303ec>] copy_process.part.5+0x238/0x1b64
softirqs last disabled at (0): [< (null)>] (null)
Preemption disabled at: [<c01fe244>] cpu_stopper_thread+0x80/0x10c
CPU: 0 PID: 14 Comm: migration/0 Not tainted 4.9.21-rt16-02220-g49e319c #15
Hardware name: Generic DRA74X (Flattened Device Tree)
[<c0112014>] (unwind_backtrace) from [<c010d370>] (show_stack+0x10/0x14)
[<c010d370>] (show_stack) from [<c049beb8>] (dump_stack+0xa8/0xd4)
[<c049beb8>] (dump_stack) from [<c01631a0>] (___might_sleep+0x1bc/0x2ac)
[<c01631a0>] (___might_sleep) from [<c08f7244>] (__rt_spin_lock+0x1c/0x30)
[<c08f7244>] (__rt_spin_lock) from [<c08f77a4>] (rt_read_lock+0x54/0x68)
[<c08f77a4>] (rt_read_lock) from [<c01183e8>] (update_sections_early+0x24/0xdc)
[<c01183e8>] (update_sections_early) from [<c01184b0>] (__fix_kernmem_perms+0x10/0x1c)
[<c01184b0>] (__fix_kernmem_perms) from [<c01fe010>] (multi_cpu_stop+0x100/0x138)
[<c01fe010>] (multi_cpu_stop) from [<c01fe24c>] (cpu_stopper_thread+0x88/0x10c)
[<c01fe24c>] (cpu_stopper_thread) from [<c015edc4>] (smpboot_thread_fn+0x174/0x31c)
[<c015edc4>] (smpboot_thread_fn) from [<c015a988>] (kthread+0xf0/0x108)
[<c015a988>] (kthread) from [<c0108818>] (ret_from_fork+0x14/0x3c)
Freeing unused kernel memory: 1024K (c0d00000 - c0e00000)
The stop_machine() is called with cpus = NULL from fix_kernmem_perms() and
mark_rodata_ro() which means only one CPU will execute
update_sections_early() while all other CPUs will spin and wait. Hence,
it's safe to remove tasklist locking from update_sections_early(). As part
of this change also mark functions which are local to this module as
static.
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Acked-by: Laura Abbott <labbott@redhat.com>
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Diffstat (limited to 'arch/arm/mm/init.c')
-rw-r--r-- | arch/arm/mm/init.c | 13 |
1 files changed, 8 insertions, 5 deletions
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 1d8558ff9827..ad80548325fe 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c | |||
@@ -709,34 +709,37 @@ void set_section_perms(struct section_perm *perms, int n, bool set, | |||
709 | 709 | ||
710 | } | 710 | } |
711 | 711 | ||
712 | /** | ||
713 | * update_sections_early intended to be called only through stop_machine | ||
714 | * framework and executed by only one CPU while all other CPUs will spin and | ||
715 | * wait, so no locking is required in this function. | ||
716 | */ | ||
712 | static void update_sections_early(struct section_perm perms[], int n) | 717 | static void update_sections_early(struct section_perm perms[], int n) |
713 | { | 718 | { |
714 | struct task_struct *t, *s; | 719 | struct task_struct *t, *s; |
715 | 720 | ||
716 | read_lock(&tasklist_lock); | ||
717 | for_each_process(t) { | 721 | for_each_process(t) { |
718 | if (t->flags & PF_KTHREAD) | 722 | if (t->flags & PF_KTHREAD) |
719 | continue; | 723 | continue; |
720 | for_each_thread(t, s) | 724 | for_each_thread(t, s) |
721 | set_section_perms(perms, n, true, s->mm); | 725 | set_section_perms(perms, n, true, s->mm); |
722 | } | 726 | } |
723 | read_unlock(&tasklist_lock); | ||
724 | set_section_perms(perms, n, true, current->active_mm); | 727 | set_section_perms(perms, n, true, current->active_mm); |
725 | set_section_perms(perms, n, true, &init_mm); | 728 | set_section_perms(perms, n, true, &init_mm); |
726 | } | 729 | } |
727 | 730 | ||
728 | int __fix_kernmem_perms(void *unused) | 731 | static int __fix_kernmem_perms(void *unused) |
729 | { | 732 | { |
730 | update_sections_early(nx_perms, ARRAY_SIZE(nx_perms)); | 733 | update_sections_early(nx_perms, ARRAY_SIZE(nx_perms)); |
731 | return 0; | 734 | return 0; |
732 | } | 735 | } |
733 | 736 | ||
734 | void fix_kernmem_perms(void) | 737 | static void fix_kernmem_perms(void) |
735 | { | 738 | { |
736 | stop_machine(__fix_kernmem_perms, NULL, NULL); | 739 | stop_machine(__fix_kernmem_perms, NULL, NULL); |
737 | } | 740 | } |
738 | 741 | ||
739 | int __mark_rodata_ro(void *unused) | 742 | static int __mark_rodata_ro(void *unused) |
740 | { | 743 | { |
741 | update_sections_early(ro_perms, ARRAY_SIZE(ro_perms)); | 744 | update_sections_early(ro_perms, ARRAY_SIZE(ro_perms)); |
742 | return 0; | 745 | return 0; |