History

Merge tag 'mm-nonmm-stable-2025-10-02-15-29' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull non-MM updates from Andrew Morton: - "ida: Remove the ida_simple_xxx() API" from Christophe Jaillet completes the removal of this legacy IDR API - "panic: introduce panic status function family" from Jinchao Wang provides a number of cleanups to the panic code and its various helpers, which were rather ad-hoc and scattered all over the place - "tools/delaytop: implement real-time keyboard interaction support" from Fan Yu adds a few nice user-facing usability changes to the delaytop monitoring tool - "efi: Fix EFI boot with kexec handover (KHO)" from Evangelos Petrongonas fixes a panic which was happening with the combination of EFI and KHO - "Squashfs: performance improvement and a sanity check" from Phillip Lougher teaches squashfs's lseek() about SEEK_DATA/SEEK_HOLE. A mere 150x speedup was measured for a well-chosen microbenchmark - plus another 50-odd singleton patches all over the place * tag 'mm-nonmm-stable-2025-10-02-15-29' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (75 commits) Squashfs: reject negative file sizes in squashfs_read_inode() kallsyms: use kmalloc_array() instead of kmalloc() MAINTAINERS: update Sibi Sankar's email address Squashfs: add SEEK_DATA/SEEK_HOLE support Squashfs: add additional inode sanity checking lib/genalloc: fix device leak in of_gen_pool_get() panic: remove CONFIG_PANIC_ON_OOPS_VALUE ocfs2: fix double free in user_cluster_connect() checkpatch: suppress strscpy warnings for userspace tools cramfs: fix incorrect physical page address calculation kernel: prevent prctl(PR_SET_PDEATHSIG) from racing with parent process exit Squashfs: fix uninit-value in squashfs_get_parent kho: only fill kimage if KHO is finalized ocfs2: avoid extra calls to strlen() after ocfs2_sprintf_system_inode_name() kernel/sys.c: fix the racy usage of task_lock(tsk->group_leader) in sys_prlimit64() paths sched/task.h: fix the wrong comment on task_lock() nesting with tasklist_lock coccinelle: platform_no_drv_owner: handle also built-in drivers coccinelle: of_table: handle SPI device ID tables lib/decompress: use designated initializers for struct compress_format efi: support booting with kexec handover (KHO) ...

Linus Torvalds committed 1 year ago

Commit e406d572 parents 8804d97 9f1c14c78 files · +1619 −476Browse files

Unified · Split

78 files
  1. .mailmap +2 −1
  2. Documentation/accounting/delay-accounting.rst +58 −33
  3. Documentation/admin-guide/kernel-parameters.txt +1 −1
  4. Documentation/admin-guide/sysctl/kernel.rst +1 −1
  5. Documentation/dev-tools/kcov.rst +6 −1
  6. MAINTAINERS +1 −1
  7. arch/x86/kernel/crash.c +19 −6
  8. arch/x86/kernel/kexec-bzimage64.c +44 −3
  9. drivers/firmware/efi/efi-init.c +25 −4
  10. drivers/video/fbdev/core/fbcon.c +1 −8
  11. fs/cramfs/inode.c +1 −1
  12. fs/fat/dir.c +3 −4
  13. fs/ocfs2/alloc.c +1 −2
  14. fs/ocfs2/dlm/dlmmaster.c +0 −11
  15. fs/ocfs2/dlm/dlmrecovery.c +0 −1
  16. fs/ocfs2/inode.c +8 −0
  17. fs/ocfs2/ioctl.c +7 −11
  18. fs/ocfs2/move_extents.c +4 −4
  19. fs/ocfs2/ocfs2_fs.h +1 −1
  20. fs/ocfs2/stack_user.c +1 −0
  21. fs/ocfs2/sysfile.c +6 −6
  22. fs/proc/base.c +1 −1
  23. fs/squashfs/file.c +126 −11
  24. fs/squashfs/inode.c +35 −4
  25. fs/squashfs/squashfs.h +1 −0
  26. fs/squashfs/squashfs_fs.h +1 −0
  27. fs/squashfs/squashfs_fs_i.h +1 −1
  28. include/linux/idr.h +0 −8
  29. include/linux/kernel.h +17 −4
  30. include/linux/kexec.h +4 −1
  31. include/linux/kexec_handover.h +6 −0
  32. include/linux/list.h +8 −0
  33. include/linux/moduleparam.h +13 −0
  34. include/linux/nvmem-provider.h +1 −1
  35. include/linux/panic.h +6 −0
  36. include/linux/printk.h +0 −2
  37. include/linux/sched/task.h +2 −3
  38. include/uapi/linux/kexec.h +4 −0
  39. init/main.c +12 −0
  40. kernel/Kconfig.kexec +11 −0
  41. kernel/Makefile +1 −0
  42. kernel/crash_core.c +18 −12
  43. kernel/crash_core_test.c +343 −0
  44. kernel/fork.c +6 −12
  45. kernel/hung_task.c +41 −37
  46. kernel/kallsyms_selftest.c +1 −1
  47. kernel/kcov.c +9 −0
  48. kernel/kexec_core.c +0 −1
  49. kernel/kexec_file.c +1 −0
  50. kernel/kexec_handover.c +21 −1
  51. kernel/panic.c +103 −26
  52. kernel/printk/internal.h +0 −1
  53. kernel/printk/nbcon.c +7 −7
  54. kernel/printk/printk.c +5 −32
  55. kernel/printk/printk_ringbuffer.c +1 −1
  56. kernel/sys.c +30 −2
  57. kernel/watchdog.c +23 −5
  58. kernel/watchdog_perf.c +4 −0
  59. lib/Kconfig.debug +0 −6
  60. lib/alloc_tag.c +2 −1
  61. lib/btree.c +2 −2
  62. lib/decompress.c +10 −11
  63. lib/digsig.c +0 −1
  64. lib/dump_stack.c +1 −1
  65. lib/fault-inject-usercopy.c +1 −3
  66. lib/genalloc.c +4 −1
  67. lib/ref_tracker.c +3 −3
  68. lib/sys_info.c +2 −1
  69. lib/test_firmware.c +4 −3
  70. scripts/checkpatch.pl +9 −5
  71. scripts/coccinelle/api/platform_no_drv_owner.cocci +9 −0
  72. scripts/coccinelle/misc/of_table.cocci +7 −7
  73. tools/accounting/delaytop.c +427 −144
  74. tools/testing/radix-tree/idr-test.c +7 −9
  75. tools/testing/selftests/proc/.gitignore +1 −0
  76. tools/testing/selftests/proc/Makefile +1 −0
  77. tools/testing/selftests/proc/proc-net-dev-lseek.c +68 −0
  78. tools/testing/selftests/proc/proc-pid-vm.c +8 −4
.mailmap+2−1
@@ -721,7 +721,8 @@ Shuah Khan <shuah@kernel.org> <shuahkhan@gmail.com> · 720 unmodified lines
721Shuah Khan <shuah@kernel.org> <shuah.khan@hp.com>721Shuah Khan <shuah@kernel.org> <shuah.khan@hp.com>
722Shuah Khan <shuah@kernel.org> <shuahkh@osg.samsung.com>722Shuah Khan <shuah@kernel.org> <shuahkh@osg.samsung.com>
723Shuah Khan <shuah@kernel.org> <shuah.kh@samsung.com>723Shuah Khan <shuah@kernel.org> <shuah.kh@samsung.com>
724Sibi Sankar <quic_sibis@quicinc.com> <sibis@codeaurora.org>724Sibi Sankar <sibi.sankar@oss.qualcomm.com> <sibis@codeaurora.org>
725Sibi Sankar <sibi.sankar@oss.qualcomm.com> <quic_sibis@quicinc.com>
725Sid Manning <quic_sidneym@quicinc.com> <sidneym@codeaurora.org>726Sid Manning <quic_sidneym@quicinc.com> <sidneym@codeaurora.org>
726Simon Arlott <simon@octiron.net> <simon@fire.lp0.eu>727Simon Arlott <simon@octiron.net> <simon@fire.lp0.eu>
727Simona Vetter <simona.vetter@ffwll.ch> <daniel.vetter@ffwll.ch>728Simona Vetter <simona.vetter@ffwll.ch> <daniel.vetter@ffwll.ch>
Documentation/accounting/delay-accounting.rst+58−33
@@ -134,47 +134,72 @@ The above command can be used with -v to get more debug information. · 133 unmodified lines
134 134
135After the system starts, use `delaytop` to get the system-wide delay information,135After the system starts, use `delaytop` to get the system-wide delay information,
136which includes system-wide PSI information and Top-N high-latency tasks.136which includes system-wide PSI information and Top-N high-latency tasks.
137Note: PSI support requires `CONFIG_PSI=y` and `psi=1` for full functionality.
137 138
138`delaytop` supports sorting by CPU latency in descending order by default,139`delaytop` is an interactive tool for monitoring system pressure and task delays.
139displays the top 20 high-latency tasks by default, and refreshes the latency140It supports multiple sorting options, display modes, and real-time keyboard controls.
140data every 2 seconds by default.
141 141
142Get PSI information and Top-N tasks delay, since system boot::142Basic usage with default settings (sorts by CPU delay, shows top 20 tasks, refreshes every 2 seconds)::
143 143
144 bash# ./delaytop144 bash# ./delaytop
145 System Pressure Information: (avg10/avg60/avg300/total)145 System Pressure Information: (avg10/avg60vg300/total)
146 CPU some: 0.0%/ 0.0%/ 0.0%/ 345(ms)146 CPU some: 0.0%/ 0.0%/ 0.0%/ 106137(ms)
147 CPU full: 0.0%/ 0.0%/ 0.0%/ 0(ms)147 CPU full: 0.0%/ 0.0%/ 0.0%/ 0(ms)
148 Memory full: 0.0%/ 0.0%/ 0.0%/ 0(ms)148 Memory full: 0.0%/ 0.0%/ 0.0%/ 0(ms)
149 Memory some: 0.0%/ 0.0%/ 0.0%/ 0(ms)149 Memory some: 0.0%/ 0.0%/ 0.0%/ 0(ms)
150 IO full: 0.0%/ 0.0%/ 0.0%/ 65(ms)150 IO full: 0.0%/ 0.0%/ 0.0%/ 2240(ms)
151 IO some: 0.0%/ 0.0%/ 0.0%/ 79(ms)151 IO some: 0.0%/ 0.0%/ 0.0%/ 2783(ms)
152 IRQ full: 0.0%/ 0.0%/ 0.0%/ 0(ms)152 IRQ full: 0.0%/ 0.0%/ 0.0%/ 0(ms)
153 Top 20 processes (sorted by CPU delay):153 [o]sort [M]memverbose [q]quit
154 PID TGID COMMAND CPU(ms) IO(ms) SWAP(ms) RCL(ms) THR(ms) CMP(ms) WP(ms) IRQ(ms)154 Top 20 processes (sorted by cpu delay):
155 ----------------------------------------------------------------------------------------------155 PID TGID COMMAND CPU(ms) IO(ms) IRQ(ms) MEM(ms)
156 161 161 zombie_memcg_re 1.40 0.00 0.00 0.00 0.00 0.00 0.00 0.00156 ------------------------------------------------------------------------
157 130 130 blkcg_punt_bio 1.37 0.00 0.00 0.00 0.00 0.00 0.00 0.00157 110 110 kworker/15:0H-s 27.91 0.00 0.00 0.00
158 444 444 scsi_tmf_0 0.73 0.00 0.00 0.00 0.00 0.00 0.00 0.00158 57 57 cpuhp/7 3.18 0.00 0.00 0.00
159 1280 1280 rsyslogd 0.53 0.04 0.00 0.00 0.00 0.00 0.00 0.00159 99 99 cpuhp/14 2.97 0.00 0.00 0.00
160 12 12 ksoftirqd/0 0.47 0.00 0.00 0.00 0.00 0.00 0.00 0.00160 51 51 cpuhp/6 0.90 0.00 0.00 0.00
161 1277 1277 nbd-server 0.44 0.00 0.00 0.00 0.00 0.00 0.00 0.00161 44 44 kworker/4:0H-sy 0.80 0.00 0.00 0.00
162 308 308 kworker/2:2-sys 0.41 0.00 0.00 0.00 0.00 0.00 0.00 0.00162 60 60 ksoftirqd/7 0.74 0.00 0.00 0.00
163 55 55 netns 0.36 0.00 0.00 0.00 0.00 0.00 0.00 0.00163 76 76 idle_inject/10 0.31 0.00 0.00 0.00
164 1187 1187 acpid 0.31 0.03 0.00 0.00 0.00 0.00 0.00 0.00164 100 100 idle_inject/14 0.30 0.00 0.00 0.00
165 6184 6184 kworker/1:2-sys 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00165 1309 1309 systemsettings 0.29 0.00 0.00 0.00
166 186 186 kaluad 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00166 45 45 cpuhp/5 0.22 0.00 0.00 0.00
167 18 18 ksoftirqd/1 0.24 0.00 0.00 0.00 0.00 0.00 0.00 0.00167 63 63 cpuhp/8 0.20 0.00 0.00 0.00
168 185 185 kmpath_rdacd 0.23 0.00 0.00 0.00 0.00 0.00 0.00 0.00168 87 87 cpuhp/12 0.18 0.00 0.00 0.00
169 190 190 kstrp 0.23 0.00 0.00 0.00 0.00 0.00 0.00 0.00169 93 93 cpuhp/13 0.17 0.00 0.00 0.00
170 2759 2759 agetty 0.20 0.03 0.00 0.00 0.00 0.00 0.00 0.00170 1265 1265 acpid 0.17 0.00 0.00 0.00
171 1190 1190 kworker/0:3-sys 0.19 0.00 0.00 0.00 0.00 0.00 0.00 0.00171 1552 1552 sshd 0.17 0.00 0.00 0.00
172 1272 1272 sshd 0.15 0.04 0.00 0.00 0.00 0.00 0.00 0.00172 2584 2584 sddm-helper 0.16 0.00 0.00 0.00
173 1156 1156 license 0.15 0.11 0.00 0.00 0.00 0.00 0.00 0.00173 1284 1284 rtkit-daemon 0.15 0.00 0.00 0.00
174 134 134 md 0.13 0.00 0.00 0.00 0.00 0.00 0.00 0.00174 1326 1326 nde-netfilter 0.14 0.00 0.00 0.00
175 6142 6142 kworker/3:2-xfs 0.13 0.00 0.00 0.00 0.00 0.00 0.00 0.00175 27 27 cpuhp/2 0.13 0.00 0.00 0.00
176 176 631 631 kworker/11:2-rc 0.11 0.00 0.00 0.00
177Dynamic interactive interface of delaytop::177
178Interactive keyboard controls during runtime::
179
180 o - Select sort field (CPU, IO, IRQ, Memory, etc.)
181 M - Toggle display mode (Default/Memory Verbose)
182 q - Quit
183
184Available sort fields(use -s/--sort or interactive command)::
185
186 cpu(c) - CPU delay
187 blkio(i) - I/O delay
188 irq(q) - IRQ delay
189 mem(m) - Total memory delay
190 swapin(s) - Swapin delay (memory verbose mode only)
191 freepages(r) - Freepages reclaim delay (memory verbose mode only)
192 thrashing(t) - Thrashing delay (memory verbose mode only)
193 compact(p) - Compaction delay (memory verbose mode only)
194 wpcopy(w) - Write page copy delay (memory verbose mode only)
195
196Advanced usage examples::
197
198 # ./delaytop -s blkio
199 Sorted by IO delay
200
201 # ./delaytop -s mem -M
202 Sorted by memory delay in memory verbose mode
178 203
179 # ./delaytop -p pid204 # ./delaytop -p pid
180 Print delayacct stats205 Print delayacct stats
Documentation/admin-guide/kernel-parameters.txt+1−1
@@ -4603,7 +4603,7 @@ · 4602 unmodified lines
4603 bit 2: print timer info4603 bit 2: print timer info
4604 bit 3: print locks info if CONFIG_LOCKDEP is on4604 bit 3: print locks info if CONFIG_LOCKDEP is on
4605 bit 4: print ftrace buffer4605 bit 4: print ftrace buffer
4606 bit 5: replay all messages on consoles at the end of panic4606 bit 5: replay all kernel messages on consoles at the end of panic
4607 bit 6: print all CPUs backtrace (if available in the arch)4607 bit 6: print all CPUs backtrace (if available in the arch)
4608 bit 7: print only tasks in uninterruptible (blocked) state4608 bit 7: print only tasks in uninterruptible (blocked) state
4609 *Be aware* that this option may print a _lot_ of lines,4609 *Be aware* that this option may print a _lot_ of lines,
Documentation/admin-guide/sysctl/kernel.rst+1−1
@@ -890,7 +890,7 @@ bit 1 print system memory info · 889 unmodified lines
890bit 2 print timer info890bit 2 print timer info
891bit 3 print locks info if ``CONFIG_LOCKDEP`` is on891bit 3 print locks info if ``CONFIG_LOCKDEP`` is on
892bit 4 print ftrace buffer892bit 4 print ftrace buffer
893bit 5 replay all messages on consoles at the end of panic893bit 5 replay all kernel messages on consoles at the end of panic
894bit 6 print all CPUs backtrace (if available in the arch)894bit 6 print all CPUs backtrace (if available in the arch)
895bit 7 print only tasks in uninterruptible (blocked) state895bit 7 print only tasks in uninterruptible (blocked) state
896===== ============================================896===== ============================================
Documentation/dev-tools/kcov.rst+6−1
@@ -361,7 +361,12 @@ local tasks spawned by the process and the global task that handles USB bus #1: · 360 unmodified lines
361 */361 */
362 sleep(2);362 sleep(2);
363 363
364 n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED);364 /*
365 * The load to the coverage count should be an acquire to pair with
366 * pair with the corresponding write memory barrier (smp_wmb()) on
367 * the kernel-side in kcov_move_area().
368 */
369 n = __atomic_load_n(&cover[0], __ATOMIC_ACQUIRE);
365 for (i = 0; i < n; i++)370 for (i = 0; i < n; i++)
366 printf("0x%lx\n", cover[i + 1]);371 printf("0x%lx\n", cover[i + 1]);
367 if (ioctl(fd, KCOV_DISABLE, 0))372 if (ioctl(fd, KCOV_DISABLE, 0))
MAINTAINERS+1−1
@@ -20987,7 +20987,7 @@ F: Documentation/devicetree/bindings/power/avs/qcom,cpr.yaml · 20986 unmodified lines
20987F: drivers/pmdomain/qcom/cpr.c20987F: drivers/pmdomain/qcom/cpr.c
20988 20988
20989QUALCOMM CPUCP MAILBOX DRIVER20989QUALCOMM CPUCP MAILBOX DRIVER
20990M: Sibi Sankar <quic_sibis@quicinc.com>20990M: Sibi Sankar <sibi.sankar@oss.qualcomm.com>
20991L: linux-arm-msm@vger.kernel.org20991L: linux-arm-msm@vger.kernel.org
20992S: Supported20992S: Supported
20993F: Documentation/devicetree/bindings/mailbox/qcom,cpucp-mbox.yaml20993F: Documentation/devicetree/bindings/mailbox/qcom,cpucp-mbox.yaml
arch/x86/kernel/crash.c+19−6
@@ -165,14 +165,23 @@ static struct crash_mem *fill_up_crash_elf_data(void) · 164 unmodified lines
165 /*165 /*
166 * Exclusion of crash region, crashk_low_res and/or crashk_cma_ranges166 * Exclusion of crash region, crashk_low_res and/or crashk_cma_ranges
167 * may cause range splits. So add extra slots here.167 * may cause range splits. So add extra slots here.
168 *
169 * Exclusion of low 1M may not cause another range split, because the
170 * range of exclude is [0, 1M] and the condition for splitting a new
171 * region is that the start, end parameters are both in a certain
172 * existing region in cmem and cannot be equal to existing region's
173 * start or end. Obviously, the start of [0, 1M] cannot meet this
174 * condition.
175 *
176 * But in order to lest the low 1M could be changed in the future,
177 * (e.g. [start, 1M]), add a extra slot.
168 */178 */
169 nr_ranges += 2 + crashk_cma_cnt;179 nr_ranges += 3 + crashk_cma_cnt;
170 cmem = vzalloc(struct_size(cmem, ranges, nr_ranges));180 cmem = vzalloc(struct_size(cmem, ranges, nr_ranges));
171 if (!cmem)181 if (!cmem)
172 return NULL;182 return NULL;
173 183
174 cmem->max_nr_ranges = nr_ranges;184 cmem->max_nr_ranges = nr_ranges;
175 cmem->nr_ranges = 0;
176 185
177 return cmem;186 return cmem;
178}187}
@@ -323,16 +332,20 @@ int crash_setup_memmap_entries(struct kimage *image, struct boot_params *params) · 144 unmodified lines
323 struct crash_mem *cmem;332 struct crash_mem *cmem;
324 333
325 /*334 /*
326 * Using random kexec_buf for passing dm crypt keys may cause a range335 * In the current x86 architecture code, the elfheader is always
327 * split. So use two slots here.336 * allocated at crashk_res.start. But it depends on the allocation
337 * position of elfheader in crashk_res. To avoid potential out of
338 * bounds in future, add an extra slot.
339 *
340 * And using random kexec_buf for passing dm crypt keys may cause a
341 * range split too, add another extra slot here.
328 */342 */
329 nr_ranges = 2;343 nr_ranges = 3;
330 cmem = vzalloc(struct_size(cmem, ranges, nr_ranges));344 cmem = vzalloc(struct_size(cmem, ranges, nr_ranges));
331 if (!cmem)345 if (!cmem)
332 return -ENOMEM;346 return -ENOMEM;
333 347
334 cmem->max_nr_ranges = nr_ranges;348 cmem->max_nr_ranges = nr_ranges;
335 cmem->nr_ranges = 0;
336 349
337 memset(&cmd, 0, sizeof(struct crash_memmap_data));350 memset(&cmd, 0, sizeof(struct crash_memmap_data));
338 cmd.params = params;351 cmd.params = params;
arch/x86/kernel/kexec-bzimage64.c+44−3
@@ -16,6 +16,8 @@ · 15 unmodified lines
16#include <linux/kexec.h>16#include <linux/kexec.h>
17#include <linux/kernel.h>17#include <linux/kernel.h>
18#include <linux/mm.h>18#include <linux/mm.h>
19#include <linux/libfdt.h>
20#include <linux/of_fdt.h>
19#include <linux/efi.h>21#include <linux/efi.h>
20#include <linux/random.h>22#include <linux/random.h>
21 23
@@ -212,6 +214,28 @@ setup_efi_state(struct boot_params *params, unsigned long params_load_addr, · 190 unmodified lines
212}214}
213#endif /* CONFIG_EFI */215#endif /* CONFIG_EFI */
214 216
217#ifdef CONFIG_OF_FLATTREE
218static void setup_dtb(struct boot_params *params,
219 unsigned long params_load_addr,
220 unsigned int dtb_setup_data_offset)
221{
222 struct setup_data *sd = (void *)params + dtb_setup_data_offset;
223 unsigned long setup_data_phys, dtb_len;
224
225 dtb_len = fdt_totalsize(initial_boot_params);
226 sd->type = SETUP_DTB;
227 sd->len = dtb_len;
228
229 /* Carry over current boot DTB with setup_data */
230 memcpy(sd->data, initial_boot_params, dtb_len);
231
232 /* Add setup data */
233 setup_data_phys = params_load_addr + dtb_setup_data_offset;
234 sd->next = params->hdr.setup_data;
235 params->hdr.setup_data = setup_data_phys;
236}
237#endif /* CONFIG_OF_FLATTREE */
238
215static void239static void
216setup_ima_state(const struct kimage *image, struct boot_params *params,240setup_ima_state(const struct kimage *image, struct boot_params *params,
217 unsigned long params_load_addr,241 unsigned long params_load_addr,
@@ -336,6 +360,17 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params, · 118 unmodified lines
336 sizeof(struct efi_setup_data);360 sizeof(struct efi_setup_data);
337#endif361#endif
338 362
363#ifdef CONFIG_OF_FLATTREE
364 if (image->force_dtb && initial_boot_params) {
365 setup_dtb(params, params_load_addr, setup_data_offset);
366 setup_data_offset += sizeof(struct setup_data) +
367 fdt_totalsize(initial_boot_params);
368 } else {
369 pr_debug("Not carrying over DTB, force_dtb = %d\n",
370 image->force_dtb);
371 }
372#endif
373
339 if (IS_ENABLED(CONFIG_IMA_KEXEC)) {374 if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
340 /* Setup IMA log buffer state */375 /* Setup IMA log buffer state */
341 setup_ima_state(image, params, params_load_addr,376 setup_ima_state(image, params, params_load_addr,
@@ -529,6 +564,12 @@ static void *bzImage64_load(struct kimage *image, char *kernel, · 187 unmodified lines
529 sizeof(struct setup_data) +564 sizeof(struct setup_data) +
530 RNG_SEED_LENGTH;565 RNG_SEED_LENGTH;
531 566
567#ifdef CONFIG_OF_FLATTREE
568 if (image->force_dtb && initial_boot_params)
569 kbuf.bufsz += sizeof(struct setup_data) +
570 fdt_totalsize(initial_boot_params);
571#endif
572
532 if (IS_ENABLED(CONFIG_IMA_KEXEC))573 if (IS_ENABLED(CONFIG_IMA_KEXEC))
533 kbuf.bufsz += sizeof(struct setup_data) +574 kbuf.bufsz += sizeof(struct setup_data) +
534 sizeof(struct ima_setup_data);575 sizeof(struct ima_setup_data);
@@ -537,7 +578,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel, · 2 unmodified lines
537 kbuf.bufsz += sizeof(struct setup_data) +578 kbuf.bufsz += sizeof(struct setup_data) +
538 sizeof(struct kho_data);579 sizeof(struct kho_data);
539 580
540 params = kzalloc(kbuf.bufsz, GFP_KERNEL);581 params = kvzalloc(kbuf.bufsz, GFP_KERNEL);
541 if (!params)582 if (!params)
542 return ERR_PTR(-ENOMEM);583 return ERR_PTR(-ENOMEM);
543 efi_map_offset = params_cmdline_sz;584 efi_map_offset = params_cmdline_sz;
@@ -647,7 +688,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel, · 103 unmodified lines
647 return ldata;688 return ldata;
648 689
649out_free_params:690out_free_params:
650 kfree(params);691 kvfree(params);
651 return ERR_PTR(ret);692 return ERR_PTR(ret);
652}693}
653 694
@@ -659,7 +700,7 @@ static int bzImage64_cleanup(void *loader_data) · 5 unmodified lines
659 if (!ldata)700 if (!ldata)
660 return 0;701 return 0;
661 702
662 kfree(ldata->bootparams_buf);703 kvfree(ldata->bootparams_buf);
663 ldata->bootparams_buf = NULL;704 ldata->bootparams_buf = NULL;
664 705
665 return 0;706 return 0;
drivers/firmware/efi/efi-init.c+25−4
@@ -12,6 +12,7 @@ · 11 unmodified lines
12#include <linux/efi.h>12#include <linux/efi.h>
13#include <linux/fwnode.h>13#include <linux/fwnode.h>
14#include <linux/init.h>14#include <linux/init.h>
15#include <linux/kexec_handover.h>
15#include <linux/memblock.h>16#include <linux/memblock.h>
16#include <linux/mm_types.h>17#include <linux/mm_types.h>
17#include <linux/of.h>18#include <linux/of.h>
@@ -164,12 +165,32 @@ static __init void reserve_regions(void) · 146 unmodified lines
164 pr_info("Processing EFI memory map:\n");165 pr_info("Processing EFI memory map:\n");
165 166
166 /*167 /*
167 * Discard memblocks discovered so far: if there are any at this168 * Discard memblocks discovered so far except for KHO scratch
168 * point, they originate from memory nodes in the DT, and UEFI169 * regions. Most memblocks at this point originate from memory nodes
169 * uses its own memory map instead.170 * in the DT and UEFI uses its own memory map instead. However, if
171 * KHO is enabled, scratch regions, which are good known memory
172 * must be preserved.
170 */173 */
171 memblock_dump_all();174 memblock_dump_all();
172 memblock_remove(0, PHYS_ADDR_MAX);175
176 if (is_kho_boot()) {
177 struct memblock_region *r;
178
179 /* Remove all non-KHO regions */
180 for_each_mem_region(r) {
181 if (!memblock_is_kho_scratch(r)) {
182 memblock_remove(r->base, r->size);
183 r--;
184 }
185 }
186 } else {
187 /*
188 * KHO is disabled. Discard memblocks discovered so far:
189 * if there are any at this point, they originate from memory
190 * nodes in the DT, and UEFI uses its own memory map instead.
191 */
192 memblock_remove(0, PHYS_ADDR_MAX);
193 }
173 194
174 for_each_efi_memory_desc(md) {195 for_each_efi_memory_desc(md) {
175 paddr = md->phys_addr;196 paddr = md->phys_addr;
drivers/video/fbdev/core/fbcon.c+1−8
@@ -279,14 +279,7 @@ static int fbcon_get_rotate(struct fb_info *info) · 278 unmodified lines
279 279
280static bool fbcon_skip_panic(struct fb_info *info)280static bool fbcon_skip_panic(struct fb_info *info)
281{281{
282/* panic_cpu is not exported, and can't be used if built as module. Use282 return (info->skip_panic && unlikely(panic_in_progress()));
283 * oops_in_progress instead, but non-fatal oops won't be printed.
284 */
285#if defined(MODULE)
286 return (info->skip_panic && unlikely(oops_in_progress));
287#else
288 return (info->skip_panic && unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID));
289#endif
290}283}
291 284
292static inline bool fbcon_is_active(struct vc_data *vc, struct fb_info *info)285static inline bool fbcon_is_active(struct vc_data *vc, struct fb_info *info)
fs/cramfs/inode.c+1−1
@@ -421,7 +421,7 @@ static int cramfs_physmem_mmap(struct file *file, struct vm_area_struct *vma) · 420 unmodified lines
421 vm_fault_t vmf;421 vm_fault_t vmf;
422 unsigned long off = i * PAGE_SIZE;422 unsigned long off = i * PAGE_SIZE;
423 vmf = vmf_insert_mixed(vma, vma->vm_start + off,423 vmf = vmf_insert_mixed(vma, vma->vm_start + off,
424 address + off);424 PHYS_PFN(address + off));
425 if (vmf & VM_FAULT_ERROR)425 if (vmf & VM_FAULT_ERROR)
426 ret = vm_fault_to_errno(vmf, 0);426 ret = vm_fault_to_errno(vmf, 0);
427 }427 }
fs/fat/dir.c+3−4
@@ -1209,7 +1209,7 @@ EXPORT_SYMBOL_GPL(fat_alloc_new_dir); · 1208 unmodified lines
1209 1209
1210static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots,1210static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots,
1211 int *nr_cluster, struct msdos_dir_entry **de,1211 int *nr_cluster, struct msdos_dir_entry **de,
1212 struct buffer_head **bh, loff_t *i_pos)1212 struct buffer_head **bh)
1213{1213{
1214 struct super_block *sb = dir->i_sb;1214 struct super_block *sb = dir->i_sb;
1215 struct msdos_sb_info *sbi = MSDOS_SB(sb);1215 struct msdos_sb_info *sbi = MSDOS_SB(sb);
@@ -1269,7 +1269,6 @@ static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots, · 53 unmodified lines
1269 get_bh(bhs[n]);1269 get_bh(bhs[n]);
1270 *bh = bhs[n];1270 *bh = bhs[n];
1271 *de = (struct msdos_dir_entry *)((*bh)->b_data + offset);1271 *de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
1272 *i_pos = fat_make_i_pos(sb, *bh, *de);
1273 1272
1274 /* Second stage: clear the rest of cluster, and write outs */1273 /* Second stage: clear the rest of cluster, and write outs */
1275 err = fat_zeroed_cluster(dir, start_blknr, ++n, bhs, MAX_BUF_PER_PAGE);1274 err = fat_zeroed_cluster(dir, start_blknr, ++n, bhs, MAX_BUF_PER_PAGE);
@@ -1298,7 +1297,7 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots, · 22 unmodified lines
1298 struct buffer_head *bh, *prev, *bhs[3]; /* 32*slots (672bytes) */1297 struct buffer_head *bh, *prev, *bhs[3]; /* 32*slots (672bytes) */
1299 struct msdos_dir_entry *de;1298 struct msdos_dir_entry *de;
1300 int err, free_slots, i, nr_bhs;1299 int err, free_slots, i, nr_bhs;
1301 loff_t pos, i_pos;1300 loff_t pos;
1302 1301
1303 sinfo->nr_slots = nr_slots;1302 sinfo->nr_slots = nr_slots;
1304 1303
@@ -1386,7 +1385,7 @@ found: · 81 unmodified lines
1386 * add the cluster to dir.1385 * add the cluster to dir.
1387 */1386 */
1388 cluster = fat_add_new_entries(dir, slots, nr_slots, &nr_cluster,1387 cluster = fat_add_new_entries(dir, slots, nr_slots, &nr_cluster,
1389 &de, &bh, &i_pos);1388 &de, &bh);
1390 if (cluster < 0) {1389 if (cluster < 0) {
1391 err = cluster;1390 err = cluster;
1392 goto error_remove;1391 goto error_remove;
fs/ocfs2/alloc.c+1−2
@@ -6928,8 +6928,7 @@ static int ocfs2_grab_folios(struct inode *inode, loff_t start, loff_t end, · 6927 unmodified lines
6928 6928
6929out:6929out:
6930 if (ret != 0) {6930 if (ret != 0) {
6931 if (folios)6931 ocfs2_unlock_and_free_folios(folios, numfolios);
6932 ocfs2_unlock_and_free_folios(folios, numfolios);
6933 numfolios = 0;6932 numfolios = 0;
6934 }6933 }
6935 6934
fs/ocfs2/dlm/dlmmaster.c+0−11
@@ -1477,7 +1477,6 @@ way_up_top: · 1476 unmodified lines
1477 goto send_response;1477 goto send_response;
1478 } else if (res->owner != DLM_LOCK_RES_OWNER_UNKNOWN) {1478 } else if (res->owner != DLM_LOCK_RES_OWNER_UNKNOWN) {
1479 spin_unlock(&res->spinlock);1479 spin_unlock(&res->spinlock);
1480 // mlog(0, "node %u is the master\n", res->owner);
1481 response = DLM_MASTER_RESP_NO;1480 response = DLM_MASTER_RESP_NO;
1482 if (mle)1481 if (mle)
1483 kmem_cache_free(dlm_mle_cache, mle);1482 kmem_cache_free(dlm_mle_cache, mle);
@@ -1493,7 +1492,6 @@ way_up_top: · 9 unmodified lines
1493 BUG();1492 BUG();
1494 }1493 }
1495 1494
1496 // mlog(0, "lockres is in progress...\n");
1497 spin_lock(&dlm->master_lock);1495 spin_lock(&dlm->master_lock);
1498 found = dlm_find_mle(dlm, &tmpmle, name, namelen);1496 found = dlm_find_mle(dlm, &tmpmle, name, namelen);
1499 if (!found) {1497 if (!found) {
@@ -1503,8 +1501,6 @@ way_up_top: · 3 unmodified lines
1503 set_maybe = 1;1501 set_maybe = 1;
1504 spin_lock(&tmpmle->spinlock);1502 spin_lock(&tmpmle->spinlock);
1505 if (tmpmle->type == DLM_MLE_BLOCK) {1503 if (tmpmle->type == DLM_MLE_BLOCK) {
1506 // mlog(0, "this node is waiting for "
1507 // "lockres to be mastered\n");
1508 response = DLM_MASTER_RESP_NO;1504 response = DLM_MASTER_RESP_NO;
1509 } else if (tmpmle->type == DLM_MLE_MIGRATION) {1505 } else if (tmpmle->type == DLM_MLE_MIGRATION) {
1510 mlog(0, "node %u is master, but trying to migrate to "1506 mlog(0, "node %u is master, but trying to migrate to "
@@ -1531,8 +1527,6 @@ way_up_top: · 20 unmodified lines
1531 } else1527 } else
1532 response = DLM_MASTER_RESP_NO;1528 response = DLM_MASTER_RESP_NO;
1533 } else {1529 } else {
1534 // mlog(0, "this node is attempting to "
1535 // "master lockres\n");
1536 response = DLM_MASTER_RESP_MAYBE;1530 response = DLM_MASTER_RESP_MAYBE;
1537 }1531 }
1538 if (set_maybe)1532 if (set_maybe)
@@ -1559,7 +1553,6 @@ way_up_top: · 20 unmodified lines
1559 found = dlm_find_mle(dlm, &tmpmle, name, namelen);1553 found = dlm_find_mle(dlm, &tmpmle, name, namelen);
1560 if (!found) {1554 if (!found) {
1561 /* this lockid has never been seen on this node yet */1555 /* this lockid has never been seen on this node yet */
1562 // mlog(0, "no mle found\n");
1563 if (!mle) {1556 if (!mle) {
1564 spin_unlock(&dlm->master_lock);1557 spin_unlock(&dlm->master_lock);
1565 spin_unlock(&dlm->spinlock);1558 spin_unlock(&dlm->spinlock);
@@ -1573,8 +1566,6 @@ way_up_top: · 7 unmodified lines
1573 goto way_up_top;1566 goto way_up_top;
1574 }1567 }
1575 1568
1576 // mlog(0, "this is second time thru, already allocated, "
1577 // "add the block.\n");
1578 dlm_init_mle(mle, DLM_MLE_BLOCK, dlm, NULL, name, namelen);1569 dlm_init_mle(mle, DLM_MLE_BLOCK, dlm, NULL, name, namelen);
1579 set_bit(request->node_idx, mle->maybe_map);1570 set_bit(request->node_idx, mle->maybe_map);
1580 __dlm_insert_mle(dlm, mle);1571 __dlm_insert_mle(dlm, mle);
@@ -1897,8 +1888,6 @@ ok: · 316 unmodified lines
1897 spin_unlock(&res->spinlock);1888 spin_unlock(&res->spinlock);
1898 }1889 }
1899 1890
1900 // mlog(0, "woo! got an assert_master from node %u!\n",
1901 // assert->node_idx);
1902 if (mle) {1891 if (mle) {
1903 int extra_ref = 0;1892 int extra_ref = 0;
1904 int nn = -1;1893 int nn = -1;
fs/ocfs2/dlm/dlmrecovery.c+0−1
@@ -464,7 +464,6 @@ static int dlm_do_recovery(struct dlm_ctxt *dlm) · 463 unmodified lines
464 }464 }
465 465
466 if (dlm->reco.dead_node == O2NM_INVALID_NODE_NUM) {466 if (dlm->reco.dead_node == O2NM_INVALID_NODE_NUM) {
467 // mlog(0, "nothing to recover! sleeping now!\n");
468 spin_unlock(&dlm->spinlock);467 spin_unlock(&dlm->spinlock);
469 /* return to main thread loop and sleep. */468 /* return to main thread loop and sleep. */
470 return 0;469 return 0;
fs/ocfs2/inode.c+8−0
@@ -1495,6 +1495,14 @@ int ocfs2_validate_inode_block(struct super_block *sb, · 1494 unmodified lines
1495 goto bail;1495 goto bail;
1496 }1496 }
1497 1497
1498 if (le16_to_cpu(di->i_suballoc_slot) != (u16)OCFS2_INVALID_SLOT &&
1499 (u32)le16_to_cpu(di->i_suballoc_slot) > OCFS2_SB(sb)->max_slots - 1) {
1500 rc = ocfs2_error(sb, "Invalid dinode %llu: suballoc slot %u\n",
1501 (unsigned long long)bh->b_blocknr,
1502 le16_to_cpu(di->i_suballoc_slot));
1503 goto bail;
1504 }
1505
1498 rc = 0;1506 rc = 0;
1499 1507
1500bail:1508bail:
fs/ocfs2/ioctl.c+7−11
@@ -358,13 +358,11 @@ static int ocfs2_info_handle_freeinode(struct inode *inode, · 357 unmodified lines
358 goto bail;358 goto bail;
359 }359 }
360 } else {360 } else {
361 ocfs2_sprintf_system_inode_name(namebuf,361 int len = ocfs2_sprintf_system_inode_name(namebuf,
362 sizeof(namebuf),362 sizeof(namebuf),
363 type, i);363 type, i);
364 status = ocfs2_lookup_ino_from_name(osb->sys_root_inode,364 status = ocfs2_lookup_ino_from_name(osb->sys_root_inode,
365 namebuf,365 namebuf, len, &blkno);
366 strlen(namebuf),
367 &blkno);
368 if (status < 0) {366 if (status < 0) {
369 status = -ENOENT;367 status = -ENOENT;
370 goto bail;368 goto bail;
@@ -651,12 +649,10 @@ static int ocfs2_info_handle_freefrag(struct inode *inode, · 280 unmodified lines
651 goto bail;649 goto bail;
652 }650 }
653 } else {651 } else {
654 ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type,652 int len = ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf),
655 OCFS2_INVALID_SLOT);653 type, OCFS2_INVALID_SLOT);
656 status = ocfs2_lookup_ino_from_name(osb->sys_root_inode,654 status = ocfs2_lookup_ino_from_name(osb->sys_root_inode,
657 namebuf,655 namebuf, len, &blkno);
658 strlen(namebuf),
659 &blkno);
660 if (status < 0) {656 if (status < 0) {
661 status = -ENOENT;657 status = -ENOENT;
662 goto bail;658 goto bail;
fs/ocfs2/move_extents.c+4−4
@@ -364,7 +364,7 @@ static int ocfs2_find_victim_alloc_group(struct inode *inode, · 363 unmodified lines
364 int *vict_bit,364 int *vict_bit,
365 struct buffer_head **ret_bh)365 struct buffer_head **ret_bh)
366{366{
367 int ret, i, bits_per_unit = 0;367 int ret, i, len, bits_per_unit = 0;
368 u64 blkno;368 u64 blkno;
369 char namebuf[40];369 char namebuf[40];
370 370
@@ -375,9 +375,9 @@ static int ocfs2_find_victim_alloc_group(struct inode *inode, · 4 unmodified lines
375 struct ocfs2_dinode *ac_dinode;375 struct ocfs2_dinode *ac_dinode;
376 struct ocfs2_group_desc *bg;376 struct ocfs2_group_desc *bg;
377 377
378 ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type, slot);378 len = ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type, slot);
379 ret = ocfs2_lookup_ino_from_name(osb->sys_root_inode, namebuf,379 ret = ocfs2_lookup_ino_from_name(osb->sys_root_inode, namebuf, len, &blkno);
380 strlen(namebuf), &blkno);380
381 if (ret) {381 if (ret) {
382 ret = -ENOENT;382 ret = -ENOENT;
383 goto out;383 goto out;
fs/ocfs2/ocfs2_fs.h+1−1
@@ -614,7 +614,7 @@ struct ocfs2_super_block { · 613 unmodified lines
614 __le16 s_reserved0;614 __le16 s_reserved0;
615 __le32 s_dx_seed[3]; /* seed[0-2] for dx dir hash.615 __le32 s_dx_seed[3]; /* seed[0-2] for dx dir hash.
616 * s_uuid_hash serves as seed[3]. */616 * s_uuid_hash serves as seed[3]. */
617/*C0*/ __le64 s_reserved2[15]; /* Fill out superblock */617/*C8*/ __le64 s_reserved2[15]; /* Fill out superblock */
618/*140*/618/*140*/
619 619
620 /*620 /*
fs/ocfs2/stack_user.c+1−0
@@ -1011,6 +1011,7 @@ static int user_cluster_connect(struct ocfs2_cluster_connection *conn) · 1010 unmodified lines
1011 printk(KERN_ERR "ocfs2: Could not determine"1011 printk(KERN_ERR "ocfs2: Could not determine"
1012 " locking version\n");1012 " locking version\n");
1013 user_cluster_disconnect(conn);1013 user_cluster_disconnect(conn);
1014 lc = NULL;
1014 goto out;1015 goto out;
1015 }1016 }
1016 wait_event(lc->oc_wait, (atomic_read(&lc->oc_this_node) > 0));1017 wait_event(lc->oc_wait, (atomic_read(&lc->oc_this_node) > 0));
fs/ocfs2/sysfile.c+6−6
@@ -127,14 +127,14 @@ static struct inode * _ocfs2_get_system_file_inode(struct ocfs2_super *osb, · 126 unmodified lines
127 char namebuf[40];127 char namebuf[40];
128 struct inode *inode = NULL;128 struct inode *inode = NULL;
129 u64 blkno;129 u64 blkno;
130 int status = 0;130 int len, status = 0;
131 131
132 ocfs2_sprintf_system_inode_name(namebuf,132 len = ocfs2_sprintf_system_inode_name(namebuf,
133 sizeof(namebuf),133 sizeof(namebuf),
134 type, slot);134 type, slot);
135 135
136 status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, namebuf,136 status = ocfs2_lookup_ino_from_name(osb->sys_root_inode,
137 strlen(namebuf), &blkno);137 namebuf, len, &blkno);
138 if (status < 0) {138 if (status < 0) {
139 goto bail;139 goto bail;
140 }140 }
fs/proc/base.c+1−1
@@ -3947,7 +3947,7 @@ static int proc_task_readdir(struct file *file, struct dir_context *ctx) · 3946 unmodified lines
3947 tid = task_pid_nr_ns(task, ns);3947 tid = task_pid_nr_ns(task, ns);
3948 if (!tid)3948 if (!tid)
3949 continue; /* The task has just exited. */3949 continue; /* The task has just exited. */
3950 len = snprintf(name, sizeof(name), "%u", tid);3950 len = snprintf(name, sizeof(name), "%d", tid);
3951 if (!proc_fill_cache(file, ctx, name, len,3951 if (!proc_fill_cache(file, ctx, name, len,
3952 proc_task_instantiate, task, NULL)) {3952 proc_task_instantiate, task, NULL)) {
3953 /* returning this tgid failed, save it as the first3953 /* returning this tgid failed, save it as the first
fs/squashfs/file.c+126−11
@@ -307,7 +307,8 @@ static int fill_meta_index(struct inode *inode, int index, · 306 unmodified lines
307all_done:307all_done:
308 *index_block = cur_index_block;308 *index_block = cur_index_block;
309 *index_offset = cur_offset;309 *index_offset = cur_offset;
310 *data_block = cur_data_block;310 if (data_block)
311 *data_block = cur_data_block;
311 312
312 /*313 /*
313 * Scale cache index (cache slot entry) to index314 * Scale cache index (cache slot entry) to index
@@ -324,17 +325,15 @@ failed: · 10 unmodified lines
324 * Get the on-disk location and compressed size of the datablock325 * Get the on-disk location and compressed size of the datablock
325 * specified by index. Fill_meta_index() does most of the work.326 * specified by index. Fill_meta_index() does most of the work.
326 */327 */
327static int read_blocklist(struct inode *inode, int index, u64 *block)328static int read_blocklist_ptrs(struct inode *inode, int index, u64 *start,
329 int *offset, u64 *block)
328{330{
329 u64 start;
330 long long blks;331 long long blks;
331 int offset;
332 __le32 size;332 __le32 size;
333 int res = fill_meta_index(inode, index, &start, &offset, block);333 int res = fill_meta_index(inode, index, start, offset, block);
334 334
335 TRACE("read_blocklist: res %d, index %d, start 0x%llx, offset"335 TRACE("read_blocklist: res %d, index %d, start 0x%llx, offset 0x%x, block 0x%llx\n",
336 " 0x%x, block 0x%llx\n", res, index, start, offset,336 res, index, *start, *offset, block ? *block : 0);
337 *block);
338 337
339 if (res < 0)338 if (res < 0)
340 return res;339 return res;
@@ -346,22 +345,31 @@ static int read_blocklist(struct inode *inode, int index, u64 *block) · 5 unmodified lines
346 * extra block indexes needed.345 * extra block indexes needed.
347 */346 */
348 if (res < index) {347 if (res < index) {
349 blks = read_indexes(inode->i_sb, index - res, &start, &offset);348 blks = read_indexes(inode->i_sb, index - res, start, offset);
350 if (blks < 0)349 if (blks < 0)
351 return (int) blks;350 return (int) blks;
352 *block += blks;351 if (block)
352 *block += blks;
353 }353 }
354 354
355 /*355 /*
356 * Read length of block specified by index.356 * Read length of block specified by index.
357 */357 */
358 res = squashfs_read_metadata(inode->i_sb, &size, &start, &offset,358 res = squashfs_read_metadata(inode->i_sb, &size, start, offset,
359 sizeof(size));359 sizeof(size));
360 if (res < 0)360 if (res < 0)
361 return res;361 return res;
362 return squashfs_block_size(size);362 return squashfs_block_size(size);
363}363}
364 364
365static inline int read_blocklist(struct inode *inode, int index, u64 *block)
366{
367 u64 start;
368 int offset;
369
370 return read_blocklist_ptrs(inode, index, &start, &offset, block);
371}
372
365static bool squashfs_fill_page(struct folio *folio,373static bool squashfs_fill_page(struct folio *folio,
366 struct squashfs_cache_entry *buffer, size_t offset,374 struct squashfs_cache_entry *buffer, size_t offset,
367 size_t avail)375 size_t avail)
@@ -658,7 +666,114 @@ skip_pages: · 290 unmodified lines
658 kfree(pages);666 kfree(pages);
659}667}
660 668
669static loff_t seek_hole_data(struct file *file, loff_t offset, int whence)
670{
671 struct inode *inode = file->f_mapping->host;
672 struct super_block *sb = inode->i_sb;
673 struct squashfs_sb_info *msblk = sb->s_fs_info;
674 u64 start, index = offset >> msblk->block_log;
675 u64 file_end = (i_size_read(inode) + msblk->block_size - 1) >> msblk->block_log;
676 int s_offset, length;
677 __le32 *blist = NULL;
678
679 /* reject offset if negative or beyond file end */
680 if ((unsigned long long)offset >= i_size_read(inode))
681 return -ENXIO;
682
683 /* is offset within tailend and is tailend packed into a fragment? */
684 if (index + 1 == file_end &&
685 squashfs_i(inode)->fragment_block != SQUASHFS_INVALID_BLK) {
686 if (whence == SEEK_DATA)
687 return offset;
688
689 /* there is an implicit hole at the end of any file */
690 return i_size_read(inode);
691 }
692
693 length = read_blocklist_ptrs(inode, index, &start, &s_offset, NULL);
694 if (length < 0)
695 return length;
696
697 /* nothing more to do if offset matches desired whence value */
698 if ((length == 0 && whence == SEEK_HOLE) ||
699 (length && whence == SEEK_DATA))
700 return offset;
701
702 /* skip scanning forwards if we're at file end */
703 if (++ index == file_end)
704 goto not_found;
705
706 blist = kmalloc(SQUASHFS_SCAN_INDEXES << 2, GFP_KERNEL);
707 if (blist == NULL) {
708 ERROR("%s: Failed to allocate block_list\n", __func__);
709 return -ENOMEM;
710 }
711
712 while (index < file_end) {
713 int i, indexes = min(file_end - index, SQUASHFS_SCAN_INDEXES);
714
715 offset = squashfs_read_metadata(sb, blist, &start, &s_offset, indexes << 2);
716 if (offset < 0)
717 goto finished;
718
719 for (i = 0; i < indexes; i++) {
720 length = squashfs_block_size(blist[i]);
721 if (length < 0) {
722 offset = length;
723 goto finished;
724 }
725
726 /* does this block match desired whence value? */
727 if ((length == 0 && whence == SEEK_HOLE) ||
728 (length && whence == SEEK_DATA)) {
729 offset = (index + i) << msblk->block_log;
730 goto finished;
731 }
732 }
733
734 index += indexes;
735 }
736
737not_found:
738 /* whence value determines what happens */
739 if (whence == SEEK_DATA)
740 offset = -ENXIO;
741 else
742 /* there is an implicit hole at the end of any file */
743 offset = i_size_read(inode);
744
745finished:
746 kfree(blist);
747 return offset;
748}
749
750static loff_t squashfs_llseek(struct file *file, loff_t offset, int whence)
751{
752 struct inode *inode = file->f_mapping->host;
753
754 switch (whence) {
755 default:
756 return generic_file_llseek(file, offset, whence);
757 case SEEK_DATA:
758 case SEEK_HOLE:
759 offset = seek_hole_data(file, offset, whence);
760 break;
761 }
762
763 if (offset < 0)
764 return offset;
765
766 return vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
767}
768
661const struct address_space_operations squashfs_aops = {769const struct address_space_operations squashfs_aops = {
662 .read_folio = squashfs_read_folio,770 .read_folio = squashfs_read_folio,
663 .readahead = squashfs_readahead771 .readahead = squashfs_readahead
664};772};
773
774const struct file_operations squashfs_file_operations = {
775 .llseek = squashfs_llseek,
776 .read_iter = generic_file_read_iter,
777 .mmap_prepare = generic_file_readonly_mmap_prepare,
778 .splice_read = filemap_splice_read
779};
fs/squashfs/inode.c+35−4
@@ -68,6 +68,10 @@ static int squashfs_new_inode(struct super_block *sb, struct inode *inode, · 67 unmodified lines
68 inode->i_mode = le16_to_cpu(sqsh_ino->mode);68 inode->i_mode = le16_to_cpu(sqsh_ino->mode);
69 inode->i_size = 0;69 inode->i_size = 0;
70 70
71 /* File type must not be set at this moment, for it will later be set by the caller. */
72 if (inode->i_mode & S_IFMT)
73 err = -EIO;
74
71 return err;75 return err;
72}76}
73 77
@@ -140,8 +144,17 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 66 unmodified lines
140 if (err < 0)144 if (err < 0)
141 goto failed_read;145 goto failed_read;
142 146
147 inode->i_size = le32_to_cpu(sqsh_ino->file_size);
143 frag = le32_to_cpu(sqsh_ino->fragment);148 frag = le32_to_cpu(sqsh_ino->fragment);
144 if (frag != SQUASHFS_INVALID_FRAG) {149 if (frag != SQUASHFS_INVALID_FRAG) {
150 /*
151 * the file cannot have a fragment (tailend) and have a
152 * file size a multiple of the block size
153 */
154 if ((inode->i_size & (msblk->block_size - 1)) == 0) {
155 err = -EINVAL;
156 goto failed_read;
157 }
145 frag_offset = le32_to_cpu(sqsh_ino->offset);158 frag_offset = le32_to_cpu(sqsh_ino->offset);
146 frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);159 frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
147 if (frag_size < 0) {160 if (frag_size < 0) {
@@ -155,8 +168,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 7 unmodified lines
155 }168 }
156 169
157 set_nlink(inode, 1);170 set_nlink(inode, 1);
158 inode->i_size = le32_to_cpu(sqsh_ino->file_size);171 inode->i_fop = &squashfs_file_operations;
159 inode->i_fop = &generic_ro_fops;
160 inode->i_mode |= S_IFREG;172 inode->i_mode |= S_IFREG;
161 inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;173 inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
162 squashfs_i(inode)->fragment_block = frag_blk;174 squashfs_i(inode)->fragment_block = frag_blk;
@@ -165,6 +177,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 2 unmodified lines
165 squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);177 squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
166 squashfs_i(inode)->block_list_start = block;178 squashfs_i(inode)->block_list_start = block;
167 squashfs_i(inode)->offset = offset;179 squashfs_i(inode)->offset = offset;
180 squashfs_i(inode)->parent = 0;
168 inode->i_data.a_ops = &squashfs_aops;181 inode->i_data.a_ops = &squashfs_aops;
169 182
170 TRACE("File inode %x:%x, start_block %llx, block_list_start "183 TRACE("File inode %x:%x, start_block %llx, block_list_start "
@@ -183,8 +196,21 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 12 unmodified lines
183 if (err < 0)196 if (err < 0)
184 goto failed_read;197 goto failed_read;
185 198
199 inode->i_size = le64_to_cpu(sqsh_ino->file_size);
200 if (inode->i_size < 0) {
201 err = -EINVAL;
202 goto failed_read;
203 }
186 frag = le32_to_cpu(sqsh_ino->fragment);204 frag = le32_to_cpu(sqsh_ino->fragment);
187 if (frag != SQUASHFS_INVALID_FRAG) {205 if (frag != SQUASHFS_INVALID_FRAG) {
206 /*
207 * the file cannot have a fragment (tailend) and have a
208 * file size a multiple of the block size
209 */
210 if ((inode->i_size & (msblk->block_size - 1)) == 0) {
211 err = -EINVAL;
212 goto failed_read;
213 }
188 frag_offset = le32_to_cpu(sqsh_ino->offset);214 frag_offset = le32_to_cpu(sqsh_ino->offset);
189 frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);215 frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
190 if (frag_size < 0) {216 if (frag_size < 0) {
@@ -199,9 +225,8 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 8 unmodified lines
199 225
200 xattr_id = le32_to_cpu(sqsh_ino->xattr);226 xattr_id = le32_to_cpu(sqsh_ino->xattr);
201 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));227 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
202 inode->i_size = le64_to_cpu(sqsh_ino->file_size);
203 inode->i_op = &squashfs_inode_ops;228 inode->i_op = &squashfs_inode_ops;
204 inode->i_fop = &generic_ro_fops;229 inode->i_fop = &squashfs_file_operations;
205 inode->i_mode |= S_IFREG;230 inode->i_mode |= S_IFREG;
206 inode->i_blocks = (inode->i_size -231 inode->i_blocks = (inode->i_size -
207 le64_to_cpu(sqsh_ino->sparse) + 511) >> 9;232 le64_to_cpu(sqsh_ino->sparse) + 511) >> 9;
@@ -212,6 +237,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 4 unmodified lines
212 squashfs_i(inode)->start = le64_to_cpu(sqsh_ino->start_block);237 squashfs_i(inode)->start = le64_to_cpu(sqsh_ino->start_block);
213 squashfs_i(inode)->block_list_start = block;238 squashfs_i(inode)->block_list_start = block;
214 squashfs_i(inode)->offset = offset;239 squashfs_i(inode)->offset = offset;
240 squashfs_i(inode)->parent = 0;
215 inode->i_data.a_ops = &squashfs_aops;241 inode->i_data.a_ops = &squashfs_aops;
216 242
217 TRACE("File inode %x:%x, start_block %llx, block_list_start "243 TRACE("File inode %x:%x, start_block %llx, block_list_start "
@@ -292,6 +318,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 74 unmodified lines
292 inode->i_mode |= S_IFLNK;318 inode->i_mode |= S_IFLNK;
293 squashfs_i(inode)->start = block;319 squashfs_i(inode)->start = block;
294 squashfs_i(inode)->offset = offset;320 squashfs_i(inode)->offset = offset;
321 squashfs_i(inode)->parent = 0;
295 322
296 if (type == SQUASHFS_LSYMLINK_TYPE) {323 if (type == SQUASHFS_LSYMLINK_TYPE) {
297 __le32 xattr;324 __le32 xattr;
@@ -329,6 +356,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 31 unmodified lines
329 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));356 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
330 rdev = le32_to_cpu(sqsh_ino->rdev);357 rdev = le32_to_cpu(sqsh_ino->rdev);
331 init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));358 init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
359 squashfs_i(inode)->parent = 0;
332 360
333 TRACE("Device inode %x:%x, rdev %x\n",361 TRACE("Device inode %x:%x, rdev %x\n",
334 SQUASHFS_INODE_BLK(ino), offset, rdev);362 SQUASHFS_INODE_BLK(ino), offset, rdev);
@@ -353,6 +381,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 18 unmodified lines
353 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));381 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
354 rdev = le32_to_cpu(sqsh_ino->rdev);382 rdev = le32_to_cpu(sqsh_ino->rdev);
355 init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));383 init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
384 squashfs_i(inode)->parent = 0;
356 385
357 TRACE("Device inode %x:%x, rdev %x\n",386 TRACE("Device inode %x:%x, rdev %x\n",
358 SQUASHFS_INODE_BLK(ino), offset, rdev);387 SQUASHFS_INODE_BLK(ino), offset, rdev);
@@ -373,6 +402,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 14 unmodified lines
373 inode->i_mode |= S_IFSOCK;402 inode->i_mode |= S_IFSOCK;
374 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));403 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
375 init_special_inode(inode, inode->i_mode, 0);404 init_special_inode(inode, inode->i_mode, 0);
405 squashfs_i(inode)->parent = 0;
376 break;406 break;
377 }407 }
378 case SQUASHFS_LFIFO_TYPE:408 case SQUASHFS_LFIFO_TYPE:
@@ -392,6 +422,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 13 unmodified lines
392 inode->i_op = &squashfs_inode_ops;422 inode->i_op = &squashfs_inode_ops;
393 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));423 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
394 init_special_inode(inode, inode->i_mode, 0);424 init_special_inode(inode, inode->i_mode, 0);
425 squashfs_i(inode)->parent = 0;
395 break;426 break;
396 }427 }
397 default:428 default:
fs/squashfs/squashfs.h+1−0
@@ -107,6 +107,7 @@ extern const struct address_space_operations squashfs_aops; · 106 unmodified lines
107 107
108/* inode.c */108/* inode.c */
109extern const struct inode_operations squashfs_inode_ops;109extern const struct inode_operations squashfs_inode_ops;
110extern const struct file_operations squashfs_file_operations;
110 111
111/* namei.c */112/* namei.c */
112extern const struct inode_operations squashfs_dir_inode_ops;113extern const struct inode_operations squashfs_dir_inode_ops;
fs/squashfs/squashfs_fs.h+1−0
@@ -208,6 +208,7 @@ static inline int squashfs_block_size(__le32 raw) · 207 unmodified lines
208#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))208#define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
209#define SQUASHFS_META_ENTRIES 127209#define SQUASHFS_META_ENTRIES 127
210#define SQUASHFS_META_SLOTS 8210#define SQUASHFS_META_SLOTS 8
211#define SQUASHFS_SCAN_INDEXES 1024
211 212
212struct meta_entry {213struct meta_entry {
213 u64 data_block;214 u64 data_block;
fs/squashfs/squashfs_fs_i.h+1−1
@@ -16,6 +16,7 @@ struct squashfs_inode_info { · 15 unmodified lines
16 u64 xattr;16 u64 xattr;
17 unsigned int xattr_size;17 unsigned int xattr_size;
18 int xattr_count;18 int xattr_count;
19 int parent;
19 union {20 union {
20 struct {21 struct {
21 u64 fragment_block;22 u64 fragment_block;
@@ -27,7 +28,6 @@ struct squashfs_inode_info { · 5 unmodified lines
27 u64 dir_idx_start;28 u64 dir_idx_start;
28 int dir_idx_offset;29 int dir_idx_offset;
29 int dir_idx_cnt;30 int dir_idx_cnt;
30 int parent;
31 };31 };
32 };32 };
33 struct inode vfs_inode;33 struct inode vfs_inode;
include/linux/idr.h+0−8
@@ -334,14 +334,6 @@ static inline void ida_init(struct ida *ida) · 333 unmodified lines
334 xa_init_flags(&ida->xa, IDA_INIT_FLAGS);334 xa_init_flags(&ida->xa, IDA_INIT_FLAGS);
335}335}
336 336
337/*
338 * ida_simple_get() and ida_simple_remove() are deprecated. Use
339 * ida_alloc() and ida_free() instead respectively.
340 */
341#define ida_simple_get(ida, start, end, gfp) \
342 ida_alloc_range(ida, start, (end) - 1, gfp)
343#define ida_simple_remove(ida, id) ida_free(ida, id)
344
345static inline bool ida_is_empty(const struct ida *ida)337static inline bool ida_is_empty(const struct ida *ida)
346{338{
347 return xa_empty(&ida->xa);339 return xa_empty(&ida->xa);
include/linux/kernel.h+17−4
@@ -164,11 +164,23 @@ extern int root_mountflags; · 163 unmodified lines
164 164
165extern bool early_boot_irqs_disabled;165extern bool early_boot_irqs_disabled;
166 166
167/*167/**
168 * Values used for system_state. Ordering of the states must not be changed168 * enum system_states - Values used for system_state.
169 *
170 * @SYSTEM_BOOTING: %0, no init needed
171 * @SYSTEM_SCHEDULING: system is ready for scheduling; OK to use RCU
172 * @SYSTEM_FREEING_INITMEM: system is freeing all of initmem; almost running
173 * @SYSTEM_RUNNING: system is up and running
174 * @SYSTEM_HALT: system entered clean system halt state
175 * @SYSTEM_POWER_OFF: system entered shutdown/clean power off state
176 * @SYSTEM_RESTART: system entered emergency power off or normal restart
177 * @SYSTEM_SUSPEND: system entered suspend or hibernate state
178 *
179 * Note:
180 * Ordering of the states must not be changed
169 * as code checks for <, <=, >, >= STATE.181 * as code checks for <, <=, >, >= STATE.
170 */182 */
171extern enum system_states {183enum system_states {
172 SYSTEM_BOOTING,184 SYSTEM_BOOTING,
173 SYSTEM_SCHEDULING,185 SYSTEM_SCHEDULING,
174 SYSTEM_FREEING_INITMEM,186 SYSTEM_FREEING_INITMEM,
@@ -177,7 +189,8 @@ extern enum system_states { · 2 unmodified lines
177 SYSTEM_POWER_OFF,189 SYSTEM_POWER_OFF,
178 SYSTEM_RESTART,190 SYSTEM_RESTART,
179 SYSTEM_SUSPEND,191 SYSTEM_SUSPEND,
180} system_state;192};
193extern enum system_states system_state;
181 194
182/*195/*
183 * General tracing related utility functions - trace_printk(),196 * General tracing related utility functions - trace_printk(),
include/linux/kexec.h+4−1
@@ -395,6 +395,9 @@ struct kimage { · 394 unmodified lines
395 395
396 /* Information for loading purgatory */396 /* Information for loading purgatory */
397 struct purgatory_info purgatory_info;397 struct purgatory_info purgatory_info;
398
399 /* Force carrying over the DTB from the current boot */
400 bool force_dtb;
398#endif401#endif
399 402
400#ifdef CONFIG_CRASH_HOTPLUG403#ifdef CONFIG_CRASH_HOTPLUG
@@ -461,7 +464,7 @@ bool kexec_load_permitted(int kexec_image_type); · 60 unmodified lines
461/* List of defined/legal kexec file flags */464/* List of defined/legal kexec file flags */
462#define KEXEC_FILE_FLAGS (KEXEC_FILE_UNLOAD | KEXEC_FILE_ON_CRASH | \465#define KEXEC_FILE_FLAGS (KEXEC_FILE_UNLOAD | KEXEC_FILE_ON_CRASH | \
463 KEXEC_FILE_NO_INITRAMFS | KEXEC_FILE_DEBUG | \466 KEXEC_FILE_NO_INITRAMFS | KEXEC_FILE_DEBUG | \
464 KEXEC_FILE_NO_CMA)467 KEXEC_FILE_NO_CMA | KEXEC_FILE_FORCE_DTB)
465 468
466/* flag to track if kexec reboot is in progress */469/* flag to track if kexec reboot is in progress */
467extern bool kexec_in_progress;470extern bool kexec_in_progress;
include/linux/kexec_handover.h+6−0
@@ -40,6 +40,7 @@ struct kho_serialization; · 39 unmodified lines
40 40
41#ifdef CONFIG_KEXEC_HANDOVER41#ifdef CONFIG_KEXEC_HANDOVER
42bool kho_is_enabled(void);42bool kho_is_enabled(void);
43bool is_kho_boot(void);
43 44
44int kho_preserve_folio(struct folio *folio);45int kho_preserve_folio(struct folio *folio);
45int kho_preserve_phys(phys_addr_t phys, size_t size);46int kho_preserve_phys(phys_addr_t phys, size_t size);
@@ -60,6 +61,11 @@ static inline bool kho_is_enabled(void) · 14 unmodified lines
60 return false;61 return false;
61}62}
62 63
64static inline bool is_kho_boot(void)
65{
66 return false;
67}
68
63static inline int kho_preserve_folio(struct folio *folio)69static inline int kho_preserve_folio(struct folio *folio)
64{70{
65 return -EOPNOTSUPP;71 return -EOPNOTSUPP;
include/linux/list.h+8−0
@@ -20,8 +20,16 @@ · 19 unmodified lines
20 * using the generic single-entry routines.20 * using the generic single-entry routines.
21 */21 */
22 22
23/**
24 * LIST_HEAD_INIT - initialize a &struct list_head's links to point to itself
25 * @name: name of the list_head
26 */
23#define LIST_HEAD_INIT(name) { &(name), &(name) }27#define LIST_HEAD_INIT(name) { &(name), &(name) }
24 28
29/**
30 * LIST_HEAD - definition of a &struct list_head with initialization values
31 * @name: name of the list_head
32 */
25#define LIST_HEAD(name) \33#define LIST_HEAD(name) \
26 struct list_head name = LIST_HEAD_INIT(name)34 struct list_head name = LIST_HEAD_INIT(name)
27 35
include/linux/moduleparam.h+13−0
@@ -349,6 +349,19 @@ static inline void kernel_param_unlock(struct module *mod) · 348 unmodified lines
349 __module_param_call("", name, &param_ops_##type, &var, perm, \349 __module_param_call("", name, &param_ops_##type, &var, perm, \
350 -1, KERNEL_PARAM_FL_UNSAFE)350 -1, KERNEL_PARAM_FL_UNSAFE)
351 351
352/**
353 * __core_param_cb - similar like core_param, with a set/get ops instead of type.
354 * @name: the name of the cmdline and sysfs parameter (often the same as var)
355 * @var: the variable
356 * @ops: the set & get operations for this parameter.
357 * @perm: visibility in sysfs
358 *
359 * Ideally this should be called 'core_param_cb', but the name has been
360 * used for module core parameter, so add the '__' prefix
361 */
362#define __core_param_cb(name, ops, arg, perm) \
363 __module_param_call("", name, ops, arg, perm, -1, 0)
364
352#endif /* !MODULE */365#endif /* !MODULE */
353 366
354/**367/**
include/linux/nvmem-provider.h+1−1
@@ -103,7 +103,7 @@ struct nvmem_cell_info { · 102 unmodified lines
103 *103 *
104 * Note: A default "nvmem<id>" name will be assigned to the device if104 * Note: A default "nvmem<id>" name will be assigned to the device if
105 * no name is specified in its configuration. In such case "<id>" is105 * no name is specified in its configuration. In such case "<id>" is
106 * generated with ida_simple_get() and provided id field is ignored.106 * generated with ida_alloc() and provided id field is ignored.
107 *107 *
108 * Note: Specifying name and setting id to -1 implies a unique device108 * Note: Specifying name and setting id to -1 implies a unique device
109 * whose name is provided as-is (kept unaltered).109 * whose name is provided as-is (kept unaltered).
include/linux/panic.h+6−0
@@ -43,6 +43,12 @@ void abort(void); · 42 unmodified lines
43extern atomic_t panic_cpu;43extern atomic_t panic_cpu;
44#define PANIC_CPU_INVALID -144#define PANIC_CPU_INVALID -1
45 45
46bool panic_try_start(void);
47void panic_reset(void);
48bool panic_in_progress(void);
49bool panic_on_this_cpu(void);
50bool panic_on_other_cpu(void);
51
46/*52/*
47 * Only to be used by arch init code. If the user over-wrote the default53 * Only to be used by arch init code. If the user over-wrote the default
48 * CONFIG_PANIC_TIMEOUT, honor it.54 * CONFIG_PANIC_TIMEOUT, honor it.
include/linux/printk.h+0−2
@@ -330,8 +330,6 @@ static inline bool pr_flush(int timeout_ms, bool reset_on_progress) · 329 unmodified lines
330 330
331#endif331#endif
332 332
333bool this_cpu_in_panic(void);
334
335#ifdef CONFIG_SMP333#ifdef CONFIG_SMP
336extern int __printk_cpu_sync_try_get(void);334extern int __printk_cpu_sync_try_get(void);
337extern void __printk_cpu_sync_wait(void);335extern void __printk_cpu_sync_wait(void);
include/linux/sched/task.h+2−3
@@ -210,9 +210,8 @@ static inline struct vm_struct *task_stack_vm_area(const struct task_struct *t) · 209 unmodified lines
210 * pins the final release of task.io_context. Also protects ->cpuset and210 * pins the final release of task.io_context. Also protects ->cpuset and
211 * ->cgroup.subsys[]. And ->vfork_done. And ->sysvshm.shm_clist.211 * ->cgroup.subsys[]. And ->vfork_done. And ->sysvshm.shm_clist.
212 *212 *
213 * Nests both inside and outside of read_lock(&tasklist_lock).213 * Nests inside of read_lock(&tasklist_lock). It must not be nested with
214 * It must not be nested with write_lock_irq(&tasklist_lock),214 * write_lock_irq(&tasklist_lock), neither inside nor outside.
215 * neither inside nor outside.
216 */215 */
217static inline void task_lock(struct task_struct *p)216static inline void task_lock(struct task_struct *p)
218{217{
include/uapi/linux/kexec.h+4−0
@@ -22,12 +22,16 @@ · 21 unmodified lines
22 * KEXEC_FILE_ON_CRASH : Load/unload operation belongs to kdump image.22 * KEXEC_FILE_ON_CRASH : Load/unload operation belongs to kdump image.
23 * KEXEC_FILE_NO_INITRAMFS : No initramfs is being loaded. Ignore the initrd23 * KEXEC_FILE_NO_INITRAMFS : No initramfs is being loaded. Ignore the initrd
24 * fd field.24 * fd field.
25 * KEXEC_FILE_FORCE_DTB : Force carrying over the current boot's DTB to the new
26 * kernel on x86. This is already the default behavior on
27 * some other architectures, like ARM64 and PowerPC.
25 */28 */
26#define KEXEC_FILE_UNLOAD 0x0000000129#define KEXEC_FILE_UNLOAD 0x00000001
27#define KEXEC_FILE_ON_CRASH 0x0000000230#define KEXEC_FILE_ON_CRASH 0x00000002
28#define KEXEC_FILE_NO_INITRAMFS 0x0000000431#define KEXEC_FILE_NO_INITRAMFS 0x00000004
29#define KEXEC_FILE_DEBUG 0x0000000832#define KEXEC_FILE_DEBUG 0x00000008
30#define KEXEC_FILE_NO_CMA 0x0000001033#define KEXEC_FILE_NO_CMA 0x00000010
34#define KEXEC_FILE_FORCE_DTB 0x00000020
31 35
32/* These values match the ELF architecture values.36/* These values match the ELF architecture values.
33 * Unless there is a good reason that should continue to be the case.37 * Unless there is a good reason that should continue to be the case.
init/main.c+12−0
@@ -545,6 +545,12 @@ static int __init unknown_bootoption(char *param, char *val, · 544 unmodified lines
545 const char *unused, void *arg)545 const char *unused, void *arg)
546{546{
547 size_t len = strlen(param);547 size_t len = strlen(param);
548 /*
549 * Well-known bootloader identifiers:
550 * 1. LILO/Grub pass "BOOT_IMAGE=...";
551 * 2. kexec/kdump (kexec-tools) pass "kexec".
552 */
553 const char *bootloader[] = { "BOOT_IMAGE=", "kexec", NULL };
548 554
549 /* Handle params aliased to sysctls */555 /* Handle params aliased to sysctls */
550 if (sysctl_is_alias(param))556 if (sysctl_is_alias(param))
@@ -552,6 +558,12 @@ static int __init unknown_bootoption(char *param, char *val, · 1 unmodified line
552 558
553 repair_env_string(param, val);559 repair_env_string(param, val);
554 560
561 /* Handle bootloader identifier */
562 for (int i = 0; bootloader[i]; i++) {
563 if (strstarts(param, bootloader[i]))
564 return 0;
565 }
566
555 /* Handle obsolete-style parameters */567 /* Handle obsolete-style parameters */
556 if (obsolete_checksetup(param))568 if (obsolete_checksetup(param))
557 return 0;569 return 0;
kernel/Kconfig.kexec+11−0
@@ -148,6 +148,17 @@ config CRASH_DM_CRYPT_CONFIGS · 147 unmodified lines
148 CRASH_DM_CRYPT cannot directly select CONFIGFS_FS, because that148 CRASH_DM_CRYPT cannot directly select CONFIGFS_FS, because that
149 is required to be built-in.149 is required to be built-in.
150 150
151config CRASH_DUMP_KUNIT_TEST
152 tristate "Unit Tests for kernel crash dumps" if !KUNIT_ALL_TESTS
153 depends on CRASH_DUMP && KUNIT
154 default KUNIT_ALL_TESTS
155 help
156 This option builds KUnit unit tests for kernel crash dumps. The unit
157 tests will be used to verify the correctness of covered functions and
158 also prevent any regression.
159
160 If unsure, say N.
161
151config CRASH_HOTPLUG162config CRASH_HOTPLUG
152 bool "Update the crash elfcorehdr on system configuration changes"163 bool "Update the crash elfcorehdr on system configuration changes"
153 default y164 default y
kernel/Makefile+1−0
@@ -78,6 +78,7 @@ obj-$(CONFIG_CRASH_RESERVE) += crash_reserve.o · 77 unmodified lines
78obj-$(CONFIG_KEXEC_CORE) += kexec_core.o78obj-$(CONFIG_KEXEC_CORE) += kexec_core.o
79obj-$(CONFIG_CRASH_DUMP) += crash_core.o79obj-$(CONFIG_CRASH_DUMP) += crash_core.o
80obj-$(CONFIG_CRASH_DM_CRYPT) += crash_dump_dm_crypt.o80obj-$(CONFIG_CRASH_DM_CRYPT) += crash_dump_dm_crypt.o
81obj-$(CONFIG_CRASH_DUMP_KUNIT_TEST) += crash_core_test.o
81obj-$(CONFIG_KEXEC) += kexec.o82obj-$(CONFIG_KEXEC) += kexec.o
82obj-$(CONFIG_KEXEC_FILE) += kexec_file.o83obj-$(CONFIG_KEXEC_FILE) += kexec_file.o
83obj-$(CONFIG_KEXEC_ELF) += kexec_elf.o84obj-$(CONFIG_KEXEC_ELF) += kexec_elf.o
kernel/crash_core.c+18−12
@@ -22,6 +22,7 @@ · 21 unmodified lines
22#include <linux/btf.h>22#include <linux/btf.h>
23#include <linux/objtool.h>23#include <linux/objtool.h>
24#include <linux/delay.h>24#include <linux/delay.h>
25#include <linux/panic.h>
25 26
26#include <asm/page.h>27#include <asm/page.h>
27#include <asm/sections.h>28#include <asm/sections.h>
@@ -143,17 +144,7 @@ STACK_FRAME_NON_STANDARD(__crash_kexec); · 115 unmodified lines
143 144
144__bpf_kfunc void crash_kexec(struct pt_regs *regs)145__bpf_kfunc void crash_kexec(struct pt_regs *regs)
145{146{
146 int old_cpu, this_cpu;147 if (panic_try_start()) {
147
148 /*
149 * Only one CPU is allowed to execute the crash_kexec() code as with
150 * panic(). Otherwise parallel calls of panic() and crash_kexec()
151 * may stop each other. To exclude them, we use panic_cpu here too.
152 */
153 old_cpu = PANIC_CPU_INVALID;
154 this_cpu = raw_smp_processor_id();
155
156 if (atomic_try_cmpxchg(&panic_cpu, &old_cpu, this_cpu)) {
157 /* This is the 1st CPU which comes here, so go ahead. */148 /* This is the 1st CPU which comes here, so go ahead. */
158 __crash_kexec(regs);149 __crash_kexec(regs);
159 150
@@ -161,7 +152,7 @@ __bpf_kfunc void crash_kexec(struct pt_regs *regs) · 1 unmodified line
161 * Reset panic_cpu to allow another panic()/crash_kexec()152 * Reset panic_cpu to allow another panic()/crash_kexec()
162 * call.153 * call.
163 */154 */
164 atomic_set(&panic_cpu, PANIC_CPU_INVALID);155 panic_reset();
165 }156 }
166}157}
167 158
@@ -274,6 +265,20 @@ int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map, · 106 unmodified lines
274 return 0;265 return 0;
275}266}
276 267
268/**
269 * crash_exclude_mem_range - exclude a mem range for existing ranges
270 * @mem: mem->range contains an array of ranges sorted in ascending order
271 * @mstart: the start of to-be-excluded range
272 * @mend: the start of to-be-excluded range
273 *
274 * If you are unsure if a range split will happen, to avoid function call
275 * failure because of -ENOMEM, always make sure
276 * mem->max_nr_ranges == mem->nr_ranges + 1
277 * before calling the function each time.
278 *
279 * returns 0 if a memory range is excluded successfully
280 * return -ENOMEM if mem->ranges doesn't have space to hold split ranges
281 */
277int crash_exclude_mem_range(struct crash_mem *mem,282int crash_exclude_mem_range(struct crash_mem *mem,
278 unsigned long long mstart, unsigned long long mend)283 unsigned long long mstart, unsigned long long mend)
279{284{
@@ -333,6 +338,7 @@ int crash_exclude_mem_range(struct crash_mem *mem, · 53 unmodified lines
333 338
334 return 0;339 return 0;
335}340}
341EXPORT_SYMBOL_GPL(crash_exclude_mem_range);
336 342
337ssize_t crash_get_memory_size(void)343ssize_t crash_get_memory_size(void)
338{344{
kernel/crash_core_test.c+343−0
@@ -0,0 +1,343 @@
1// SPDX-License-Identifier: GPL-2.0-only
2#include <kunit/test.h>
3#include <linux/crash_core.h> // For struct crash_mem and struct range if defined there
4
5// Helper to create and initialize crash_mem
6static struct crash_mem *create_crash_mem(struct kunit *test, unsigned int max_ranges,
7 unsigned int nr_initial_ranges,
8 const struct range *initial_ranges)
9{
10 struct crash_mem *mem;
11 size_t alloc_size;
12
13 // Check if max_ranges can even hold initial_ranges
14 if (max_ranges < nr_initial_ranges) {
15 kunit_err(test, "max_ranges (%u) < nr_initial_ranges (%u)\n",
16 max_ranges, nr_initial_ranges);
17 return NULL;
18 }
19
20 alloc_size = sizeof(struct crash_mem) + (size_t)max_ranges * sizeof(struct range);
21 mem = kunit_kzalloc(test, alloc_size, GFP_KERNEL);
22 if (!mem) {
23 kunit_err(test, "Failed to allocate crash_mem\n");
24 return NULL;
25 }
26
27 mem->max_nr_ranges = max_ranges;
28 mem->nr_ranges = nr_initial_ranges;
29 if (initial_ranges && nr_initial_ranges > 0) {
30 memcpy(mem->ranges, initial_ranges,
31 nr_initial_ranges * sizeof(struct range));
32 }
33
34 return mem;
35}
36
37// Helper to compare ranges for assertions
38static void assert_ranges_equal(struct kunit *test,
39 const struct range *actual_ranges,
40 unsigned int actual_nr_ranges,
41 const struct range *expected_ranges,
42 unsigned int expected_nr_ranges,
43 const char *case_name)
44{
45 unsigned int i;
46
47 KUNIT_ASSERT_EQ_MSG(test, expected_nr_ranges, actual_nr_ranges,
48 "%s: Number of ranges mismatch.", case_name);
49
50 for (i = 0; i < expected_nr_ranges; i++) {
51 KUNIT_ASSERT_EQ_MSG(test, expected_ranges[i].start, actual_ranges[i].start,
52 "%s: Range %u start mismatch.", case_name, i);
53 KUNIT_ASSERT_EQ_MSG(test, expected_ranges[i].end, actual_ranges[i].end,
54 "%s: Range %u end mismatch.", case_name, i);
55 }
56}
57
58// Structure for test parameters
59struct exclude_test_param {
60 const char *description;
61 unsigned long long exclude_start;
62 unsigned long long exclude_end;
63 unsigned int initial_max_ranges;
64 const struct range *initial_ranges;
65 unsigned int initial_nr_ranges;
66 const struct range *expected_ranges;
67 unsigned int expected_nr_ranges;
68 int expected_ret;
69};
70
71static void run_exclude_test_case(struct kunit *test, const struct exclude_test_param *params)
72{
73 struct crash_mem *mem;
74 int ret;
75
76 kunit_info(test, "%s", params->description);
77
78 mem = create_crash_mem(test, params->initial_max_ranges,
79 params->initial_nr_ranges, params->initial_ranges);
80 if (!mem)
81 return; // Error already logged by create_crash_mem or kunit_kzalloc
82
83 ret = crash_exclude_mem_range(mem, params->exclude_start, params->exclude_end);
84
85 KUNIT_ASSERT_EQ_MSG(test, params->expected_ret, ret,
86 "%s: Return value mismatch.", params->description);
87
88 if (params->expected_ret == 0) {
89 assert_ranges_equal(test, mem->ranges, mem->nr_ranges,
90 params->expected_ranges, params->expected_nr_ranges,
91 params->description);
92 } else {
93 // If an error is expected, nr_ranges might still be relevant to check
94 // depending on the exact point of failure. For ENOMEM on split,
95 // nr_ranges shouldn't have changed.
96 KUNIT_ASSERT_EQ_MSG(test, params->initial_nr_ranges,
97 mem->nr_ranges,
98 "%s: Number of ranges mismatch on error.",
99 params->description);
100 }
101}
102
103/*
104 * Test Strategy 1: One to-be-excluded range A and one existing range B.
105 *
106 * Exhaust all possibilities of the position of A regarding B.
107 */
108
109static const struct range single_range_b = { .start = 100, .end = 199 };
110
111static const struct exclude_test_param exclude_single_range_test_data[] = {
112 {
113 .description = "1.1: A is left of B, no overlap",
114 .exclude_start = 10, .exclude_end = 50,
115 .initial_max_ranges = 1,
116 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
117 .expected_ranges = &single_range_b, .expected_nr_ranges = 1,
118 .expected_ret = 0,
119 },
120 {
121 .description = "1.2: A's right boundary touches B's left boundary",
122 .exclude_start = 10, .exclude_end = 99,
123 .initial_max_ranges = 1,
124 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
125 .expected_ranges = &single_range_b, .expected_nr_ranges = 1,
126 .expected_ret = 0,
127 },
128 {
129 .description = "1.3: A overlaps B's left part",
130 .exclude_start = 50, .exclude_end = 149,
131 .initial_max_ranges = 1,
132 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
133 .expected_ranges = (const struct range[]){{ .start = 150, .end = 199 }},
134 .expected_nr_ranges = 1,
135 .expected_ret = 0,
136 },
137 {
138 .description = "1.4: A is completely inside B",
139 .exclude_start = 120, .exclude_end = 179,
140 .initial_max_ranges = 2, // Needs space for split
141 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
142 .expected_ranges = (const struct range[]){
143 { .start = 100, .end = 119 },
144 { .start = 180, .end = 199 }
145 },
146 .expected_nr_ranges = 2,
147 .expected_ret = 0,
148 },
149 {
150 .description = "1.5: A overlaps B's right part",
151 .exclude_start = 150, .exclude_end = 249,
152 .initial_max_ranges = 1,
153 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
154 .expected_ranges = (const struct range[]){{ .start = 100, .end = 149 }},
155 .expected_nr_ranges = 1,
156 .expected_ret = 0,
157 },
158 {
159 .description = "1.6: A's left boundary touches B's right boundary",
160 .exclude_start = 200, .exclude_end = 250,
161 .initial_max_ranges = 1,
162 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
163 .expected_ranges = &single_range_b, .expected_nr_ranges = 1,
164 .expected_ret = 0,
165 },
166 {
167 .description = "1.7: A is right of B, no overlap",
168 .exclude_start = 250, .exclude_end = 300,
169 .initial_max_ranges = 1,
170 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
171 .expected_ranges = &single_range_b, .expected_nr_ranges = 1,
172 .expected_ret = 0,
173 },
174 {
175 .description = "1.8: A completely covers B and extends beyond",
176 .exclude_start = 50, .exclude_end = 250,
177 .initial_max_ranges = 1,
178 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
179 .expected_ranges = NULL, .expected_nr_ranges = 0,
180 .expected_ret = 0,
181 },
182 {
183 .description = "1.9: A covers B and extends to the left",
184 .exclude_start = 50, .exclude_end = 199, // A ends exactly where B ends
185 .initial_max_ranges = 1,
186 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
187 .expected_ranges = NULL, .expected_nr_ranges = 0,
188 .expected_ret = 0,
189 },
190 {
191 .description = "1.10: A covers B and extends to the right",
192 .exclude_start = 100, .exclude_end = 250, // A starts exactly where B starts
193 .initial_max_ranges = 1,
194 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
195 .expected_ranges = NULL, .expected_nr_ranges = 0,
196 .expected_ret = 0,
197 },
198 {
199 .description = "1.11: A is identical to B",
200 .exclude_start = 100, .exclude_end = 199,
201 .initial_max_ranges = 1,
202 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
203 .expected_ranges = NULL, .expected_nr_ranges = 0,
204 .expected_ret = 0,
205 },
206 {
207 .description = "1.12: A is a point, left of B, no overlap",
208 .exclude_start = 10, .exclude_end = 10,
209 .initial_max_ranges = 1,
210 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
211 .expected_ranges = &single_range_b, .expected_nr_ranges = 1,
212 .expected_ret = 0,
213 },
214 {
215 .description = "1.13: A is a point, at start of B",
216 .exclude_start = 100, .exclude_end = 100,
217 .initial_max_ranges = 1,
218 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
219 .expected_ranges = (const struct range[]){{ .start = 101, .end = 199 }},
220 .expected_nr_ranges = 1,
221 .expected_ret = 0,
222 },
223 {
224 .description = "1.14: A is a point, in middle of B (causes split)",
225 .exclude_start = 150, .exclude_end = 150,
226 .initial_max_ranges = 2, // Needs space for split
227 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
228 .expected_ranges = (const struct range[]){
229 { .start = 100, .end = 149 },
230 { .start = 151, .end = 199 }
231 },
232 .expected_nr_ranges = 2,
233 .expected_ret = 0,
234 },
235 {
236 .description = "1.15: A is a point, at end of B",
237 .exclude_start = 199, .exclude_end = 199,
238 .initial_max_ranges = 1,
239 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
240 .expected_ranges = (const struct range[]){{ .start = 100, .end = 198 }},
241 .expected_nr_ranges = 1,
242 .expected_ret = 0,
243 },
244 {
245 .description = "1.16: A is a point, right of B, no overlap",
246 .exclude_start = 250, .exclude_end = 250,
247 .initial_max_ranges = 1,
248 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
249 .expected_ranges = &single_range_b, .expected_nr_ranges = 1,
250 .expected_ret = 0,
251 },
252 // ENOMEM case for single range split
253 {
254 .description = "1.17: A completely inside B (split), no space (ENOMEM)",
255 .exclude_start = 120, .exclude_end = 179,
256 .initial_max_ranges = 1, // Not enough for split
257 .initial_ranges = &single_range_b, .initial_nr_ranges = 1,
258 .expected_ranges = NULL, // Not checked on error by assert_ranges_equal for content
259 .expected_nr_ranges = 1, // Should remain unchanged
260 .expected_ret = -ENOMEM,
261 },
262};
263
264
265static void exclude_single_range_test(struct kunit *test)
266{
267 size_t i;
268
269 for (i = 0; i < ARRAY_SIZE(exclude_single_range_test_data); i++) {
270 kunit_log(KERN_INFO, test, "Running: %s", exclude_single_range_test_data[i].description);
271 run_exclude_test_case(test, &exclude_single_range_test_data[i]);
272 // KUnit will stop on first KUNIT_ASSERT failure within run_exclude_test_case
273 }
274}
275
276/*
277 * Test Strategy 2: Regression test.
278 */
279
280static const struct exclude_test_param exclude_range_regression_test_data[] = {
281 // Test data from commit a2e9a95d2190
282 {
283 .description = "2.1: exclude low 1M",
284 .exclude_start = 0, .exclude_end = (1 << 20) - 1,
285 .initial_max_ranges = 3,
286 .initial_ranges = (const struct range[]){
287 { .start = 0, .end = 0x3efff },
288 { .start = 0x3f000, .end = 0x3ffff },
289 { .start = 0x40000, .end = 0x9ffff }
290 },
291 .initial_nr_ranges = 3,
292 .expected_nr_ranges = 0,
293 .expected_ret = 0,
294 },
295 // Test data from https://lore.kernel.org/all/ZXrY7QbXAlxydsSC@MiWiFi-R3L-srv/T/#u
296 {
297 .description = "2.2: when range out of bound",
298 .exclude_start = 100, .exclude_end = 200,
299 .initial_max_ranges = 3,
300 .initial_ranges = (const struct range[]){
301 { .start = 1, .end = 299 },
302 { .start = 401, .end = 1000 },
303 { .start = 1001, .end = 2000 }
304 },
305 .initial_nr_ranges = 3,
306 .expected_ranges = NULL, // Not checked on error by assert_ranges_equal for content
307 .expected_nr_ranges = 3, // Should remain unchanged
308 .expected_ret = -ENOMEM
309 },
310
311};
312
313
314static void exclude_range_regression_test(struct kunit *test)
315{
316 size_t i;
317
318 for (i = 0; i < ARRAY_SIZE(exclude_range_regression_test_data); i++) {
319 kunit_log(KERN_INFO, test, "Running: %s", exclude_range_regression_test_data[i].description);
320 run_exclude_test_case(test, &exclude_range_regression_test_data[i]);
321 // KUnit will stop on first KUNIT_ASSERT failure within run_exclude_test_case
322 }
323}
324
325/*
326 * KUnit Test Suite
327 */
328static struct kunit_case crash_exclude_mem_range_test_cases[] = {
329 KUNIT_CASE(exclude_single_range_test),
330 KUNIT_CASE(exclude_range_regression_test),
331 {}
332};
333
334static struct kunit_suite crash_exclude_mem_range_suite = {
335 .name = "crash_exclude_mem_range_tests",
336 .test_cases = crash_exclude_mem_range_test_cases,
337 // .init and .exit can be NULL if not needed globally for the suite
338};
339
340kunit_test_suite(crash_exclude_mem_range_suite);
341
342MODULE_DESCRIPTION("crash dump KUnit test suite");
343MODULE_LICENSE("GPL");
kernel/fork.c+6−12
@@ -2132,9 +2132,7 @@ __latent_entropy struct task_struct *copy_process( · 2131 unmodified lines
2132 2132
2133 p->pagefault_disabled = 0;2133 p->pagefault_disabled = 0;
2134 2134
2135#ifdef CONFIG_LOCKDEP
2136 lockdep_init_task(p);2135 lockdep_init_task(p);
2137#endif
2138 2136
2139 p->blocked_on = NULL; /* not blocked yet */2137 p->blocked_on = NULL; /* not blocked yet */
2140 2138
@@ -2547,11 +2545,9 @@ struct task_struct * __init fork_idle(int cpu) · 406 unmodified lines
2547struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node)2545struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node)
2548{2546{
2549 unsigned long flags = CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|2547 unsigned long flags = CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|
2550 CLONE_IO;2548 CLONE_IO|CLONE_VM|CLONE_UNTRACED;
2551 struct kernel_clone_args args = {2549 struct kernel_clone_args args = {
2552 .flags = ((lower_32_bits(flags) | CLONE_VM |2550 .flags = flags,
2553 CLONE_UNTRACED) & ~CSIGNAL),
2554 .exit_signal = (lower_32_bits(flags) & CSIGNAL),
2555 .fn = fn,2551 .fn = fn,
2556 .fn_arg = arg,2552 .fn_arg = arg,
2557 .io_thread = 1,2553 .io_thread = 1,
@@ -2663,9 +2659,8 @@ pid_t kernel_thread(int (*fn)(void *), void *arg, const char *name, · 105 unmodified lines
2663 unsigned long flags)2659 unsigned long flags)
2664{2660{
2665 struct kernel_clone_args args = {2661 struct kernel_clone_args args = {
2666 .flags = ((lower_32_bits(flags) | CLONE_VM |2662 .flags = ((flags | CLONE_VM | CLONE_UNTRACED) & ~CSIGNAL),
2667 CLONE_UNTRACED) & ~CSIGNAL),2663 .exit_signal = (flags & CSIGNAL),
2668 .exit_signal = (lower_32_bits(flags) & CSIGNAL),
2669 .fn = fn,2664 .fn = fn,
2670 .fn_arg = arg,2665 .fn_arg = arg,
2671 .name = name,2666 .name = name,
@@ -2681,9 +2676,8 @@ pid_t kernel_thread(int (*fn)(void *), void *arg, const char *name, · 9 unmodified lines
2681pid_t user_mode_thread(int (*fn)(void *), void *arg, unsigned long flags)2676pid_t user_mode_thread(int (*fn)(void *), void *arg, unsigned long flags)
2682{2677{
2683 struct kernel_clone_args args = {2678 struct kernel_clone_args args = {
2684 .flags = ((lower_32_bits(flags) | CLONE_VM |2679 .flags = ((flags | CLONE_VM | CLONE_UNTRACED) & ~CSIGNAL),
2685 CLONE_UNTRACED) & ~CSIGNAL),2680 .exit_signal = (flags & CSIGNAL),
2686 .exit_signal = (lower_32_bits(flags) & CSIGNAL),
2687 .fn = fn,2681 .fn = fn,
2688 .fn_arg = arg,2682 .fn_arg = arg,
2689 };2683 };
kernel/hung_task.c+41−37
@@ -95,9 +95,41 @@ static struct notifier_block panic_block = { · 94 unmodified lines
95 .notifier_call = hung_task_panic,95 .notifier_call = hung_task_panic,
96};96};
97 97
98static bool task_is_hung(struct task_struct *t, unsigned long timeout)
99{
100 unsigned long switch_count = t->nvcsw + t->nivcsw;
101 unsigned int state = READ_ONCE(t->__state);
102
103 /*
104 * skip the TASK_KILLABLE tasks -- these can be killed
105 * skip the TASK_IDLE tasks -- those are genuinely idle
106 * skip the TASK_FROZEN task -- it reasonably stops scheduling by freezer
107 */
108 if (!(state & TASK_UNINTERRUPTIBLE) ||
109 (state & (TASK_WAKEKILL | TASK_NOLOAD | TASK_FROZEN)))
110 return false;
111
112 /*
113 * When a freshly created task is scheduled once, changes its state to
114 * TASK_UNINTERRUPTIBLE without having ever been switched out once, it
115 * musn't be checked.
116 */
117 if (unlikely(!switch_count))
118 return false;
119
120 if (switch_count != t->last_switch_count) {
121 t->last_switch_count = switch_count;
122 t->last_switch_time = jiffies;
123 return false;
124 }
125 if (time_is_after_jiffies(t->last_switch_time + timeout * HZ))
126 return false;
127
128 return true;
129}
98 130
99#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER131#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
100static void debug_show_blocker(struct task_struct *task)132static void debug_show_blocker(struct task_struct *task, unsigned long timeout)
101{133{
102 struct task_struct *g, *t;134 struct task_struct *g, *t;
103 unsigned long owner, blocker, blocker_type;135 unsigned long owner, blocker, blocker_type;
@@ -174,41 +206,21 @@ static void debug_show_blocker(struct task_struct *task) · 70 unmodified lines
174 t->pid, rwsem_blocked_by);206 t->pid, rwsem_blocked_by);
175 break;207 break;
176 }208 }
177 sched_show_task(t);209 /* Avoid duplicated task dump, skip if the task is also hung. */
210 if (!task_is_hung(t, timeout))
211 sched_show_task(t);
178 return;212 return;
179 }213 }
180}214}
181#else215#else
182static inline void debug_show_blocker(struct task_struct *task)216static inline void debug_show_blocker(struct task_struct *task, unsigned long timeout)
183{217{
184}218}
185#endif219#endif
186 220
187static void check_hung_task(struct task_struct *t, unsigned long timeout)221static void check_hung_task(struct task_struct *t, unsigned long timeout)
188{222{
189 unsigned long switch_count = t->nvcsw + t->nivcsw;223 if (!task_is_hung(t, timeout))
190
191 /*
192 * Ensure the task is not frozen.
193 * Also, skip vfork and any other user process that freezer should skip.
194 */
195 if (unlikely(READ_ONCE(t->__state) & TASK_FROZEN))
196 return;
197
198 /*
199 * When a freshly created task is scheduled once, changes its state to
200 * TASK_UNINTERRUPTIBLE without having ever been switched out once, it
201 * musn't be checked.
202 */
203 if (unlikely(!switch_count))
204 return;
205
206 if (switch_count != t->last_switch_count) {
207 t->last_switch_count = switch_count;
208 t->last_switch_time = jiffies;
209 return;
210 }
211 if (time_is_after_jiffies(t->last_switch_time + timeout * HZ))
212 return;224 return;
213 225
214 /*226 /*
@@ -243,7 +255,7 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) · 28 unmodified lines
243 pr_err("\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\""255 pr_err("\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\""
244 " disables this message.\n");256 " disables this message.\n");
245 sched_show_task(t);257 sched_show_task(t);
246 debug_show_blocker(t);258 debug_show_blocker(t, timeout);
247 hung_task_show_lock = true;259 hung_task_show_lock = true;
248 260
249 if (sysctl_hung_task_all_cpu_backtrace)261 if (sysctl_hung_task_all_cpu_backtrace)
@@ -299,7 +311,6 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) · 49 unmodified lines
299 hung_task_show_lock = false;311 hung_task_show_lock = false;
300 rcu_read_lock();312 rcu_read_lock();
301 for_each_process_thread(g, t) {313 for_each_process_thread(g, t) {
302 unsigned int state;
303 314
304 if (!max_count--)315 if (!max_count--)
305 goto unlock;316 goto unlock;
@@ -308,15 +319,8 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) · 2 unmodified lines
308 goto unlock;319 goto unlock;
309 last_break = jiffies;320 last_break = jiffies;
310 }321 }
311 /*322
312 * skip the TASK_KILLABLE tasks -- these can be killed323 check_hung_task(t, timeout);
313 * skip the TASK_IDLE tasks -- those are genuinely idle
314 */
315 state = READ_ONCE(t->__state);
316 if ((state & TASK_UNINTERRUPTIBLE) &&
317 !(state & TASK_WAKEKILL) &&
318 !(state & TASK_NOLOAD))
319 check_hung_task(t, timeout);
320 }324 }
321 unlock:325 unlock:
322 rcu_read_unlock();326 rcu_read_unlock();
kernel/kallsyms_selftest.c+1−1
@@ -264,7 +264,7 @@ static int test_kallsyms_basic_function(void) · 263 unmodified lines
264 char namebuf[KSYM_NAME_LEN];264 char namebuf[KSYM_NAME_LEN];
265 struct test_stat *stat, *stat2;265 struct test_stat *stat, *stat2;
266 266
267 stat = kmalloc(sizeof(*stat) * 2, GFP_KERNEL);267 stat = kmalloc_array(2, sizeof(*stat), GFP_KERNEL);
268 if (!stat)268 if (!stat)
269 return -ENOMEM;269 return -ENOMEM;
270 stat2 = stat + 1;270 stat2 = stat + 1;
kernel/kcov.c+9−0
@@ -978,6 +978,15 @@ static void kcov_move_area(enum kcov_mode mode, void *dst_area, · 977 unmodified lines
978 memcpy(dst_entries, src_entries, bytes_to_move);978 memcpy(dst_entries, src_entries, bytes_to_move);
979 entries_moved = bytes_to_move >> entry_size_log;979 entries_moved = bytes_to_move >> entry_size_log;
980 980
981 /*
982 * A write memory barrier is required here, to ensure
983 * that the writes from the memcpy() are visible before
984 * the count is updated. Without this, it is possible for
985 * a user to observe a new count value but stale
986 * coverage data.
987 */
988 smp_wmb();
989
981 switch (mode) {990 switch (mode) {
982 case KCOV_MODE_TRACE_PC:991 case KCOV_MODE_TRACE_PC:
983 WRITE_ONCE(*(unsigned long *)dst_area, dst_len + entries_moved);992 WRITE_ONCE(*(unsigned long *)dst_area, dst_len + entries_moved);
kernel/kexec_core.c+0−1
@@ -233,7 +233,6 @@ struct kimage *do_kimage_alloc_init(void) · 232 unmodified lines
233 if (!image)233 if (!image)
234 return NULL;234 return NULL;
235 235
236 image->head = 0;
237 image->entry = &image->head;236 image->entry = &image->head;
238 image->last_entry = &image->head;237 image->last_entry = &image->head;
239 image->control_page = ~0; /* By default this does not apply */238 image->control_page = ~0; /* By default this does not apply */
kernel/kexec_file.c+1−0
@@ -255,6 +255,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, · 254 unmodified lines
255 }255 }
256 256
257 image->no_cma = !!(flags & KEXEC_FILE_NO_CMA);257 image->no_cma = !!(flags & KEXEC_FILE_NO_CMA);
258 image->force_dtb = flags & KEXEC_FILE_FORCE_DTB;
258 259
259 if (cmdline_len) {260 if (cmdline_len) {
260 image->cmdline_buf = memdup_user(cmdline_ptr, cmdline_len);261 image->cmdline_buf = memdup_user(cmdline_ptr, cmdline_len);
kernel/kexec_handover.c+21−1
@@ -987,6 +987,26 @@ static const void *kho_get_fdt(void) · 986 unmodified lines
987 return kho_in.fdt_phys ? phys_to_virt(kho_in.fdt_phys) : NULL;987 return kho_in.fdt_phys ? phys_to_virt(kho_in.fdt_phys) : NULL;
988}988}
989 989
990/**
991 * is_kho_boot - check if current kernel was booted via KHO-enabled
992 * kexec
993 *
994 * This function checks if the current kernel was loaded through a kexec
995 * operation with KHO enabled, by verifying that a valid KHO FDT
996 * was passed.
997 *
998 * Note: This function returns reliable results only after
999 * kho_populate() has been called during early boot. Before that,
1000 * it may return false even if KHO data is present.
1001 *
1002 * Return: true if booted via KHO-enabled kexec, false otherwise
1003 */
1004bool is_kho_boot(void)
1005{
1006 return !!kho_get_fdt();
1007}
1008EXPORT_SYMBOL_GPL(is_kho_boot);
1009
990/**1010/**
991 * kho_retrieve_subtree - retrieve a preserved sub FDT by its name.1011 * kho_retrieve_subtree - retrieve a preserved sub FDT by its name.
992 * @name: the name of the sub FDT passed to kho_add_subtree().1012 * @name: the name of the sub FDT passed to kho_add_subtree().
@@ -1269,7 +1289,7 @@ int kho_fill_kimage(struct kimage *image) · 276 unmodified lines
1269 int err = 0;1289 int err = 0;
1270 struct kexec_buf scratch;1290 struct kexec_buf scratch;
1271 1291
1272 if (!kho_enable)1292 if (!kho_out.finalized)
1273 return 0;1293 return 0;
1274 1294
1275 image->kho.fdt = page_to_phys(kho_out.ser.fdt);1295 image->kho.fdt = page_to_phys(kho_out.ser.fdt);
kernel/panic.c+103−26
@@ -53,7 +53,7 @@ static unsigned int __read_mostly sysctl_oops_all_cpu_backtrace; · 52 unmodified lines
53#define sysctl_oops_all_cpu_backtrace 053#define sysctl_oops_all_cpu_backtrace 0
54#endif /* CONFIG_SMP */54#endif /* CONFIG_SMP */
55 55
56int panic_on_oops = CONFIG_PANIC_ON_OOPS_VALUE;56int panic_on_oops = IS_ENABLED(CONFIG_PANIC_ON_OOPS);
57static unsigned long tainted_mask =57static unsigned long tainted_mask =
58 IS_ENABLED(CONFIG_RANDSTRUCT) ? (1 << TAINT_RANDSTRUCT) : 0;58 IS_ENABLED(CONFIG_RANDSTRUCT) ? (1 << TAINT_RANDSTRUCT) : 0;
59static int pause_on_oops;59static int pause_on_oops;
@@ -67,6 +67,7 @@ static unsigned int warn_limit __read_mostly; · 7 unmodified lines
67static bool panic_console_replay;67static bool panic_console_replay;
68 68
69bool panic_triggering_all_cpu_backtrace;69bool panic_triggering_all_cpu_backtrace;
70static bool panic_this_cpu_backtrace_printed;
70 71
71int panic_timeout = CONFIG_PANIC_TIMEOUT;72int panic_timeout = CONFIG_PANIC_TIMEOUT;
72EXPORT_SYMBOL_GPL(panic_timeout);73EXPORT_SYMBOL_GPL(panic_timeout);
@@ -77,6 +78,11 @@ ATOMIC_NOTIFIER_HEAD(panic_notifier_list); · 4 unmodified lines
77 78
78EXPORT_SYMBOL(panic_notifier_list);79EXPORT_SYMBOL(panic_notifier_list);
79 80
81static void panic_print_deprecated(void)
82{
83 pr_info_once("Kernel: The 'panic_print' parameter is now deprecated. Please use 'panic_sys_info' and 'panic_console_replay' instead.\n");
84}
85
80#ifdef CONFIG_SYSCTL86#ifdef CONFIG_SYSCTL
81 87
82/*88/*
@@ -125,7 +131,7 @@ static int proc_taint(const struct ctl_table *table, int write, · 42 unmodified lines
125static int sysctl_panic_print_handler(const struct ctl_table *table, int write,131static int sysctl_panic_print_handler(const struct ctl_table *table, int write,
126 void *buffer, size_t *lenp, loff_t *ppos)132 void *buffer, size_t *lenp, loff_t *ppos)
127{133{
128 pr_info_once("Kernel: 'panic_print' sysctl interface will be obsoleted by both 'panic_sys_info' and 'panic_console_replay'\n");134 panic_print_deprecated();
129 return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);135 return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
130}136}
131 137
@@ -294,6 +300,59 @@ void __weak crash_smp_send_stop(void) · 162 unmodified lines
294 300
295atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID);301atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID);
296 302
303bool panic_try_start(void)
304{
305 int old_cpu, this_cpu;
306
307 /*
308 * Only one CPU is allowed to execute the crash_kexec() code as with
309 * panic(). Otherwise parallel calls of panic() and crash_kexec()
310 * may stop each other. To exclude them, we use panic_cpu here too.
311 */
312 old_cpu = PANIC_CPU_INVALID;
313 this_cpu = raw_smp_processor_id();
314
315 return atomic_try_cmpxchg(&panic_cpu, &old_cpu, this_cpu);
316}
317EXPORT_SYMBOL(panic_try_start);
318
319void panic_reset(void)
320{
321 atomic_set(&panic_cpu, PANIC_CPU_INVALID);
322}
323EXPORT_SYMBOL(panic_reset);
324
325bool panic_in_progress(void)
326{
327 return unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID);
328}
329EXPORT_SYMBOL(panic_in_progress);
330
331/* Return true if a panic is in progress on the current CPU. */
332bool panic_on_this_cpu(void)
333{
334 /*
335 * We can use raw_smp_processor_id() here because it is impossible for
336 * the task to be migrated to the panic_cpu, or away from it. If
337 * panic_cpu has already been set, and we're not currently executing on
338 * that CPU, then we never will be.
339 */
340 return unlikely(atomic_read(&panic_cpu) == raw_smp_processor_id());
341}
342EXPORT_SYMBOL(panic_on_this_cpu);
343
344/*
345 * Return true if a panic is in progress on a remote CPU.
346 *
347 * On true, the local CPU should immediately release any printing resources
348 * that may be needed by the panic CPU.
349 */
350bool panic_on_other_cpu(void)
351{
352 return (panic_in_progress() && !panic_on_this_cpu());
353}
354EXPORT_SYMBOL(panic_on_other_cpu);
355
297/*356/*
298 * A variant of panic() called from NMI context. We return if we've already357 * A variant of panic() called from NMI context. We return if we've already
299 * panicked on this CPU. If another CPU already panicked, loop in358 * panicked on this CPU. If another CPU already panicked, loop in
@@ -302,15 +361,9 @@ atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID); · 2 unmodified lines
302 */361 */
303void nmi_panic(struct pt_regs *regs, const char *msg)362void nmi_panic(struct pt_regs *regs, const char *msg)
304{363{
305 int old_cpu, this_cpu;364 if (panic_try_start())
306
307 old_cpu = PANIC_CPU_INVALID;
308 this_cpu = raw_smp_processor_id();
309
310 /* atomic_try_cmpxchg updates old_cpu on failure */
311 if (atomic_try_cmpxchg(&panic_cpu, &old_cpu, this_cpu))
312 panic("%s", msg);365 panic("%s", msg);
313 else if (old_cpu != this_cpu)366 else if (panic_on_other_cpu())
314 nmi_panic_self_stop(regs);367 nmi_panic_self_stop(regs);
315}368}
316EXPORT_SYMBOL(nmi_panic);369EXPORT_SYMBOL(nmi_panic);
@@ -328,6 +381,19 @@ void check_panic_on_warn(const char *origin) · 11 unmodified lines
328 origin, limit);381 origin, limit);
329}382}
330 383
384static void panic_trigger_all_cpu_backtrace(void)
385{
386 /* Temporary allow non-panic CPUs to write their backtraces. */
387 panic_triggering_all_cpu_backtrace = true;
388
389 if (panic_this_cpu_backtrace_printed)
390 trigger_allbutcpu_cpu_backtrace(raw_smp_processor_id());
391 else
392 trigger_all_cpu_backtrace();
393
394 panic_triggering_all_cpu_backtrace = false;
395}
396
331/*397/*
332 * Helper that triggers the NMI backtrace (if set in panic_print)398 * Helper that triggers the NMI backtrace (if set in panic_print)
333 * and then performs the secondary CPUs shutdown - we cannot have399 * and then performs the secondary CPUs shutdown - we cannot have
@@ -335,12 +401,8 @@ void check_panic_on_warn(const char *origin) · 1 unmodified line
335 */401 */
336static void panic_other_cpus_shutdown(bool crash_kexec)402static void panic_other_cpus_shutdown(bool crash_kexec)
337{403{
338 if (panic_print & SYS_INFO_ALL_CPU_BT) {404 if (panic_print & SYS_INFO_ALL_CPU_BT)
339 /* Temporary allow non-panic CPUs to write their backtraces. */405 panic_trigger_all_cpu_backtrace();
340 panic_triggering_all_cpu_backtrace = true;
341 trigger_all_cpu_backtrace();
342 panic_triggering_all_cpu_backtrace = false;
343 }
344 406
345 /*407 /*
346 * Note that smp_send_stop() is the usual SMP shutdown function,408 * Note that smp_send_stop() is the usual SMP shutdown function,
@@ -368,7 +430,6 @@ void vpanic(const char *fmt, va_list args) · 21 unmodified lines
368 static char buf[1024];430 static char buf[1024];
369 long i, i_next = 0, len;431 long i, i_next = 0, len;
370 int state = 0;432 int state = 0;
371 int old_cpu, this_cpu;
372 bool _crash_kexec_post_notifiers = crash_kexec_post_notifiers;433 bool _crash_kexec_post_notifiers = crash_kexec_post_notifiers;
373 434
374 if (panic_on_warn) {435 if (panic_on_warn) {
@@ -405,13 +466,10 @@ void vpanic(const char *fmt, va_list args) · 30 unmodified lines
405 * `old_cpu == this_cpu' means we came from nmi_panic() which sets466 * `old_cpu == this_cpu' means we came from nmi_panic() which sets
406 * panic_cpu to this CPU. In this case, this is also the 1st CPU.467 * panic_cpu to this CPU. In this case, this is also the 1st CPU.
407 */468 */
408 old_cpu = PANIC_CPU_INVALID;
409 this_cpu = raw_smp_processor_id();
410
411 /* atomic_try_cmpxchg updates old_cpu on failure */469 /* atomic_try_cmpxchg updates old_cpu on failure */
412 if (atomic_try_cmpxchg(&panic_cpu, &old_cpu, this_cpu)) {470 if (panic_try_start()) {
413 /* go ahead */471 /* go ahead */
414 } else if (old_cpu != this_cpu)472 } else if (panic_on_other_cpu())
415 panic_smp_self_stop();473 panic_smp_self_stop();
416 474
417 console_verbose();475 console_verbose();
@@ -422,13 +480,15 @@ void vpanic(const char *fmt, va_list args) · 4 unmodified lines
422 buf[len - 1] = '\0';480 buf[len - 1] = '\0';
423 481
424 pr_emerg("Kernel panic - not syncing: %s\n", buf);482 pr_emerg("Kernel panic - not syncing: %s\n", buf);
425#ifdef CONFIG_DEBUG_BUGVERBOSE
426 /*483 /*
427 * Avoid nested stack-dumping if a panic occurs during oops processing484 * Avoid nested stack-dumping if a panic occurs during oops processing
428 */485 */
429 if (!test_taint(TAINT_DIE) && oops_in_progress <= 1)486 if (test_taint(TAINT_DIE) || oops_in_progress > 1) {
487 panic_this_cpu_backtrace_printed = true;
488 } else if (IS_ENABLED(CONFIG_DEBUG_BUGVERBOSE)) {
430 dump_stack();489 dump_stack();
431#endif490 panic_this_cpu_backtrace_printed = true;
491 }
432 492
433 /*493 /*
434 * If kgdb is enabled, give it a chance to run before we stop all494 * If kgdb is enabled, give it a chance to run before we stop all
@@ -937,12 +997,29 @@ EXPORT_SYMBOL(__stack_chk_fail); · 502 unmodified lines
937#endif997#endif
938 998
939core_param(panic, panic_timeout, int, 0644);999core_param(panic, panic_timeout, int, 0644);
940core_param(panic_print, panic_print, ulong, 0644);
941core_param(pause_on_oops, pause_on_oops, int, 0644);1000core_param(pause_on_oops, pause_on_oops, int, 0644);
942core_param(panic_on_warn, panic_on_warn, int, 0644);1001core_param(panic_on_warn, panic_on_warn, int, 0644);
943core_param(crash_kexec_post_notifiers, crash_kexec_post_notifiers, bool, 0644);1002core_param(crash_kexec_post_notifiers, crash_kexec_post_notifiers, bool, 0644);
944core_param(panic_console_replay, panic_console_replay, bool, 0644);1003core_param(panic_console_replay, panic_console_replay, bool, 0644);
945 1004
1005static int panic_print_set(const char *val, const struct kernel_param *kp)
1006{
1007 panic_print_deprecated();
1008 return param_set_ulong(val, kp);
1009}
1010
1011static int panic_print_get(char *val, const struct kernel_param *kp)
1012{
1013 panic_print_deprecated();
1014 return param_get_ulong(val, kp);
1015}
1016
1017static const struct kernel_param_ops panic_print_ops = {
1018 .set = panic_print_set,
1019 .get = panic_print_get,
1020};
1021__core_param_cb(panic_print, &panic_print_ops, &panic_print, 0644);
1022
946static int __init oops_setup(char *s)1023static int __init oops_setup(char *s)
947{1024{
948 if (!s)1025 if (!s)
kernel/printk/internal.h+0−1
@@ -332,7 +332,6 @@ struct printk_message { · 331 unmodified lines
332 unsigned long dropped;332 unsigned long dropped;
333};333};
334 334
335bool other_cpu_in_panic(void);
336bool printk_get_next_message(struct printk_message *pmsg, u64 seq,335bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
337 bool is_extended, bool may_supress);336 bool is_extended, bool may_supress);
338 337
kernel/printk/nbcon.c+7−7
@@ -12,6 +12,7 @@ · 11 unmodified lines
12#include <linux/irqflags.h>12#include <linux/irqflags.h>
13#include <linux/kthread.h>13#include <linux/kthread.h>
14#include <linux/minmax.h>14#include <linux/minmax.h>
15#include <linux/panic.h>
15#include <linux/percpu.h>16#include <linux/percpu.h>
16#include <linux/preempt.h>17#include <linux/preempt.h>
17#include <linux/slab.h>18#include <linux/slab.h>
@@ -254,7 +255,7 @@ static int nbcon_context_try_acquire_direct(struct nbcon_context *ctxt, · 236 unmodified lines
254 * opportunity to perform any necessary cleanup if they were255 * opportunity to perform any necessary cleanup if they were
255 * interrupted by the panic CPU while printing.256 * interrupted by the panic CPU while printing.
256 */257 */
257 if (other_cpu_in_panic() &&258 if (panic_on_other_cpu() &&
258 (!is_reacquire || cur->unsafe_takeover)) {259 (!is_reacquire || cur->unsafe_takeover)) {
259 return -EPERM;260 return -EPERM;
260 }261 }
@@ -309,7 +310,7 @@ static bool nbcon_waiter_matches(struct nbcon_state *cur, int expected_prio) · 48 unmodified lines
309 * Event #2 implies the new context is PANIC.310 * Event #2 implies the new context is PANIC.
310 * Event #3 occurs when panic() has flushed the console.311 * Event #3 occurs when panic() has flushed the console.
311 * Event #4 occurs when a non-panic CPU reacquires.312 * Event #4 occurs when a non-panic CPU reacquires.
312 * Event #5 is not possible due to the other_cpu_in_panic() check313 * Event #5 is not possible due to the panic_on_other_cpu() check
313 * in nbcon_context_try_acquire_handover().314 * in nbcon_context_try_acquire_handover().
314 */315 */
315 316
@@ -348,7 +349,7 @@ static int nbcon_context_try_acquire_requested(struct nbcon_context *ctxt, · 32 unmodified lines
348 struct nbcon_state new;349 struct nbcon_state new;
349 350
350 /* Note that the caller must still remove the request! */351 /* Note that the caller must still remove the request! */
351 if (other_cpu_in_panic())352 if (panic_on_other_cpu())
352 return -EPERM;353 return -EPERM;
353 354
354 /*355 /*
@@ -446,7 +447,7 @@ static int nbcon_context_try_acquire_handover(struct nbcon_context *ctxt, · 91 unmodified lines
446 * nbcon_waiter_matches(). In particular, the assumption that447 * nbcon_waiter_matches(). In particular, the assumption that
447 * lower priorities are ignored during panic.448 * lower priorities are ignored during panic.
448 */449 */
449 if (other_cpu_in_panic())450 if (panic_on_other_cpu())
450 return -EPERM;451 return -EPERM;
451 452
452 /* Handover is not possible on the same CPU. */453 /* Handover is not possible on the same CPU. */
@@ -589,7 +590,6 @@ static struct printk_buffers panic_nbcon_pbufs; · 136 unmodified lines
589 */590 */
590static bool nbcon_context_try_acquire(struct nbcon_context *ctxt, bool is_reacquire)591static bool nbcon_context_try_acquire(struct nbcon_context *ctxt, bool is_reacquire)
591{592{
592 unsigned int cpu = smp_processor_id();
593 struct console *con = ctxt->console;593 struct console *con = ctxt->console;
594 struct nbcon_state cur;594 struct nbcon_state cur;
595 int err;595 int err;
@@ -614,7 +614,7 @@ out: · 18 unmodified lines
614 /* Acquire succeeded. */614 /* Acquire succeeded. */
615 615
616 /* Assign the appropriate buffer for this context. */616 /* Assign the appropriate buffer for this context. */
617 if (atomic_read(&panic_cpu) == cpu)617 if (panic_on_this_cpu())
618 ctxt->pbufs = &panic_nbcon_pbufs;618 ctxt->pbufs = &panic_nbcon_pbufs;
619 else619 else
620 ctxt->pbufs = con->pbufs;620 ctxt->pbufs = con->pbufs;
@@ -1394,7 +1394,7 @@ enum nbcon_prio nbcon_get_default_prio(void) · 773 unmodified lines
1394{1394{
1395 unsigned int *cpu_emergency_nesting;1395 unsigned int *cpu_emergency_nesting;
1396 1396
1397 if (this_cpu_in_panic())1397 if (panic_on_this_cpu())
1398 return NBCON_PRIO_PANIC;1398 return NBCON_PRIO_PANIC;
1399 1399
1400 cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting();1400 cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting();
kernel/printk/printk.c+5−32
@@ -48,6 +48,7 @@ · 47 unmodified lines
48#include <linux/sched/clock.h>48#include <linux/sched/clock.h>
49#include <linux/sched/debug.h>49#include <linux/sched/debug.h>
50#include <linux/sched/task_stack.h>50#include <linux/sched/task_stack.h>
51#include <linux/panic.h>
51 52
52#include <linux/uaccess.h>53#include <linux/uaccess.h>
53#include <asm/sections.h>54#include <asm/sections.h>
@@ -345,34 +346,6 @@ static void __up_console_sem(unsigned long ip) · 291 unmodified lines
345}346}
346#define up_console_sem() __up_console_sem(_RET_IP_)347#define up_console_sem() __up_console_sem(_RET_IP_)
347 348
348static bool panic_in_progress(void)
349{
350 return unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID);
351}
352
353/* Return true if a panic is in progress on the current CPU. */
354bool this_cpu_in_panic(void)
355{
356 /*
357 * We can use raw_smp_processor_id() here because it is impossible for
358 * the task to be migrated to the panic_cpu, or away from it. If
359 * panic_cpu has already been set, and we're not currently executing on
360 * that CPU, then we never will be.
361 */
362 return unlikely(atomic_read(&panic_cpu) == raw_smp_processor_id());
363}
364
365/*
366 * Return true if a panic is in progress on a remote CPU.
367 *
368 * On true, the local CPU should immediately release any printing resources
369 * that may be needed by the panic CPU.
370 */
371bool other_cpu_in_panic(void)
372{
373 return (panic_in_progress() && !this_cpu_in_panic());
374}
375
376/*349/*
377 * This is used for debugging the mess that is the VT code by350 * This is used for debugging the mess that is the VT code by
378 * keeping track if we have the console semaphore held. It's351 * keeping track if we have the console semaphore held. It's
@@ -2407,7 +2380,7 @@ asmlinkage int vprintk_emit(int facility, int level, · 2028 unmodified lines
2407 * non-panic CPUs are generating any messages, they will be2380 * non-panic CPUs are generating any messages, they will be
2408 * silently dropped.2381 * silently dropped.
2409 */2382 */
2410 if (other_cpu_in_panic() &&2383 if (panic_on_other_cpu() &&
2411 !debug_non_panic_cpus &&2384 !debug_non_panic_cpus &&
2412 !panic_triggering_all_cpu_backtrace)2385 !panic_triggering_all_cpu_backtrace)
2413 return 0;2386 return 0;
@@ -2843,7 +2816,7 @@ void console_lock(void) · 429 unmodified lines
2843 might_sleep();2816 might_sleep();
2844 2817
2845 /* On panic, the console_lock must be left to the panic cpu. */2818 /* On panic, the console_lock must be left to the panic cpu. */
2846 while (other_cpu_in_panic())2819 while (panic_on_other_cpu())
2847 msleep(1000);2820 msleep(1000);
2848 2821
2849 down_console_sem();2822 down_console_sem();
@@ -2863,7 +2836,7 @@ EXPORT_SYMBOL(console_lock); · 13 unmodified lines
2863int console_trylock(void)2836int console_trylock(void)
2864{2837{
2865 /* On panic, the console_lock must be left to the panic cpu. */2838 /* On panic, the console_lock must be left to the panic cpu. */
2866 if (other_cpu_in_panic())2839 if (panic_on_other_cpu())
2867 return 0;2840 return 0;
2868 if (down_trylock_console_sem())2841 if (down_trylock_console_sem())
2869 return 0;2842 return 0;
@@ -3243,7 +3216,7 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove · 373 unmodified lines
3243 any_progress = true;3216 any_progress = true;
3244 3217
3245 /* Allow panic_cpu to take over the consoles safely. */3218 /* Allow panic_cpu to take over the consoles safely. */
3246 if (other_cpu_in_panic())3219 if (panic_on_other_cpu())
3247 goto abandon;3220 goto abandon;
3248 3221
3249 if (do_cond_resched)3222 if (do_cond_resched)
kernel/printk/printk_ringbuffer.c+1−1
@@ -2143,7 +2143,7 @@ static bool _prb_read_valid(struct printk_ringbuffer *rb, u64 *seq, · 2142 unmodified lines
2143 * But it would have the sequence number returned2143 * But it would have the sequence number returned
2144 * by "prb_next_reserve_seq() - 1".2144 * by "prb_next_reserve_seq() - 1".
2145 */2145 */
2146 if (this_cpu_in_panic() &&2146 if (panic_on_this_cpu() &&
2147 (!debug_non_panic_cpus || legacy_allow_panic_sync) &&2147 (!debug_non_panic_cpus || legacy_allow_panic_sync) &&
2148 ((*seq + 1) < prb_next_reserve_seq(rb))) {2148 ((*seq + 1) < prb_next_reserve_seq(rb))) {
2149 (*seq)++;2149 (*seq)++;
kernel/sys.c+30−2
@@ -1734,6 +1734,7 @@ SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, · 1733 unmodified lines
1734 struct rlimit old, new;1734 struct rlimit old, new;
1735 struct task_struct *tsk;1735 struct task_struct *tsk;
1736 unsigned int checkflags = 0;1736 unsigned int checkflags = 0;
1737 bool need_tasklist;
1737 int ret;1738 int ret;
1738 1739
1739 if (old_rlim)1740 if (old_rlim)
@@ -1760,8 +1761,25 @@ SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, · 20 unmodified lines
1760 get_task_struct(tsk);1761 get_task_struct(tsk);
1761 rcu_read_unlock();1762 rcu_read_unlock();
1762 1763
1763 ret = do_prlimit(tsk, resource, new_rlim ? &new : NULL,1764 need_tasklist = !same_thread_group(tsk, current);
1764 old_rlim ? &old : NULL);1765 if (need_tasklist) {
1766 /*
1767 * Ensure we can't race with group exit or de_thread(),
1768 * so tsk->group_leader can't be freed or changed until
1769 * read_unlock(tasklist_lock) below.
1770 */
1771 read_lock(&tasklist_lock);
1772 if (!pid_alive(tsk))
1773 ret = -ESRCH;
1774 }
1775
1776 if (!ret) {
1777 ret = do_prlimit(tsk, resource, new_rlim ? &new : NULL,
1778 old_rlim ? &old : NULL);
1779 }
1780
1781 if (need_tasklist)
1782 read_unlock(&tasklist_lock);
1765 1783
1766 if (!ret && old_rlim) {1784 if (!ret && old_rlim) {
1767 rlim_to_rlim64(&old, &old64);1785 rlim_to_rlim64(&old, &old64);
@@ -2515,7 +2533,17 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, · 747 unmodified lines
2515 error = -EINVAL;2533 error = -EINVAL;
2516 break;2534 break;
2517 }2535 }
2536 /*
2537 * Ensure that either:
2538 *
2539 * 1. Subsequent getppid() calls reflect the parent process having died.
2540 * 2. forget_original_parent() will send the new me->pdeath_signal.
2541 *
2542 * Also prevent the read of me->pdeath_signal from being a data race.
2543 */
2544 read_lock(&tasklist_lock);
2518 me->pdeath_signal = arg2;2545 me->pdeath_signal = arg2;
2546 read_unlock(&tasklist_lock);
2519 break;2547 break;
2520 case PR_GET_PDEATHSIG:2548 case PR_GET_PDEATHSIG:
2521 error = put_user(me->pdeath_signal, (int __user *)arg2);2549 error = put_user(me->pdeath_signal, (int __user *)arg2);
kernel/watchdog.c+23−5
@@ -425,7 +425,11 @@ static DEFINE_PER_CPU(u8, cpustat_tail); · 424 unmodified lines
425 */425 */
426static u16 get_16bit_precision(u64 data_ns)426static u16 get_16bit_precision(u64 data_ns)
427{427{
428 return data_ns >> 24LL; /* 2^24ns ~= 16.8ms */428 /*
429 * 2^24ns ~= 16.8ms
430 * Round to the nearest multiple of 16.8 milliseconds.
431 */
432 return (data_ns + (1 << 23)) >> 24LL;
429}433}
430 434
431static void update_cpustat(void)435static void update_cpustat(void)
@@ -444,6 +448,14 @@ static void update_cpustat(void) · 12 unmodified lines
444 old_stat = __this_cpu_read(cpustat_old[i]);448 old_stat = __this_cpu_read(cpustat_old[i]);
445 new_stat = get_16bit_precision(cpustat[tracked_stats[i]]);449 new_stat = get_16bit_precision(cpustat[tracked_stats[i]]);
446 util = DIV_ROUND_UP(100 * (new_stat - old_stat), sample_period_16);450 util = DIV_ROUND_UP(100 * (new_stat - old_stat), sample_period_16);
451 /*
452 * Since we use 16-bit precision, the raw data will undergo
453 * integer division, which may sometimes result in data loss,
454 * and then result might exceed 100%. To avoid confusion,
455 * we enforce a 100% display cap when calculations exceed this threshold.
456 */
457 if (util > 100)
458 util = 100;
447 __this_cpu_write(cpustat_util[tail][i], util);459 __this_cpu_write(cpustat_util[tail][i], util);
448 __this_cpu_write(cpustat_old[i], new_stat);460 __this_cpu_write(cpustat_old[i], new_stat);
449 }461 }
@@ -455,17 +467,17 @@ static void print_cpustat(void) · 5 unmodified lines
455{467{
456 int i, group;468 int i, group;
457 u8 tail = __this_cpu_read(cpustat_tail);469 u8 tail = __this_cpu_read(cpustat_tail);
458 u64 sample_period_second = sample_period;470 u64 sample_period_msecond = sample_period;
459 471
460 do_div(sample_period_second, NSEC_PER_SEC);472 do_div(sample_period_msecond, NSEC_PER_MSEC);
461 473
462 /*474 /*
463 * Outputting the "watchdog" prefix on every line is redundant and not475 * Outputting the "watchdog" prefix on every line is redundant and not
464 * concise, and the original alarm information is sufficient for476 * concise, and the original alarm information is sufficient for
465 * positioning in logs, hence here printk() is used instead of pr_crit().477 * positioning in logs, hence here printk() is used instead of pr_crit().
466 */478 */
467 printk(KERN_CRIT "CPU#%d Utilization every %llus during lockup:\n",479 printk(KERN_CRIT "CPU#%d Utilization every %llums during lockup:\n",
468 smp_processor_id(), sample_period_second);480 smp_processor_id(), sample_period_msecond);
469 481
470 for (i = 0; i < NUM_SAMPLE_PERIODS; i++) {482 for (i = 0; i < NUM_SAMPLE_PERIODS; i++) {
471 group = (tail + i) % NUM_SAMPLE_PERIODS;483 group = (tail + i) % NUM_SAMPLE_PERIODS;
@@ -740,6 +752,12 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) · 268 unmodified lines
740 if (!watchdog_enabled)752 if (!watchdog_enabled)
741 return HRTIMER_NORESTART;753 return HRTIMER_NORESTART;
742 754
755 /*
756 * pass the buddy check if a panic is in process
757 */
758 if (panic_in_progress())
759 return HRTIMER_NORESTART;
760
743 watchdog_hardlockup_kick();761 watchdog_hardlockup_kick();
744 762
745 /* kick the softlockup detector */763 /* kick the softlockup detector */
kernel/watchdog_perf.c+4−0
@@ -12,6 +12,7 @@ · 11 unmodified lines
12 12
13#define pr_fmt(fmt) "NMI watchdog: " fmt13#define pr_fmt(fmt) "NMI watchdog: " fmt
14 14
15#include <linux/panic.h>
15#include <linux/nmi.h>16#include <linux/nmi.h>
16#include <linux/atomic.h>17#include <linux/atomic.h>
17#include <linux/module.h>18#include <linux/module.h>
@@ -108,6 +109,9 @@ static void watchdog_overflow_callback(struct perf_event *event, · 90 unmodified lines
108 /* Ensure the watchdog never gets throttled */109 /* Ensure the watchdog never gets throttled */
109 event->hw.interrupts = 0;110 event->hw.interrupts = 0;
110 111
112 if (panic_in_progress())
113 return;
114
111 if (!watchdog_check_timestamp())115 if (!watchdog_check_timestamp())
112 return;116 return;
113 117
lib/Kconfig.debug+0−6
@@ -1067,12 +1067,6 @@ config PANIC_ON_OOPS · 1066 unmodified lines
1067 1067
1068 Say N if unsure.1068 Say N if unsure.
1069 1069
1070config PANIC_ON_OOPS_VALUE
1071 int
1072 range 0 1
1073 default 0 if !PANIC_ON_OOPS
1074 default 1 if PANIC_ON_OOPS
1075
1076config PANIC_TIMEOUT1070config PANIC_TIMEOUT
1077 int "panic timeout"1071 int "panic timeout"
1078 default 01072 default 0
lib/alloc_tag.c+2−1
@@ -9,6 +9,7 @@ · 8 unmodified lines
9#include <linux/proc_fs.h>9#include <linux/proc_fs.h>
10#include <linux/seq_buf.h>10#include <linux/seq_buf.h>
11#include <linux/seq_file.h>11#include <linux/seq_file.h>
12#include <linux/string_choices.h>
12#include <linux/vmalloc.h>13#include <linux/vmalloc.h>
13#include <linux/kmemleak.h>14#include <linux/kmemleak.h>
14 15
@@ -728,7 +729,7 @@ static int __init setup_early_mem_profiling(char *str) · 713 unmodified lines
728 }729 }
729 mem_profiling_support = true;730 mem_profiling_support = true;
730 pr_info("Memory allocation profiling is enabled %s compression and is turned %s!\n",731 pr_info("Memory allocation profiling is enabled %s compression and is turned %s!\n",
731 compressed ? "with" : "without", enable ? "on" : "off");732 compressed ? "with" : "without", str_on_off(enable));
732 }733 }
733 734
734 if (enable != mem_alloc_profiling_enabled()) {735 if (enable != mem_alloc_profiling_enabled()) {
lib/btree.c+2−2
@@ -653,9 +653,9 @@ int btree_merge(struct btree_head *target, struct btree_head *victim, · 652 unmodified lines
653 * walks to remove a single object from the victim.653 * walks to remove a single object from the victim.
654 */654 */
655 for (;;) {655 for (;;) {
656 if (!btree_last(victim, geo, key))656 val = btree_last(victim, geo, key);
657 if (!val)
657 break;658 break;
658 val = btree_lookup(victim, geo, key);
659 err = btree_insert(target, geo, key, val, gfp);659 err = btree_insert(target, geo, key, val, gfp);
660 if (err)660 if (err)
661 return err;661 return err;
lib/decompress.c+10−11
@@ -49,15 +49,15 @@ struct compress_format { · 48 unmodified lines
49};49};
50 50
51static const struct compress_format compressed_formats[] __initconst = {51static const struct compress_format compressed_formats[] __initconst = {
52 { {0x1f, 0x8b}, "gzip", gunzip },52 { .magic = {0x1f, 0x8b}, .name = "gzip", .decompressor = gunzip },
53 { {0x1f, 0x9e}, "gzip", gunzip },53 { .magic = {0x1f, 0x9e}, .name = "gzip", .decompressor = gunzip },
54 { {0x42, 0x5a}, "bzip2", bunzip2 },54 { .magic = {0x42, 0x5a}, .name = "bzip2", .decompressor = bunzip2 },
55 { {0x5d, 0x00}, "lzma", unlzma },55 { .magic = {0x5d, 0x00}, .name = "lzma", .decompressor = unlzma },
56 { {0xfd, 0x37}, "xz", unxz },56 { .magic = {0xfd, 0x37}, .name = "xz", .decompressor = unxz },
57 { {0x89, 0x4c}, "lzo", unlzo },57 { .magic = {0x89, 0x4c}, .name = "lzo", .decompressor = unlzo },
58 { {0x02, 0x21}, "lz4", unlz4 },58 { .magic = {0x02, 0x21}, .name = "lz4", .decompressor = unlz4 },
59 { {0x28, 0xb5}, "zstd", unzstd },59 { .magic = {0x28, 0xb5}, .name = "zstd", .decompressor = unzstd },
60 { {0, 0}, NULL, NULL }60 { /* sentinel */ }
61};61};
62 62
63decompress_fn __init decompress_method(const unsigned char *inbuf, long len,63decompress_fn __init decompress_method(const unsigned char *inbuf, long len,
@@ -73,11 +73,10 @@ decompress_fn __init decompress_method(const unsigned char *inbuf, long len, · 9 unmodified lines
73 73
74 pr_debug("Compressed data magic: %#.2x %#.2x\n", inbuf[0], inbuf[1]);74 pr_debug("Compressed data magic: %#.2x %#.2x\n", inbuf[0], inbuf[1]);
75 75
76 for (cf = compressed_formats; cf->name; cf++) {76 for (cf = compressed_formats; cf->name; cf++)
77 if (!memcmp(inbuf, cf->magic, 2))77 if (!memcmp(inbuf, cf->magic, 2))
78 break;78 break;
79 79
80 }
81 if (name)80 if (name)
82 *name = cf->name;81 *name = cf->name;
83 return cf->decompressor;82 return cf->decompressor;
lib/digsig.c+0−1
@@ -159,7 +159,6 @@ static int digsig_verify_rsa(struct key *key, · 158 unmodified lines
159 159
160 len = mlen;160 len = mlen;
161 head = len - l;161 head = len - l;
162 memset(out1, 0, head);
163 memcpy(out1 + head, p, l);162 memcpy(out1 + head, p, l);
164 163
165 kfree(p);164 kfree(p);
lib/dump_stack.c+1−1
@@ -102,7 +102,7 @@ static void __dump_stack(const char *log_lvl) · 101 unmodified lines
102 */102 */
103asmlinkage __visible void dump_stack_lvl(const char *log_lvl)103asmlinkage __visible void dump_stack_lvl(const char *log_lvl)
104{104{
105 bool in_panic = this_cpu_in_panic();105 bool in_panic = panic_on_this_cpu();
106 unsigned long flags;106 unsigned long flags;
107 107
108 /*108 /*
lib/fault-inject-usercopy.c+1−3
@@ -22,10 +22,8 @@ static int __init fail_usercopy_debugfs(void) · 21 unmodified lines
22 22
23 dir = fault_create_debugfs_attr("fail_usercopy", NULL,23 dir = fault_create_debugfs_attr("fail_usercopy", NULL,
24 &fail_usercopy.attr);24 &fail_usercopy.attr);
25 if (IS_ERR(dir))
26 return PTR_ERR(dir);
27 25
28 return 0;26 return PTR_ERR_OR_ZERO(dir);
29}27}
30 28
31late_initcall(fail_usercopy_debugfs);29late_initcall(fail_usercopy_debugfs);
lib/genalloc.c+4−1
@@ -899,8 +899,11 @@ struct gen_pool *of_gen_pool_get(struct device_node *np, · 898 unmodified lines
899 if (!name)899 if (!name)
900 name = of_node_full_name(np_pool);900 name = of_node_full_name(np_pool);
901 }901 }
902 if (pdev)902 if (pdev) {
903 pool = gen_pool_get(&pdev->dev, name);903 pool = gen_pool_get(&pdev->dev, name);
904 put_device(&pdev->dev);
905 }
906
904 of_node_put(np_pool);907 of_node_put(np_pool);
905 908
906 return pool;909 return pool;
lib/ref_tracker.c+3−3
@@ -75,7 +75,7 @@ ref_tracker_get_stats(struct ref_tracker_dir *dir, unsigned int limit) · 74 unmodified lines
75 struct ref_tracker *tracker;75 struct ref_tracker *tracker;
76 76
77 stats = kmalloc(struct_size(stats, stacks, limit),77 stats = kmalloc(struct_size(stats, stacks, limit),
78 GFP_NOWAIT | __GFP_NOWARN);78 GFP_NOWAIT);
79 if (!stats)79 if (!stats)
80 return ERR_PTR(-ENOMEM);80 return ERR_PTR(-ENOMEM);
81 stats->total = 0;81 stats->total = 0;
@@ -159,7 +159,7 @@ __ref_tracker_dir_pr_ostream(struct ref_tracker_dir *dir, · 77 unmodified lines
159 return;159 return;
160 }160 }
161 161
162 sbuf = kmalloc(STACK_BUF_SIZE, GFP_NOWAIT | __GFP_NOWARN);162 sbuf = kmalloc(STACK_BUF_SIZE, GFP_NOWAIT);
163 163
164 for (i = 0, skipped = stats->total; i < stats->count; ++i) {164 for (i = 0, skipped = stats->total; i < stats->count; ++i) {
165 stack = stats->stacks[i].stack_handle;165 stack = stats->stacks[i].stack_handle;
@@ -306,7 +306,7 @@ int ref_tracker_free(struct ref_tracker_dir *dir, · 140 unmodified lines
306 }306 }
307 nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 1);307 nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 1);
308 stack_handle = stack_depot_save(entries, nr_entries,308 stack_handle = stack_depot_save(entries, nr_entries,
309 GFP_NOWAIT | __GFP_NOWARN);309 GFP_NOWAIT);
310 310
311 spin_lock_irqsave(&dir->lock, flags);311 spin_lock_irqsave(&dir->lock, flags);
312 if (tracker->dead) {312 if (tracker->dead) {
lib/sys_info.c+2−1
@@ -55,7 +55,7 @@ int sysctl_sys_info_handler(const struct ctl_table *ro_table, int write, · 54 unmodified lines
55 void *buffer, size_t *lenp,55 void *buffer, size_t *lenp,
56 loff_t *ppos)56 loff_t *ppos)
57{57{
58 char names[sizeof(sys_info_avail) + 1];58 char names[sizeof(sys_info_avail)];
59 struct ctl_table table;59 struct ctl_table table;
60 unsigned long *si_bits_global;60 unsigned long *si_bits_global;
61 61
@@ -81,6 +81,7 @@ int sysctl_sys_info_handler(const struct ctl_table *ro_table, int write, · 19 unmodified lines
81 char *delim = "";81 char *delim = "";
82 int i, len = 0;82 int i, len = 0;
83 83
84 names[0] = '\0';
84 for (i = 0; i < ARRAY_SIZE(si_names); i++) {85 for (i = 0; i < ARRAY_SIZE(si_names); i++) {
85 if (*si_bits_global & si_names[i].bit) {86 if (*si_bits_global & si_names[i].bit) {
86 len += scnprintf(names + len, sizeof(names) - len,87 len += scnprintf(names + len, sizeof(names) - len,
lib/test_firmware.c+4−3
@@ -26,6 +26,7 @@ · 25 unmodified lines
26#include <linux/kthread.h>26#include <linux/kthread.h>
27#include <linux/vmalloc.h>27#include <linux/vmalloc.h>
28#include <linux/efi_embedded_fw.h>28#include <linux/efi_embedded_fw.h>
29#include <linux/string_choices.h>
29 30
30MODULE_IMPORT_NS("TEST_FIRMWARE");31MODULE_IMPORT_NS("TEST_FIRMWARE");
31 32
@@ -304,17 +305,17 @@ static ssize_t config_show(struct device *dev, · 272 unmodified lines
304 "FW_ACTION_NOUEVENT");305 "FW_ACTION_NOUEVENT");
305 len += scnprintf(buf + len, PAGE_SIZE - len,306 len += scnprintf(buf + len, PAGE_SIZE - len,
306 "into_buf:\t\t%s\n",307 "into_buf:\t\t%s\n",
307 test_fw_config->into_buf ? "true" : "false");308 str_true_false(test_fw_config->into_buf));
308 len += scnprintf(buf + len, PAGE_SIZE - len,309 len += scnprintf(buf + len, PAGE_SIZE - len,
309 "buf_size:\t%zu\n", test_fw_config->buf_size);310 "buf_size:\t%zu\n", test_fw_config->buf_size);
310 len += scnprintf(buf + len, PAGE_SIZE - len,311 len += scnprintf(buf + len, PAGE_SIZE - len,
311 "file_offset:\t%zu\n", test_fw_config->file_offset);312 "file_offset:\t%zu\n", test_fw_config->file_offset);
312 len += scnprintf(buf + len, PAGE_SIZE - len,313 len += scnprintf(buf + len, PAGE_SIZE - len,
313 "partial:\t\t%s\n",314 "partial:\t\t%s\n",
314 test_fw_config->partial ? "true" : "false");315 str_true_false(test_fw_config->partial));
315 len += scnprintf(buf + len, PAGE_SIZE - len,316 len += scnprintf(buf + len, PAGE_SIZE - len,
316 "sync_direct:\t\t%s\n",317 "sync_direct:\t\t%s\n",
317 test_fw_config->sync_direct ? "true" : "false");318 str_true_false(test_fw_config->sync_direct));
318 len += scnprintf(buf + len, PAGE_SIZE - len,319 len += scnprintf(buf + len, PAGE_SIZE - len,
319 "read_fw_idx:\t%u\n", test_fw_config->read_fw_idx);320 "read_fw_idx:\t%u\n", test_fw_config->read_fw_idx);
320 if (test_fw_config->upload_name)321 if (test_fw_config->upload_name)
scripts/checkpatch.pl+9−5
@@ -2636,6 +2636,11 @@ sub exclude_global_initialisers { · 2635 unmodified lines
2636 $realfile =~ m@/bpf/.*\.bpf\.c$@;2636 $realfile =~ m@/bpf/.*\.bpf\.c$@;
2637}2637}
2638 2638
2639sub is_userspace {
2640 my ($realfile) = @_;
2641 return ($realfile =~ m@^tools/@ || $realfile =~ m@^scripts/@);
2642}
2643
2639sub process {2644sub process {
2640 my $filename = shift;2645 my $filename = shift;
2641 2646
@@ -3294,7 +3299,7 @@ sub process { · 652 unmodified lines
3294 # file delta changes3299 # file delta changes
3295 $line =~ /^\s*(?:[\w\.\-\+]*\/)++[\w\.\-\+]+:/ ||3300 $line =~ /^\s*(?:[\w\.\-\+]*\/)++[\w\.\-\+]+:/ ||
3296 # filename then :3301 # filename then :
3297 $line =~ /^\s*(?:Fixes:|$link_tags_search|$signature_tags)/i ||3302 $line =~ /^\s*(?:Fixes:|https?:|$link_tags_search|$signature_tags)/i ||
3298 # A Fixes:, link or signature tag line3303 # A Fixes:, link or signature tag line
3299 $commit_log_possible_stack_dump)) {3304 $commit_log_possible_stack_dump)) {
3300 WARN("COMMIT_LOG_LONG_LINE",3305 WARN("COMMIT_LOG_LONG_LINE",
@@ -7018,21 +7023,20 @@ sub process { · 3717 unmodified lines
7018# }7023# }
7019# }7024# }
7020# }7025# }
7021
7022# strcpy uses that should likely be strscpy7026# strcpy uses that should likely be strscpy
7023 if ($line =~ /\bstrcpy\s*\(/) {7027 if ($line =~ /\bstrcpy\s*\(/ && !is_userspace($realfile)) {
7024 WARN("STRCPY",7028 WARN("STRCPY",
7025 "Prefer strscpy over strcpy - see: https://github.com/KSPP/linux/issues/88\n" . $herecurr);7029 "Prefer strscpy over strcpy - see: https://github.com/KSPP/linux/issues/88\n" . $herecurr);
7026 }7030 }
7027 7031
7028# strlcpy uses that should likely be strscpy7032# strlcpy uses that should likely be strscpy
7029 if ($line =~ /\bstrlcpy\s*\(/) {7033 if ($line =~ /\bstrlcpy\s*\(/ && !is_userspace($realfile)) {
7030 WARN("STRLCPY",7034 WARN("STRLCPY",
7031 "Prefer strscpy over strlcpy - see: https://github.com/KSPP/linux/issues/89\n" . $herecurr);7035 "Prefer strscpy over strlcpy - see: https://github.com/KSPP/linux/issues/89\n" . $herecurr);
7032 }7036 }
7033 7037
7034# strncpy uses that should likely be strscpy or strscpy_pad7038# strncpy uses that should likely be strscpy or strscpy_pad
7035 if ($line =~ /\bstrncpy\s*\(/) {7039 if ($line =~ /\bstrncpy\s*\(/ && !is_userspace($realfile)) {
7036 WARN("STRNCPY",7040 WARN("STRNCPY",
7037 "Prefer strscpy, strscpy_pad, or __nonstring over strncpy - see: https://github.com/KSPP/linux/issues/90\n" . $herecurr);7041 "Prefer strscpy, strscpy_pad, or __nonstring over strncpy - see: https://github.com/KSPP/linux/issues/90\n" . $herecurr);
7038 }7042 }
scripts/coccinelle/api/platform_no_drv_owner.cocci+9−0
@@ -10,12 +10,21 @@ virtual org · 9 unmodified lines
10virtual report10virtual report
11 11
12@match1@12@match1@
13declarer name builtin_i2c_driver;
14declarer name builtin_platform_driver;
15declarer name builtin_platform_driver_probe;
13declarer name module_i2c_driver;16declarer name module_i2c_driver;
14declarer name module_platform_driver;17declarer name module_platform_driver;
15declarer name module_platform_driver_probe;18declarer name module_platform_driver_probe;
16identifier __driver;19identifier __driver;
17@@20@@
18(21(
22 builtin_i2c_driver(__driver);
23|
24 builtin_platform_driver(__driver);
25|
26 builtin_platform_driver_probe(__driver, ...);
27|
19 module_i2c_driver(__driver);28 module_i2c_driver(__driver);
20|29|
21 module_platform_driver(__driver);30 module_platform_driver(__driver);
scripts/coccinelle/misc/of_table.cocci+7−7
@@ -1,5 +1,5 @@
1// SPDX-License-Identifier: GPL-2.01// SPDX-License-Identifier: GPL-2.0
2/// Make sure (of/i2c/platform)_device_id tables are NULL terminated2/// Make sure (of/i2c/platform/spi)_device_id tables are NULL terminated
3//3//
4// Keywords: of_table i2c_table platform_table4// Keywords: of_table i2c_table platform_table
5// Confidence: Medium5// Confidence: Medium
@@ -15,14 +15,14 @@ identifier var, arr; · 9 unmodified lines
15expression E;15expression E;
16@@16@@
17(17(
18struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {18struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
19 ...,19 ...,
20 {20 {
21 .var = E,21 .var = E,
22* }22* }
23};23};
24|24|
25struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {25struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
26 ...,26 ...,
27* { ..., E, ... },27* { ..., E, ... },
28};28};
@@ -33,7 +33,7 @@ identifier var, arr; · 4 unmodified lines
33expression E;33expression E;
34@@34@@
35(35(
36struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {36struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
37 ...,37 ...,
38 {38 {
39 .var = E,39 .var = E,
@@ -42,7 +42,7 @@ struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = { · 2 unmodified lines
42+ { }42+ { }
43};43};
44|44|
45struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {45struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
46 ...,46 ...,
47 { ..., E, ... },47 { ..., E, ... },
48+ { },48+ { },
@@ -55,7 +55,7 @@ identifier var, arr; · 6 unmodified lines
55expression E;55expression E;
56@@56@@
57(57(
58struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {58struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
59 ...,59 ...,
60 {60 {
61 .var = E,61 .var = E,
@@ -63,7 +63,7 @@ struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = { · 1 unmodified line
63 @p163 @p1
64};64};
65|65|
66struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {66struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
67 ...,67 ...,
68 { ..., E, ... }68 { ..., E, ... }
69 @p169 @p1
tools/accounting/delaytop.c+427−144
@@ -42,14 +42,13 @@ · 41 unmodified lines
42#include <linux/genetlink.h>42#include <linux/genetlink.h>
43#include <linux/taskstats.h>43#include <linux/taskstats.h>
44#include <linux/cgroupstats.h>44#include <linux/cgroupstats.h>
45#include <stddef.h>
45 46
46#define PSI_CPU_SOME "/proc/pressure/cpu"47#define PSI_PATH "/proc/pressure"
47#define PSI_CPU_FULL "/proc/pressure/cpu"48#define PSI_CPU_PATH "/proc/pressure/cpu"
48#define PSI_MEMORY_SOME "/proc/pressure/memory"49#define PSI_MEMORY_PATH "/proc/pressure/memory"
49#define PSI_MEMORY_FULL "/proc/pressure/memory"50#define PSI_IO_PATH "/proc/pressure/io"
50#define PSI_IO_SOME "/proc/pressure/io"51#define PSI_IRQ_PATH "/proc/pressure/irq"
51#define PSI_IO_FULL "/proc/pressure/io"
52#define PSI_IRQ_FULL "/proc/pressure/irq"
53 52
54#define NLA_NEXT(na) ((struct nlattr *)((char *)(na) + NLA_ALIGN((na)->nla_len)))53#define NLA_NEXT(na) ((struct nlattr *)((char *)(na) + NLA_ALIGN((na)->nla_len)))
55#define NLA_DATA(na) ((void *)((char *)(na) + NLA_HDRLEN))54#define NLA_DATA(na) ((void *)((char *)(na) + NLA_HDRLEN))
@@ -61,24 +60,28 @@ · 5 unmodified lines
61#define TASK_COMM_LEN 1660#define TASK_COMM_LEN 16
62#define MAX_MSG_SIZE 102461#define MAX_MSG_SIZE 1024
63#define MAX_TASKS 100062#define MAX_TASKS 1000
63#define MAX_BUF_LEN 256
64#define SET_TASK_STAT(task_count, field) tasks[task_count].field = stats.field64#define SET_TASK_STAT(task_count, field) tasks[task_count].field = stats.field
65#define BOOL_FPRINT(stream, fmt, ...) \65#define BOOL_FPRINT(stream, fmt, ...) \
66({ \66({ \
67 int ret = fprintf(stream, fmt, ##__VA_ARGS__); \67 int ret = fprintf(stream, fmt, ##__VA_ARGS__); \
68 ret >= 0; \68 ret >= 0; \
69})69})
70#define TASK_AVG(task, field) average_ms((task).field##_delay_total, (task).field##_count)
70#define PSI_LINE_FORMAT "%-12s %6.1f%%/%6.1f%%/%6.1f%%/%8llu(ms)\n"71#define PSI_LINE_FORMAT "%-12s %6.1f%%/%6.1f%%/%6.1f%%/%8llu(ms)\n"
71 72#define DELAY_FMT_DEFAULT "%8.2f %8.2f %8.2f %8.2f\n"
72/* Program settings structure */73#define DELAY_FMT_MEMVERBOSE "%8.2f %8.2f %8.2f %8.2f %8.2f %8.2f\n"
73struct config {74#define SORT_FIELD(name, cmd, modes) \
74 int delay; /* Update interval in seconds */75 {#name, #cmd, \
75 int iterations; /* Number of iterations, 0 == infinite */76 offsetof(struct task_info, name##_delay_total), \
76 int max_processes; /* Maximum number of processes to show */77 offsetof(struct task_info, name##_count), \
77 char sort_field; /* Field to sort by */78 modes}
78 int output_one_time; /* Output once and exit */79#define END_FIELD {NULL, 0, 0}
79 int monitor_pid; /* Monitor specific PID */80
80 char *container_path; /* Path to container cgroup */81/* Display mode types */
81};82#define MODE_TYPE_ALL (0xFFFFFFFF)
83#define MODE_DEFAULT (1 << 0)
84#define MODE_MEMVERBOSE (1 << 1)
82 85
83/* PSI statistics structure */86/* PSI statistics structure */
84struct psi_stats {87struct psi_stats {
@@ -119,6 +122,8 @@ struct task_info { · 34 unmodified lines
119 unsigned long long wpcopy_delay_total;122 unsigned long long wpcopy_delay_total;
120 unsigned long long irq_count;123 unsigned long long irq_count;
121 unsigned long long irq_delay_total;124 unsigned long long irq_delay_total;
125 unsigned long long mem_count;
126 unsigned long long mem_delay_total;
122};127};
123 128
124/* Container statistics structure */129/* Container statistics structure */
@@ -130,6 +135,27 @@ struct container_stats { · 5 unmodified lines
130 int nr_io_wait; /* Number of processes in IO wait */135 int nr_io_wait; /* Number of processes in IO wait */
131};136};
132 137
138/* Delay field structure */
139struct field_desc {
140 const char *name; /* Field name for cmdline argument */
141 const char *cmd_char; /* Interactive command */
142 unsigned long total_offset; /* Offset of total delay in task_info */
143 unsigned long count_offset; /* Offset of count in task_info */
144 size_t supported_modes; /* Supported display modes */
145};
146
147/* Program settings structure */
148struct config {
149 int delay; /* Update interval in seconds */
150 int iterations; /* Number of iterations, 0 == infinite */
151 int max_processes; /* Maximum number of processes to show */
152 int output_one_time; /* Output once and exit */
153 int monitor_pid; /* Monitor specific PID */
154 char *container_path; /* Path to container cgroup */
155 const struct field_desc *sort_field; /* Current sort field */
156 size_t display_mode; /* Current display mode */
157};
158
133/* Global variables */159/* Global variables */
134static struct config cfg;160static struct config cfg;
135static struct psi_stats psi;161static struct psi_stats psi;
@@ -137,6 +163,19 @@ static struct task_info tasks[MAX_TASKS]; · 1 unmodified line
137static int task_count;163static int task_count;
138static int running = 1;164static int running = 1;
139static struct container_stats container_stats;165static struct container_stats container_stats;
166static const struct field_desc sort_fields[] = {
167 SORT_FIELD(cpu, c, MODE_DEFAULT),
168 SORT_FIELD(blkio, i, MODE_DEFAULT),
169 SORT_FIELD(irq, q, MODE_DEFAULT),
170 SORT_FIELD(mem, m, MODE_DEFAULT | MODE_MEMVERBOSE),
171 SORT_FIELD(swapin, s, MODE_MEMVERBOSE),
172 SORT_FIELD(freepages, r, MODE_MEMVERBOSE),
173 SORT_FIELD(thrashing, t, MODE_MEMVERBOSE),
174 SORT_FIELD(compact, p, MODE_MEMVERBOSE),
175 SORT_FIELD(wpcopy, w, MODE_MEMVERBOSE),
176 END_FIELD
177};
178static int sort_selected;
140 179
141/* Netlink socket variables */180/* Netlink socket variables */
142static int nl_sd = -1;181static int nl_sd = -1;
@@ -158,18 +197,75 @@ static void disable_raw_mode(void) · 15 unmodified lines
158 tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);197 tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);
159}198}
160 199
200/* Find field descriptor by command line */
201static const struct field_desc *get_field_by_cmd_char(char ch)
202{
203 const struct field_desc *field;
204
205 for (field = sort_fields; field->name != NULL; field++) {
206 if (field->cmd_char[0] == ch)
207 return field;
208 }
209
210 return NULL;
211}
212
213/* Find field descriptor by name with string comparison */
214static const struct field_desc *get_field_by_name(const char *name)
215{
216 const struct field_desc *field;
217 size_t field_len;
218
219 for (field = sort_fields; field->name != NULL; field++) {
220 field_len = strlen(field->name);
221 if (field_len != strlen(name))
222 continue;
223 if (strncmp(field->name, name, field_len) == 0)
224 return field;
225 }
226
227 return NULL;
228}
229
230/* Find display name for a field descriptor */
231static const char *get_name_by_field(const struct field_desc *field)
232{
233 return field ? field->name : "UNKNOWN";
234}
235
236/* Generate string of available field names */
237static void display_available_fields(size_t mode)
238{
239 const struct field_desc *field;
240 char buf[MAX_BUF_LEN];
241
242 buf[0] = '\0';
243
244 for (field = sort_fields; field->name != NULL; field++) {
245 if (!(field->supported_modes & mode))
246 continue;
247 strncat(buf, "|", MAX_BUF_LEN - strlen(buf) - 1);
248 strncat(buf, field->name, MAX_BUF_LEN - strlen(buf) - 1);
249 buf[MAX_BUF_LEN - 1] = '\0';
250 }
251
252 fprintf(stderr, "Available fields: %s\n", buf);
253}
254
161/* Display usage information and command line options */255/* Display usage information and command line options */
162static void usage(void)256static void usage(void)
163{257{
164 printf("Usage: delaytop [Options]\n"258 printf("Usage: delaytop [Options]\n"
165 "Options:\n"259 "Options:\n"
166 " -h, --help Show this help message and exit\n"260 " -h, --help Show this help message and exit\n"
167 " -d, --delay=SECONDS Set refresh interval (default: 2 seconds, min: 1)\n"261 " -d, --delay=SECONDS Set refresh interval (default: 2 seconds, min: 1)\n"
168 " -n, --iterations=COUNT Set number of updates (default: 0 = infinite)\n"262 " -n, --iterations=COUNT Set number of updates (default: 0 = infinite)\n"
169 " -P, --processes=NUMBER Set maximum number of processes to show (default: 20, max: 1000)\n"263 " -P, --processes=NUMBER Set maximum number of processes to show (default: 20, max: 1000)\n"
170 " -o, --once Display once and exit\n"264 " -o, --once Display once and exit\n"
171 " -p, --pid=PID Monitor only the specified PID\n"265 " -p, --pid=PID Monitor only the specified PID\n"
172 " -C, --container=PATH Monitor the container at specified cgroup path\n");266 " -C, --container=PATH Monitor the container at specified cgroup path\n"
267 " -s, --sort=FIELD Sort by delay field (default: cpu)\n"
268 " -M, --memverbose Display memory detailed information\n");
173 exit(0);269 exit(0);
174}270}
175 271
@@ -177,6 +273,7 @@ static void usage(void) · 1 unmodified line
177static void parse_args(int argc, char **argv)273static void parse_args(int argc, char **argv)
178{274{
179 int c;275 int c;
276 const struct field_desc *field;
180 struct option long_options[] = {277 struct option long_options[] = {
181 {"help", no_argument, 0, 'h'},278 {"help", no_argument, 0, 'h'},
182 {"delay", required_argument, 0, 'd'},279 {"delay", required_argument, 0, 'd'},
@@ -184,7 +281,9 @@ static void parse_args(int argc, char **argv) · 1 unmodified line
184 {"pid", required_argument, 0, 'p'},281 {"pid", required_argument, 0, 'p'},
185 {"once", no_argument, 0, 'o'},282 {"once", no_argument, 0, 'o'},
186 {"processes", required_argument, 0, 'P'},283 {"processes", required_argument, 0, 'P'},
284 {"sort", required_argument, 0, 's'},
187 {"container", required_argument, 0, 'C'},285 {"container", required_argument, 0, 'C'},
286 {"memverbose", no_argument, 0, 'M'},
188 {0, 0, 0, 0}287 {0, 0, 0, 0}
189 };288 };
190 289
@@ -192,15 +291,16 @@ static void parse_args(int argc, char **argv) · 1 unmodified line
192 cfg.delay = 2;291 cfg.delay = 2;
193 cfg.iterations = 0;292 cfg.iterations = 0;
194 cfg.max_processes = 20;293 cfg.max_processes = 20;
195 cfg.sort_field = 'c'; /* Default sort by CPU delay */294 cfg.sort_field = &sort_fields[0]; /* Default sorted by CPU delay */
196 cfg.output_one_time = 0;295 cfg.output_one_time = 0;
197 cfg.monitor_pid = 0; /* 0 means monitor all PIDs */296 cfg.monitor_pid = 0; /* 0 means monitor all PIDs */
198 cfg.container_path = NULL;297 cfg.container_path = NULL;
298 cfg.display_mode = MODE_DEFAULT;
199 299
200 while (1) {300 while (1) {
201 int option_index = 0;301 int option_index = 0;
202 302
203 c = getopt_long(argc, argv, "hd:n:p:oP:C:", long_options, &option_index);303 c = getopt_long(argc, argv, "hd:n:p:oP:C:s:M", long_options, &option_index);
204 if (c == -1)304 if (c == -1)
205 break;305 break;
206 306
@@ -247,6 +347,26 @@ static void parse_args(int argc, char **argv) · 40 unmodified lines
247 case 'C':347 case 'C':
248 cfg.container_path = strdup(optarg);348 cfg.container_path = strdup(optarg);
249 break;349 break;
350 case 's':
351 if (strlen(optarg) == 0) {
352 fprintf(stderr, "Error: empty sort field\n");
353 exit(1);
354 }
355
356 field = get_field_by_name(optarg);
357 /* Show available fields if invalid option provided */
358 if (!field) {
359 fprintf(stderr, "Error: invalid sort field '%s'\n", optarg);
360 display_available_fields(MODE_TYPE_ALL);
361 exit(1);
362 }
363
364 cfg.sort_field = field;
365 break;
366 case 'M':
367 cfg.display_mode = MODE_MEMVERBOSE;
368 cfg.sort_field = get_field_by_name("mem");
369 break;
250 default:370 default:
251 fprintf(stderr, "Try 'delaytop --help' for more information.\n");371 fprintf(stderr, "Try 'delaytop --help' for more information.\n");
252 exit(1);372 exit(1);
@@ -254,6 +374,25 @@ static void parse_args(int argc, char **argv) · 1 unmodified line
254 }374 }
255}375}
256 376
377/* Calculate average delay in milliseconds for overall memory */
378static void set_mem_delay_total(struct task_info *t)
379{
380 t->mem_delay_total = t->swapin_delay_total +
381 t->freepages_delay_total +
382 t->thrashing_delay_total +
383 t->compact_delay_total +
384 t->wpcopy_delay_total;
385}
386
387static void set_mem_count(struct task_info *t)
388{
389 t->mem_count = t->swapin_count +
390 t->freepages_count +
391 t->thrashing_count +
392 t->compact_count +
393 t->wpcopy_count;
394}
395
257/* Create a raw netlink socket and bind */396/* Create a raw netlink socket and bind */
258static int create_nl_socket(void)397static int create_nl_socket(void)
259{398{
@@ -358,87 +497,134 @@ static int get_family_id(int sd) · 98 unmodified lines
358 return id;497 return id;
359}498}
360 499
361static void read_psi_stats(void)500static int read_psi_stats(void)
362{501{
363 FILE *fp;502 FILE *fp;
364 char line[256];503 char line[256];
365 int ret = 0;504 int ret = 0;
505 int error_count = 0;
506
507 /* Check if PSI path exists */
508 if (access(PSI_PATH, F_OK) != 0) {
509 fprintf(stderr, "Error: PSI interface not found at %s\n", PSI_PATH);
510 fprintf(stderr, "Please ensure your kernel supports PSI (Pressure Stall Information)\n");
511 return -1;
512 }
513
366 /* Zero all fields */514 /* Zero all fields */
367 memset(&psi, 0, sizeof(psi));515 memset(&psi, 0, sizeof(psi));
516
368 /* CPU pressure */517 /* CPU pressure */
369 fp = fopen(PSI_CPU_SOME, "r");518 fp = fopen(PSI_CPU_PATH, "r");
370 if (fp) {519 if (fp) {
371 while (fgets(line, sizeof(line), fp)) {520 while (fgets(line, sizeof(line), fp)) {
372 if (strncmp(line, "some", 4) == 0) {521 if (strncmp(line, "some", 4) == 0) {
373 ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",522 ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
374 &psi.cpu_some_avg10, &psi.cpu_some_avg60,523 &psi.cpu_some_avg10, &psi.cpu_some_avg60,
375 &psi.cpu_some_avg300, &psi.cpu_some_total);524 &psi.cpu_some_avg300, &psi.cpu_some_total);
376 if (ret != 4)525 if (ret != 4) {
377 fprintf(stderr, "Failed to parse CPU some PSI data\n");526 fprintf(stderr, "Failed to parse CPU some PSI data\n");
527 error_count++;
528 }
378 } else if (strncmp(line, "full", 4) == 0) {529 } else if (strncmp(line, "full", 4) == 0) {
379 ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",530 ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
380 &psi.cpu_full_avg10, &psi.cpu_full_avg60,531 &psi.cpu_full_avg10, &psi.cpu_full_avg60,
381 &psi.cpu_full_avg300, &psi.cpu_full_total);532 &psi.cpu_full_avg300, &psi.cpu_full_total);
382 if (ret != 4)533 if (ret != 4) {
383 fprintf(stderr, "Failed to parse CPU full PSI data\n");534 fprintf(stderr, "Failed to parse CPU full PSI data\n");
535 error_count++;
536 }
384 }537 }
385 }538 }
386 fclose(fp);539 fclose(fp);
540 } else {
541 fprintf(stderr, "Warning: Failed to open %s\n", PSI_CPU_PATH);
542 error_count++;
387 }543 }
544
388 /* Memory pressure */545 /* Memory pressure */
389 fp = fopen(PSI_MEMORY_SOME, "r");546 fp = fopen(PSI_MEMORY_PATH, "r");
390 if (fp) {547 if (fp) {
391 while (fgets(line, sizeof(line), fp)) {548 while (fgets(line, sizeof(line), fp)) {
392 if (strncmp(line, "some", 4) == 0) {549 if (strncmp(line, "some", 4) == 0) {
393 ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",550 ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
394 &psi.memory_some_avg10, &psi.memory_some_avg60,551 &psi.memory_some_avg10, &psi.memory_some_avg60,
395 &psi.memory_some_avg300, &psi.memory_some_total);552 &psi.memory_some_avg300, &psi.memory_some_total);
396 if (ret != 4)553 if (ret != 4) {
397 fprintf(stderr, "Failed to parse Memory some PSI data\n");554 fprintf(stderr, "Failed to parse Memory some PSI data\n");
555 error_count++;
556 }
398 } else if (strncmp(line, "full", 4) == 0) {557 } else if (strncmp(line, "full", 4) == 0) {
399 ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",558 ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
400 &psi.memory_full_avg10, &psi.memory_full_avg60,559 &psi.memory_full_avg10, &psi.memory_full_avg60,
401 &psi.memory_full_avg300, &psi.memory_full_total);560 &psi.memory_full_avg300, &psi.memory_full_total);
402 }561 if (ret != 4) {
403 if (ret != 4)
404 fprintf(stderr, "Failed to parse Memory full PSI data\n");562 fprintf(stderr, "Failed to parse Memory full PSI data\n");
563 error_count++;
564 }
565 }
405 }566 }
406 fclose(fp);567 fclose(fp);
568 } else {
569 fprintf(stderr, "Warning: Failed to open %s\n", PSI_MEMORY_PATH);
570 error_count++;
407 }571 }
572
408 /* IO pressure */573 /* IO pressure */
409 fp = fopen(PSI_IO_SOME, "r");574 fp = fopen(PSI_IO_PATH, "r");
410 if (fp) {575 if (fp) {
411 while (fgets(line, sizeof(line), fp)) {576 while (fgets(line, sizeof(line), fp)) {
412 if (strncmp(line, "some", 4) == 0) {577 if (strncmp(line, "some", 4) == 0) {
413 ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",578 ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
414 &psi.io_some_avg10, &psi.io_some_avg60,579 &psi.io_some_avg10, &psi.io_some_avg60,
415 &psi.io_some_avg300, &psi.io_some_total);580 &psi.io_some_avg300, &psi.io_some_total);
416 if (ret != 4)581 if (ret != 4) {
417 fprintf(stderr, "Failed to parse IO some PSI data\n");582 fprintf(stderr, "Failed to parse IO some PSI data\n");
583 error_count++;
584 }
418 } else if (strncmp(line, "full", 4) == 0) {585 } else if (strncmp(line, "full", 4) == 0) {
419 ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",586 ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
420 &psi.io_full_avg10, &psi.io_full_avg60,587 &psi.io_full_avg10, &psi.io_full_avg60,
421 &psi.io_full_avg300, &psi.io_full_total);588 &psi.io_full_avg300, &psi.io_full_total);
422 if (ret != 4)589 if (ret != 4) {
423 fprintf(stderr, "Failed to parse IO full PSI data\n");590 fprintf(stderr, "Failed to parse IO full PSI data\n");
591 error_count++;
592 }
424 }593 }
425 }594 }
426 fclose(fp);595 fclose(fp);
596 } else {
597 fprintf(stderr, "Warning: Failed to open %s\n", PSI_IO_PATH);
598 error_count++;
427 }599 }
600
428 /* IRQ pressure (only full) */601 /* IRQ pressure (only full) */
429 fp = fopen(PSI_IRQ_FULL, "r");602 fp = fopen(PSI_IRQ_PATH, "r");
430 if (fp) {603 if (fp) {
431 while (fgets(line, sizeof(line), fp)) {604 while (fgets(line, sizeof(line), fp)) {
432 if (strncmp(line, "full", 4) == 0) {605 if (strncmp(line, "full", 4) == 0) {
433 ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",606 ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
434 &psi.irq_full_avg10, &psi.irq_full_avg60,607 &psi.irq_full_avg10, &psi.irq_full_avg60,
435 &psi.irq_full_avg300, &psi.irq_full_total);608 &psi.irq_full_avg300, &psi.irq_full_total);
436 if (ret != 4)609 if (ret != 4) {
437 fprintf(stderr, "Failed to parse IRQ full PSI data\n");610 fprintf(stderr, "Failed to parse IRQ full PSI data\n");
611 error_count++;
612 }
438 }613 }
439 }614 }
440 fclose(fp);615 fclose(fp);
616 } else {
617 fprintf(stderr, "Warning: Failed to open %s\n", PSI_IRQ_PATH);
618 error_count++;
619 }
620
621 /* Return error count: 0 means success, >0 means warnings, -1 means fatal error */
622 if (error_count > 0) {
623 fprintf(stderr, "PSI stats reading completed with %d warnings\n", error_count);
624 return error_count;
441 }625 }
626
627 return 0;
442}628}
443 629
444static int read_comm(int pid, char *comm_buf, size_t buf_size)630static int read_comm(int pid, char *comm_buf, size_t buf_size)
@@ -527,6 +713,8 @@ static void fetch_and_fill_task_info(int pid, const char *comm) · 82 unmodified lines
527 SET_TASK_STAT(task_count, wpcopy_delay_total);713 SET_TASK_STAT(task_count, wpcopy_delay_total);
528 SET_TASK_STAT(task_count, irq_count);714 SET_TASK_STAT(task_count, irq_count);
529 SET_TASK_STAT(task_count, irq_delay_total);715 SET_TASK_STAT(task_count, irq_delay_total);
716 set_mem_count(&tasks[task_count]);
717 set_mem_delay_total(&tasks[task_count]);
530 task_count++;718 task_count++;
531 }719 }
532 break;720 break;
@@ -587,19 +775,23 @@ static int compare_tasks(const void *a, const void *b) · 54 unmodified lines
587{775{
588 const struct task_info *t1 = (const struct task_info *)a;776 const struct task_info *t1 = (const struct task_info *)a;
589 const struct task_info *t2 = (const struct task_info *)b;777 const struct task_info *t2 = (const struct task_info *)b;
778 unsigned long long total1;
779 unsigned long long total2;
780 unsigned long count1;
781 unsigned long count2;
590 double avg1, avg2;782 double avg1, avg2;
591 783
592 switch (cfg.sort_field) {784 total1 = *(unsigned long long *)((char *)t1 + cfg.sort_field->total_offset);
593 case 'c': /* CPU */785 total2 = *(unsigned long long *)((char *)t2 + cfg.sort_field->total_offset);
594 avg1 = average_ms(t1->cpu_delay_total, t1->cpu_count);786 count1 = *(unsigned long *)((char *)t1 + cfg.sort_field->count_offset);
595 avg2 = average_ms(t2->cpu_delay_total, t2->cpu_count);787 count2 = *(unsigned long *)((char *)t2 + cfg.sort_field->count_offset);
596 if (avg1 != avg2)
597 return avg2 > avg1 ? 1 : -1;
598 return t2->cpu_delay_total > t1->cpu_delay_total ? 1 : -1;
599 788
600 default:789 avg1 = average_ms(total1, count1);
601 return t2->cpu_delay_total > t1->cpu_delay_total ? 1 : -1;790 avg2 = average_ms(total2, count2);
602 }791 if (avg1 != avg2)
792 return avg2 > avg1 ? 1 : -1;
793
794 return 0;
603}795}
604 796
605/* Sort tasks by selected field */797/* Sort tasks by selected field */
@@ -673,7 +865,7 @@ static void get_container_stats(void) · 67 unmodified lines
673}865}
674 866
675/* Display results to stdout or log file */867/* Display results to stdout or log file */
676static void display_results(void)868static void display_results(int psi_ret)
677{869{
678 time_t now = time(NULL);870 time_t now = time(NULL);
679 struct tm *tm_now = localtime(&now);871 struct tm *tm_now = localtime(&now);
@@ -686,49 +878,53 @@ static void display_results(void) · 6 unmodified lines
686 suc &= BOOL_FPRINT(out, "\033[H\033[J");878 suc &= BOOL_FPRINT(out, "\033[H\033[J");
687 879
688 /* PSI output (one-line, no cat style) */880 /* PSI output (one-line, no cat style) */
689 suc &= BOOL_FPRINT(out, "System Pressure Information: (avg10/avg60/avg300/total)\n");881 suc &= BOOL_FPRINT(out, "System Pressure Information: (avg10/avg60vg300/total)\n");
690 suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,882 if (psi_ret) {
691 "CPU some:",883 suc &= BOOL_FPRINT(out, " PSI not found: check if psi=1 enabled in cmdline\n");
692 psi.cpu_some_avg10,884 } else {
693 psi.cpu_some_avg60,885 suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
694 psi.cpu_some_avg300,886 "CPU some:",
695 psi.cpu_some_total / 1000);887 psi.cpu_some_avg10,
696 suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,888 psi.cpu_some_avg60,
697 "CPU full:",889 psi.cpu_some_avg300,
698 psi.cpu_full_avg10,890 psi.cpu_some_total / 1000);
699 psi.cpu_full_avg60,891 suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
700 psi.cpu_full_avg300,892 "CPU full:",
701 psi.cpu_full_total / 1000);893 psi.cpu_full_avg10,
702 suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,894 psi.cpu_full_avg60,
703 "Memory full:",895 psi.cpu_full_avg300,
704 psi.memory_full_avg10,896 psi.cpu_full_total / 1000);
705 psi.memory_full_avg60,897 suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
706 psi.memory_full_avg300,898 "Memory full:",
707 psi.memory_full_total / 1000);899 psi.memory_full_avg10,
708 suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,900 psi.memory_full_avg60,
709 "Memory some:",901 psi.memory_full_avg300,
710 psi.memory_some_avg10,902 psi.memory_full_total / 1000);
711 psi.memory_some_avg60,903 suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
712 psi.memory_some_avg300,904 "Memory some:",
713 psi.memory_some_total / 1000);905 psi.memory_some_avg10,
714 suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,906 psi.memory_some_avg60,
715 "IO full:",907 psi.memory_some_avg300,
716 psi.io_full_avg10,908 psi.memory_some_total / 1000);
717 psi.io_full_avg60,909 suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
718 psi.io_full_avg300,910 "IO full:",
719 psi.io_full_total / 1000);911 psi.io_full_avg10,
720 suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,912 psi.io_full_avg60,
721 "IO some:",913 psi.io_full_avg300,
722 psi.io_some_avg10,914 psi.io_full_total / 1000);
723 psi.io_some_avg60,915 suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
724 psi.io_some_avg300,916 "IO some:",
725 psi.io_some_total / 1000);917 psi.io_some_avg10,
726 suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,918 psi.io_some_avg60,
727 "IRQ full:",919 psi.io_some_avg300,
728 psi.irq_full_avg10,920 psi.io_some_total / 1000);
729 psi.irq_full_avg60,921 suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
730 psi.irq_full_avg300,922 "IRQ full:",
731 psi.irq_full_total / 1000);923 psi.irq_full_avg10,
924 psi.irq_full_avg60,
925 psi.irq_full_avg300,
926 psi.irq_full_total / 1000);
927 }
732 928
733 if (cfg.container_path) {929 if (cfg.container_path) {
734 suc &= BOOL_FPRINT(out, "Container Information (%s):\n", cfg.container_path);930 suc &= BOOL_FPRINT(out, "Container Information (%s):\n", cfg.container_path);
@@ -738,29 +934,59 @@ static void display_results(void) · 3 unmodified lines
738 container_stats.nr_stopped, container_stats.nr_uninterruptible,934 container_stats.nr_stopped, container_stats.nr_uninterruptible,
739 container_stats.nr_io_wait);935 container_stats.nr_io_wait);
740 }936 }
741 suc &= BOOL_FPRINT(out, "Top %d processes (sorted by CPU delay):\n",
742 cfg.max_processes);
743 suc &= BOOL_FPRINT(out, "%5s %5s %-17s", "PID", "TGID", "COMMAND");
744 suc &= BOOL_FPRINT(out, "%7s %7s %7s %7s %7s %7s %7s %7s\n",
745 "CPU(ms)", "IO(ms)", "SWAP(ms)", "RCL(ms)",
746 "THR(ms)", "CMP(ms)", "WP(ms)", "IRQ(ms)");
747 937
748 suc &= BOOL_FPRINT(out, "-----------------------------------------------");938 /* Interacive command */
749 suc &= BOOL_FPRINT(out, "----------------------------------------------\n");939 suc &= BOOL_FPRINT(out, "[o]sort [M]memverbose [q]quit\n");
940 if (sort_selected) {
941 if (cfg.display_mode == MODE_MEMVERBOSE)
942 suc &= BOOL_FPRINT(out,
943 "sort selection: [m]MEM [r]RCL [t]THR [p]CMP [w]WP\n");
944 else
945 suc &= BOOL_FPRINT(out,
946 "sort selection: [c]CPU [i]IO [m]MEM [q]IRQ\n");
947 }
948
949 /* Task delay output */
950 suc &= BOOL_FPRINT(out, "Top %d processes (sorted by %s delay):\n",
951 cfg.max_processes, get_name_by_field(cfg.sort_field));
952
953 suc &= BOOL_FPRINT(out, "%8s %8s %-17s", "PID", "TGID", "COMMAND");
954 if (cfg.display_mode == MODE_MEMVERBOSE) {
955 suc &= BOOL_FPRINT(out, "%8s %8s %8s %8s %8s %8s\n",
956 "MEM(ms)", "SWAP(ms)", "RCL(ms)",
957 "THR(ms)", "CMP(ms)", "WP(ms)");
958 suc &= BOOL_FPRINT(out, "-----------------------");
959 suc &= BOOL_FPRINT(out, "-----------------------");
960 suc &= BOOL_FPRINT(out, "-----------------------");
961 suc &= BOOL_FPRINT(out, "---------------------\n");
962 } else {
963 suc &= BOOL_FPRINT(out, "%8s %8s %8s %8s\n",
964 "CPU(ms)", "IO(ms)", "IRQ(ms)", "MEM(ms)");
965 suc &= BOOL_FPRINT(out, "-----------------------");
966 suc &= BOOL_FPRINT(out, "-----------------------");
967 suc &= BOOL_FPRINT(out, "--------------------------\n");
968 }
969
750 count = task_count < cfg.max_processes ? task_count : cfg.max_processes;970 count = task_count < cfg.max_processes ? task_count : cfg.max_processes;
751 971
752 for (i = 0; i < count; i++) {972 for (i = 0; i < count; i++) {
753 suc &= BOOL_FPRINT(out, "%5d %5d %-15s",973 suc &= BOOL_FPRINT(out, "%8d %8d %-15s",
754 tasks[i].pid, tasks[i].tgid, tasks[i].command);974 tasks[i].pid, tasks[i].tgid, tasks[i].command);
755 suc &= BOOL_FPRINT(out, "%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n",975 if (cfg.display_mode == MODE_MEMVERBOSE) {
756 average_ms(tasks[i].cpu_delay_total, tasks[i].cpu_count),976 suc &= BOOL_FPRINT(out, DELAY_FMT_MEMVERBOSE,
757 average_ms(tasks[i].blkio_delay_total, tasks[i].blkio_count),977 TASK_AVG(tasks[i], mem),
758 average_ms(tasks[i].swapin_delay_total, tasks[i].swapin_count),978 TASK_AVG(tasks[i], swapin),
759 average_ms(tasks[i].freepages_delay_total, tasks[i].freepages_count),979 TASK_AVG(tasks[i], freepages),
760 average_ms(tasks[i].thrashing_delay_total, tasks[i].thrashing_count),980 TASK_AVG(tasks[i], thrashing),
761 average_ms(tasks[i].compact_delay_total, tasks[i].compact_count),981 TASK_AVG(tasks[i], compact),
762 average_ms(tasks[i].wpcopy_delay_total, tasks[i].wpcopy_count),982 TASK_AVG(tasks[i], wpcopy));
763 average_ms(tasks[i].irq_delay_total, tasks[i].irq_count));983 } else {
984 suc &= BOOL_FPRINT(out, DELAY_FMT_DEFAULT,
985 TASK_AVG(tasks[i], cpu),
986 TASK_AVG(tasks[i], blkio),
987 TASK_AVG(tasks[i], irq),
988 TASK_AVG(tasks[i], mem));
989 }
764 }990 }
765 991
766 suc &= BOOL_FPRINT(out, "\n");992 suc &= BOOL_FPRINT(out, "\n");
@@ -769,11 +995,79 @@ static void display_results(void) · 2 unmodified lines
769 perror("Error writing to output");995 perror("Error writing to output");
770}996}
771 997
998/* Check for keyboard input with timeout based on cfg.delay */
999static char check_for_keypress(void)
1000{
1001 struct timeval tv = {cfg.delay, 0};
1002 fd_set readfds;
1003 char ch = 0;
1004
1005 FD_ZERO(&readfds);
1006 FD_SET(STDIN_FILENO, &readfds);
1007 int r = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &tv);
1008
1009 if (r > 0 && FD_ISSET(STDIN_FILENO, &readfds)) {
1010 read(STDIN_FILENO, &ch, 1);
1011 return ch;
1012 }
1013
1014 return 0;
1015}
1016
1017#define MAX_MODE_SIZE 2
1018static void toggle_display_mode(void)
1019{
1020 static const size_t modes[MAX_MODE_SIZE] = {MODE_DEFAULT, MODE_MEMVERBOSE};
1021 static size_t cur_index;
1022
1023 cur_index = (cur_index + 1) % MAX_MODE_SIZE;
1024 cfg.display_mode = modes[cur_index];
1025}
1026
1027/* Handle keyboard input: sorting selection, mode toggle, or quit */
1028static void handle_keypress(char ch, int *running)
1029{
1030 const struct field_desc *field;
1031
1032 /* Change sort field */
1033 if (sort_selected) {
1034 field = get_field_by_cmd_char(ch);
1035 if (field && (field->supported_modes & cfg.display_mode))
1036 cfg.sort_field = field;
1037
1038 sort_selected = 0;
1039 /* Handle mode changes or quit */
1040 } else {
1041 switch (ch) {
1042 case 'o':
1043 sort_selected = 1;
1044 break;
1045 case 'M':
1046 toggle_display_mode();
1047 for (field = sort_fields; field->name != NULL; field++) {
1048 if (field->supported_modes & cfg.display_mode) {
1049 cfg.sort_field = field;
1050 break;
1051 }
1052 }
1053 break;
1054 case 'q':
1055 case 'Q':
1056 *running = 0;
1057 break;
1058 default:
1059 break;
1060 }
1061 }
1062}
1063
772/* Main function */1064/* Main function */
773int main(int argc, char **argv)1065int main(int argc, char **argv)
774{1066{
1067 const struct field_desc *field;
775 int iterations = 0;1068 int iterations = 0;
776 int use_q_quit = 0;1069 int psi_ret = 0;
1070 char keypress;
777 1071
778 /* Parse command line arguments */1072 /* Parse command line arguments */
779 parse_args(argc, argv);1073 parse_args(argc, argv);
@@ -793,17 +1087,24 @@ int main(int argc, char **argv) · 13 unmodified lines
793 exit(1);1087 exit(1);
794 }1088 }
795 1089
796 if (!cfg.output_one_time) {1090 /* Set terminal to non-canonical mode for interaction */
797 use_q_quit = 1;1091 enable_raw_mode();
798 enable_raw_mode();
799 printf("Press 'q' to quit.\n");
800 fflush(stdout);
801 }
802 1092
803 /* Main loop */1093 /* Main loop */
804 while (running) {1094 while (running) {
1095 /* Auto-switch sort field when not matching display mode */
1096 if (!(cfg.sort_field->supported_modes & cfg.display_mode)) {
1097 for (field = sort_fields; field->name != NULL; field++) {
1098 if (field->supported_modes & cfg.display_mode) {
1099 cfg.sort_field = field;
1100 printf("Auto-switched sort field to: %s\n", field->name);
1101 break;
1102 }
1103 }
1104 }
1105
805 /* Read PSI statistics */1106 /* Read PSI statistics */
806 read_psi_stats();1107 psi_ret = read_psi_stats();
807 1108
808 /* Get container stats if container path provided */1109 /* Get container stats if container path provided */
809 if (cfg.container_path)1110 if (cfg.container_path)
@@ -816,7 +1117,7 @@ int main(int argc, char **argv) · 6 unmodified lines
816 sort_tasks();1117 sort_tasks();
817 1118
818 /* Display results to stdout or log file */1119 /* Display results to stdout or log file */
819 display_results();1120 display_results(psi_ret);
820 1121
821 /* Check for iterations */1122 /* Check for iterations */
822 if (cfg.iterations > 0 && ++iterations >= cfg.iterations)1123 if (cfg.iterations > 0 && ++iterations >= cfg.iterations)
@@ -826,32 +1127,14 @@ int main(int argc, char **argv) · 3 unmodified lines
826 if (cfg.output_one_time)1127 if (cfg.output_one_time)
827 break;1128 break;
828 1129
829 /* Check for 'q' key to quit */1130 /* Keypress for interactive usage */
830 if (use_q_quit) {1131 keypress = check_for_keypress();
831 struct timeval tv = {cfg.delay, 0};1132 if (keypress)
832 fd_set readfds;1133 handle_keypress(keypress, &running);
833
834 FD_ZERO(&readfds);
835 FD_SET(STDIN_FILENO, &readfds);
836 int r = select(STDIN_FILENO+1, &readfds, NULL, NULL, &tv);
837
838 if (r > 0 && FD_ISSET(STDIN_FILENO, &readfds)) {
839 char ch = 0;
840
841 read(STDIN_FILENO, &ch, 1);
842 if (ch == 'q' || ch == 'Q') {
843 running = 0;
844 break;
845 }
846 }
847 } else {
848 sleep(cfg.delay);
849 }
850 }1134 }
851 1135
852 /* Restore terminal mode */1136 /* Restore terminal mode */
853 if (use_q_quit)1137 disable_raw_mode();
854 disable_raw_mode();
855 1138
856 /* Cleanup */1139 /* Cleanup */
857 close(nl_sd);1140 close(nl_sd);
tools/testing/radix-tree/idr-test.c+7−9
@@ -499,19 +499,17 @@ void ida_check_random(void) · 498 unmodified lines
499 goto repeat;499 goto repeat;
500}500}
501 501
502void ida_simple_get_remove_test(void)502void ida_alloc_free_test(void)
503{503{
504 DEFINE_IDA(ida);504 DEFINE_IDA(ida);
505 unsigned long i;505 unsigned long i;
506 506
507 for (i = 0; i < 10000; i++) {507 for (i = 0; i < 10000; i++)
508 assert(ida_simple_get(&ida, 0, 20000, GFP_KERNEL) == i);508 assert(ida_alloc_max(&ida, 20000, GFP_KERNEL) == i);
509 }509 assert(ida_alloc_range(&ida, 5, 30, GFP_KERNEL) < 0);
510 assert(ida_simple_get(&ida, 5, 30, GFP_KERNEL) < 0);
511 510
512 for (i = 0; i < 10000; i++) {511 for (i = 0; i < 10000; i++)
513 ida_simple_remove(&ida, i);512 ida_free(&ida, i);
514 }
515 assert(ida_is_empty(&ida));513 assert(ida_is_empty(&ida));
516 514
517 ida_destroy(&ida);515 ida_destroy(&ida);
@@ -524,7 +522,7 @@ void user_ida_checks(void) · 6 unmodified lines
524 ida_check_nomem();522 ida_check_nomem();
525 ida_check_conv_user();523 ida_check_conv_user();
526 ida_check_random();524 ida_check_random();
527 ida_simple_get_remove_test();525 ida_alloc_free_test();
528 526
529 radix_tree_cpu_dead(1);527 radix_tree_cpu_dead(1);
530}528}
tools/testing/selftests/proc/.gitignore+1−0
@@ -7,6 +7,7 @@ · 6 unmodified lines
7/proc-loadavg-0017/proc-loadavg-001
8/proc-maps-race8/proc-maps-race
9/proc-multiple-procfs9/proc-multiple-procfs
10/proc-net-dev-lseek
10/proc-empty-vm11/proc-empty-vm
11/proc-pid-vm12/proc-pid-vm
12/proc-self-map-files-00113/proc-self-map-files-001
tools/testing/selftests/proc/Makefile+1−0
@@ -10,6 +10,7 @@ TEST_GEN_PROGS += fd-003-kthread · 9 unmodified lines
10TEST_GEN_PROGS += proc-2-is-kthread10TEST_GEN_PROGS += proc-2-is-kthread
11TEST_GEN_PROGS += proc-loadavg-00111TEST_GEN_PROGS += proc-loadavg-001
12TEST_GEN_PROGS += proc-maps-race12TEST_GEN_PROGS += proc-maps-race
13TEST_GEN_PROGS += proc-net-dev-lseek
13TEST_GEN_PROGS += proc-empty-vm14TEST_GEN_PROGS += proc-empty-vm
14TEST_GEN_PROGS += proc-pid-vm15TEST_GEN_PROGS += proc-pid-vm
15TEST_GEN_PROGS += proc-self-map-files-00116TEST_GEN_PROGS += proc-self-map-files-001
tools/testing/selftests/proc/proc-net-dev-lseek.c+68−0
@@ -0,0 +1,68 @@
1/*
2 * Copyright (c) 2025 Alexey Dobriyan <adobriyan@gmail.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16#undef _GNU_SOURCE
17#define _GNU_SOURCE
18#undef NDEBUG
19#include <assert.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <string.h>
23#include <unistd.h>
24#include <sched.h>
25/*
26 * Test that lseek("/proc/net/dev/", 0, SEEK_SET)
27 * a) works,
28 * b) does what you think it does.
29 */
30int main(void)
31{
32 /* /proc/net/dev output is deterministic in fresh netns only. */
33 if (unshare(CLONE_NEWNET) == -1) {
34 if (errno == ENOSYS || errno == EPERM) {
35 return 4;
36 }
37 return 1;
38 }
39
40 const int fd = open("/proc/net/dev", O_RDONLY);
41 assert(fd >= 0);
42
43 char buf1[4096];
44 const ssize_t rv1 = read(fd, buf1, sizeof(buf1));
45 /*
46 * Not "<=", this file can't be empty:
47 * there is header, "lo" interface with some zeroes.
48 */
49 assert(0 < rv1);
50 assert(rv1 <= sizeof(buf1));
51
52 /* Believe it or not, this line broke one day. */
53 assert(lseek(fd, 0, SEEK_SET) == 0);
54
55 char buf2[4096];
56 const ssize_t rv2 = read(fd, buf2, sizeof(buf2));
57 /* Not "<=", see above. */
58 assert(0 < rv2);
59 assert(rv2 <= sizeof(buf2));
60
61 /* Test that lseek rewinds to the beginning of the file. */
62 assert(rv1 == rv2);
63 assert(memcmp(buf1, buf2, rv1) == 0);
64
65 /* Contents of the file is not validated: this test is about lseek(). */
66
67 return 0;
68}
tools/testing/selftests/proc/proc-pid-vm.c+8−4
@@ -47,6 +47,10 @@ · 46 unmodified lines
47#include <sys/resource.h>47#include <sys/resource.h>
48#include <linux/fs.h>48#include <linux/fs.h>
49 49
50#ifndef __maybe_unused
51#define __maybe_unused __attribute__((__unused__))
52#endif
53
50#include "../kselftest.h"54#include "../kselftest.h"
51 55
52static inline long sys_execveat(int dirfd, const char *pathname, char **argv, char **envp, int flags)56static inline long sys_execveat(int dirfd, const char *pathname, char **argv, char **envp, int flags)
@@ -218,12 +222,12 @@ static int make_exe(const uint8_t *payload, size_t len) · 165 unmodified lines
218 * 2: vsyscall VMA is r-xp vsyscall=emulate222 * 2: vsyscall VMA is r-xp vsyscall=emulate
219 */223 */
220static volatile int g_vsyscall;224static volatile int g_vsyscall;
221static const char *str_vsyscall;225static const char *str_vsyscall __maybe_unused;
222 226
223static const char str_vsyscall_0[] = "";227static const char str_vsyscall_0[] __maybe_unused = "";
224static const char str_vsyscall_1[] =228static const char str_vsyscall_1[] __maybe_unused =
225"ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]\n";229"ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]\n";
226static const char str_vsyscall_2[] =230static const char str_vsyscall_2[] __maybe_unused =
227"ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n";231"ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n";
228 232
229#ifdef __x86_64__233#ifdef __x86_64__

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t