Eric reported that handling corresponding crash hotplug event can be failed easily when many memory hotplug event are notified in a short period. They failed because failing to take __kexec_lock. ======= [ 78.714569] Fallback order for Node 0: 0 [ 78.714575] Built 1 zonelists, mobility grouping on. Total pages: 1817886 [ 78.717133] Policy zone: Normal [ 78.724423] crash hp: kexec_trylock() failed, elfcorehdr may be inaccurate [ 78.727207] crash hp: kexec_trylock() failed, elfcorehdr may be inaccurate [ 80.056643] PEFILE: Unsigned PE binary ======= The memory hotplug events are notified very quickly and very many, while the handling of crash hotplug is much slower relatively. So the atomic variable __kexec_lock and kexec_trylock() can't guarantee the serialization of crash hotplug handling. Here, add a new mutex lock __crash_hotplug_lock to serialize crash hotplug handling specifically. This doesn't impact the usage of __kexec_lock.
Unified · Split
| @@ -739,6 +739,17 @@ subsys_initcall(crash_notes_memory_init); · 738 unmodified lines | ||
| 739 | 739 | #undef pr_fmt |
| 740 | 740 | #define pr_fmt(fmt) "crash hp: " fmt |
| 741 | 741 | |
| 742 | +/* | |
| 743 | + * Different than kexec/kdump loading/unloading/jumping/shrinking which | |
| 744 | + * usually rarely happen, there will be many crash hotplug events notified | |
| 745 | + * during one short period, e.g one memory board is hot added and memory | |
| 746 | + * regions are online. So mutex lock __crash_hotplug_lock is used to | |
| 747 | + * serialize the crash hotplug handling specifically. | |
| 748 | + */ | |
| 749 | +DEFINE_MUTEX(__crash_hotplug_lock); | |
| 750 | +#define crash_hotplug_lock() mutex_lock(&__crash_hotplug_lock) | |
| 751 | +#define crash_hotplug_unlock() mutex_unlock(&__crash_hotplug_lock) | |
| 752 | + | |
| 742 | 753 | /* |
| 743 | 754 | * This routine utilized when the crash_hotplug sysfs node is read. |
| 744 | 755 | * It reflects the kernel's ability/permission to update the crash |
| @@ -748,9 +759,11 @@ int crash_check_update_elfcorehdr(void) · 3 unmodified lines | ||
| 748 | 759 | { |
| 749 | 760 | int rc = 0; |
| 750 | 761 | |
| 762 | + crash_hotplug_lock(); | |
| 751 | 763 | /* Obtain lock while reading crash information */ |
| 752 | 764 | if (!kexec_trylock()) { |
| 753 | 765 | pr_info("kexec_trylock() failed, elfcorehdr may be inaccurate\n"); |
| 766 | + crash_hotplug_unlock(); | |
| 754 | 767 | return 0; |
| 755 | 768 | } |
| 756 | 769 | if (kexec_crash_image) { |
| @@ -761,6 +774,7 @@ int crash_check_update_elfcorehdr(void) · 4 unmodified lines | ||
| 761 | 774 | } |
| 762 | 775 | /* Release lock now that update complete */ |
| 763 | 776 | kexec_unlock(); |
| 777 | + crash_hotplug_unlock(); | |
| 764 | 778 | |
| 765 | 779 | return rc; |
| 766 | 780 | } |
| @@ -783,9 +797,11 @@ static void crash_handle_hotplug_event(unsigned int hp_action, unsigned int cpu) · 16 unmodified lines | ||
| 783 | 797 | { |
| 784 | 798 | struct kimage *image; |
| 785 | 799 | |
| 800 | + crash_hotplug_lock(); | |
| 786 | 801 | /* Obtain lock while changing crash information */ |
| 787 | 802 | if (!kexec_trylock()) { |
| 788 | 803 | pr_info("kexec_trylock() failed, elfcorehdr may be inaccurate\n"); |
| 804 | + crash_hotplug_unlock(); | |
| 789 | 805 | return; |
| 790 | 806 | } |
| 791 | 807 | |
| @@ -852,6 +868,7 @@ static void crash_handle_hotplug_event(unsigned int hp_action, unsigned int cpu) · 60 unmodified lines | ||
| 852 | 868 | out: |
| 853 | 869 | /* Release lock now that update complete */ |
| 854 | 870 | kexec_unlock(); |
| 871 | + crash_hotplug_unlock(); | |
| 855 | 872 | } |
| 856 | 873 | |
| 857 | 874 | static int crash_memhp_notifier(struct notifier_block *nb, unsigned long val, void *v) |