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
721721 Shuah Khan <shuah@kernel.org> <shuah.khan@hp.com>
722722 Shuah Khan <shuah@kernel.org> <shuahkh@osg.samsung.com>
723723 Shuah Khan <shuah@kernel.org> <shuah.kh@samsung.com>
724−Sibi Sankar <quic_sibis@quicinc.com> <sibis@codeaurora.org>
724+Sibi Sankar <sibi.sankar@oss.qualcomm.com> <sibis@codeaurora.org>
725+Sibi Sankar <sibi.sankar@oss.qualcomm.com> <quic_sibis@quicinc.com>
725726 Sid Manning <quic_sidneym@quicinc.com> <sidneym@codeaurora.org>
726727 Simon Arlott <simon@octiron.net> <simon@fire.lp0.eu>
727728 Simona 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
134134
135135 After the system starts, use `delaytop` to get the system-wide delay information,
136136 which includes system-wide PSI information and Top-N high-latency tasks.
137+Note: PSI support requires `CONFIG_PSI=y` and `psi=1` for full functionality.
137138
138−`delaytop` supports sorting by CPU latency in descending order by default,
139−displays the top 20 high-latency tasks by default, and refreshes the latency
140−data every 2 seconds by default.
139+`delaytop` is an interactive tool for monitoring system pressure and task delays.
140+It supports multiple sorting options, display modes, and real-time keyboard controls.
141141
142−Get PSI information and Top-N tasks delay, since system boot::
142+Basic usage with default settings (sorts by CPU delay, shows top 20 tasks, refreshes every 2 seconds)::
143143
144144 bash# ./delaytop
145− System Pressure Information: (avg10/avg60/avg300/total)
146− CPU some: 0.0%/ 0.0%/ 0.0%/ 345(ms)
145+ System Pressure Information: (avg10/avg60vg300/total)
146+ CPU some: 0.0%/ 0.0%/ 0.0%/ 106137(ms)
147147 CPU full: 0.0%/ 0.0%/ 0.0%/ 0(ms)
148148 Memory full: 0.0%/ 0.0%/ 0.0%/ 0(ms)
149149 Memory some: 0.0%/ 0.0%/ 0.0%/ 0(ms)
150− IO full: 0.0%/ 0.0%/ 0.0%/ 65(ms)
151− IO some: 0.0%/ 0.0%/ 0.0%/ 79(ms)
150+ IO full: 0.0%/ 0.0%/ 0.0%/ 2240(ms)
151+ IO some: 0.0%/ 0.0%/ 0.0%/ 2783(ms)
152152 IRQ full: 0.0%/ 0.0%/ 0.0%/ 0(ms)
153− Top 20 processes (sorted by CPU delay):
154− PID TGID COMMAND CPU(ms) IO(ms) SWAP(ms) RCL(ms) THR(ms) CMP(ms) WP(ms) IRQ(ms)
155− ----------------------------------------------------------------------------------------------
156− 161 161 zombie_memcg_re 1.40 0.00 0.00 0.00 0.00 0.00 0.00 0.00
157− 130 130 blkcg_punt_bio 1.37 0.00 0.00 0.00 0.00 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.00
159− 1280 1280 rsyslogd 0.53 0.04 0.00 0.00 0.00 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.00
161− 1277 1277 nbd-server 0.44 0.00 0.00 0.00 0.00 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.00
163− 55 55 netns 0.36 0.00 0.00 0.00 0.00 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.00
165− 6184 6184 kworker/1:2-sys 0.24 0.00 0.00 0.00 0.00 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.00
167− 18 18 ksoftirqd/1 0.24 0.00 0.00 0.00 0.00 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.00
169− 190 190 kstrp 0.23 0.00 0.00 0.00 0.00 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.00
171− 1190 1190 kworker/0:3-sys 0.19 0.00 0.00 0.00 0.00 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.00
173− 1156 1156 license 0.15 0.11 0.00 0.00 0.00 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.00
175− 6142 6142 kworker/3:2-xfs 0.13 0.00 0.00 0.00 0.00 0.00 0.00 0.00
176−
177−Dynamic interactive interface of delaytop::
153+ [o]sort [M]memverbose [q]quit
154+ Top 20 processes (sorted by cpu delay):
155+ PID TGID COMMAND CPU(ms) IO(ms) IRQ(ms) MEM(ms)
156+ ------------------------------------------------------------------------
157+ 110 110 kworker/15:0H-s 27.91 0.00 0.00 0.00
158+ 57 57 cpuhp/7 3.18 0.00 0.00 0.00
159+ 99 99 cpuhp/14 2.97 0.00 0.00 0.00
160+ 51 51 cpuhp/6 0.90 0.00 0.00 0.00
161+ 44 44 kworker/4:0H-sy 0.80 0.00 0.00 0.00
162+ 60 60 ksoftirqd/7 0.74 0.00 0.00 0.00
163+ 76 76 idle_inject/10 0.31 0.00 0.00 0.00
164+ 100 100 idle_inject/14 0.30 0.00 0.00 0.00
165+ 1309 1309 systemsettings 0.29 0.00 0.00 0.00
166+ 45 45 cpuhp/5 0.22 0.00 0.00 0.00
167+ 63 63 cpuhp/8 0.20 0.00 0.00 0.00
168+ 87 87 cpuhp/12 0.18 0.00 0.00 0.00
169+ 93 93 cpuhp/13 0.17 0.00 0.00 0.00
170+ 1265 1265 acpid 0.17 0.00 0.00 0.00
171+ 1552 1552 sshd 0.17 0.00 0.00 0.00
172+ 2584 2584 sddm-helper 0.16 0.00 0.00 0.00
173+ 1284 1284 rtkit-daemon 0.15 0.00 0.00 0.00
174+ 1326 1326 nde-netfilter 0.14 0.00 0.00 0.00
175+ 27 27 cpuhp/2 0.13 0.00 0.00 0.00
176+ 631 631 kworker/11:2-rc 0.11 0.00 0.00 0.00
177+
178+Interactive 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+
184+Available 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+
196+Advanced 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
178203
179204 # ./delaytop -p pid
180205 Print delayacct stats
Documentation/admin-guide/kernel-parameters.txt+1−1
@@ -4603,7 +4603,7 @@ · 4602 unmodified lines
46034603 bit 2: print timer info
46044604 bit 3: print locks info if CONFIG_LOCKDEP is on
46054605 bit 4: print ftrace buffer
4606− bit 5: replay all messages on consoles at the end of panic
4606+ bit 5: replay all kernel messages on consoles at the end of panic
46074607 bit 6: print all CPUs backtrace (if available in the arch)
46084608 bit 7: print only tasks in uninterruptible (blocked) state
46094609 *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
890890 bit 2 print timer info
891891 bit 3 print locks info if ``CONFIG_LOCKDEP`` is on
892892 bit 4 print ftrace buffer
893−bit 5 replay all messages on consoles at the end of panic
893+bit 5 replay all kernel messages on consoles at the end of panic
894894 bit 6 print all CPUs backtrace (if available in the arch)
895895 bit 7 print only tasks in uninterruptible (blocked) state
896896 ===== ============================================
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
361361 */
362362 sleep(2);
363363
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);
365370 for (i = 0; i < n; i++)
366371 printf("0x%lx\n", cover[i + 1]);
367372 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
2098720987 F: drivers/pmdomain/qcom/cpr.c
2098820988
2098920989 QUALCOMM CPUCP MAILBOX DRIVER
20990−M: Sibi Sankar <quic_sibis@quicinc.com>
20990+M: Sibi Sankar <sibi.sankar@oss.qualcomm.com>
2099120991 L: linux-arm-msm@vger.kernel.org
2099220992 S: Supported
2099320993 F: 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
165165 /*
166166 * Exclusion of crash region, crashk_low_res and/or crashk_cma_ranges
167167 * 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.
168178 */
169− nr_ranges += 2 + crashk_cma_cnt;
179+ nr_ranges += 3 + crashk_cma_cnt;
170180 cmem = vzalloc(struct_size(cmem, ranges, nr_ranges));
171181 if (!cmem)
172182 return NULL;
173183
174184 cmem->max_nr_ranges = nr_ranges;
175− cmem->nr_ranges = 0;
176185
177186 return cmem;
178187 }
@@ -323,16 +332,20 @@ int crash_setup_memmap_entries(struct kimage *image, struct boot_params *params) · 144 unmodified lines
323332 struct crash_mem *cmem;
324333
325334 /*
326− * Using random kexec_buf for passing dm crypt keys may cause a range
327− * split. So use two slots here.
335+ * In the current x86 architecture code, the elfheader is always
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.
328342 */
329− nr_ranges = 2;
343+ nr_ranges = 3;
330344 cmem = vzalloc(struct_size(cmem, ranges, nr_ranges));
331345 if (!cmem)
332346 return -ENOMEM;
333347
334348 cmem->max_nr_ranges = nr_ranges;
335− cmem->nr_ranges = 0;
336349
337350 memset(&cmd, 0, sizeof(struct crash_memmap_data));
338351 cmd.params = params;
arch/x86/kernel/kexec-bzimage64.c+44−3
@@ -16,6 +16,8 @@ · 15 unmodified lines
1616 #include <linux/kexec.h>
1717 #include <linux/kernel.h>
1818 #include <linux/mm.h>
19+#include <linux/libfdt.h>
20+#include <linux/of_fdt.h>
1921 #include <linux/efi.h>
2022 #include <linux/random.h>
2123
@@ -212,6 +214,28 @@ setup_efi_state(struct boot_params *params, unsigned long params_load_addr, · 190 unmodified lines
212214 }
213215 #endif /* CONFIG_EFI */
214216
217+#ifdef CONFIG_OF_FLATTREE
218+static 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+
215239 static void
216240 setup_ima_state(const struct kimage *image, struct boot_params *params,
217241 unsigned long params_load_addr,
@@ -336,6 +360,17 @@ setup_boot_parameters(struct kimage *image, struct boot_params *params, · 118 unmodified lines
336360 sizeof(struct efi_setup_data);
337361 #endif
338362
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+
339374 if (IS_ENABLED(CONFIG_IMA_KEXEC)) {
340375 /* Setup IMA log buffer state */
341376 setup_ima_state(image, params, params_load_addr,
@@ -529,6 +564,12 @@ static void *bzImage64_load(struct kimage *image, char *kernel, · 187 unmodified lines
529564 sizeof(struct setup_data) +
530565 RNG_SEED_LENGTH;
531566
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+
532573 if (IS_ENABLED(CONFIG_IMA_KEXEC))
533574 kbuf.bufsz += sizeof(struct setup_data) +
534575 sizeof(struct ima_setup_data);
@@ -537,7 +578,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel, · 2 unmodified lines
537578 kbuf.bufsz += sizeof(struct setup_data) +
538579 sizeof(struct kho_data);
539580
540− params = kzalloc(kbuf.bufsz, GFP_KERNEL);
581+ params = kvzalloc(kbuf.bufsz, GFP_KERNEL);
541582 if (!params)
542583 return ERR_PTR(-ENOMEM);
543584 efi_map_offset = params_cmdline_sz;
@@ -647,7 +688,7 @@ static void *bzImage64_load(struct kimage *image, char *kernel, · 103 unmodified lines
647688 return ldata;
648689
649690 out_free_params:
650− kfree(params);
691+ kvfree(params);
651692 return ERR_PTR(ret);
652693 }
653694
@@ -659,7 +700,7 @@ static int bzImage64_cleanup(void *loader_data) · 5 unmodified lines
659700 if (!ldata)
660701 return 0;
661702
662− kfree(ldata->bootparams_buf);
703+ kvfree(ldata->bootparams_buf);
663704 ldata->bootparams_buf = NULL;
664705
665706 return 0;
drivers/firmware/efi/efi-init.c+25−4
@@ -12,6 +12,7 @@ · 11 unmodified lines
1212 #include <linux/efi.h>
1313 #include <linux/fwnode.h>
1414 #include <linux/init.h>
15+#include <linux/kexec_handover.h>
1516 #include <linux/memblock.h>
1617 #include <linux/mm_types.h>
1718 #include <linux/of.h>
@@ -164,12 +165,32 @@ static __init void reserve_regions(void) · 146 unmodified lines
164165 pr_info("Processing EFI memory map:\n");
165166
166167 /*
167− * Discard memblocks discovered so far: if there are any at this
168− * point, they originate from memory nodes in the DT, and UEFI
169− * uses its own memory map instead.
168+ * Discard memblocks discovered so far except for KHO scratch
169+ * regions. Most memblocks at this point originate from memory nodes
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.
170173 */
171174 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+ }
173194
174195 for_each_efi_memory_desc(md) {
175196 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
279279
280280 static bool fbcon_skip_panic(struct fb_info *info)
281281 {
282−/* panic_cpu is not exported, and can't be used if built as module. Use
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
282+ return (info->skip_panic && unlikely(panic_in_progress()));
290283 }
291284
292285 static 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
421421 vm_fault_t vmf;
422422 unsigned long off = i * PAGE_SIZE;
423423 vmf = vmf_insert_mixed(vma, vma->vm_start + off,
424− address + off);
424+ PHYS_PFN(address + off));
425425 if (vmf & VM_FAULT_ERROR)
426426 ret = vm_fault_to_errno(vmf, 0);
427427 }
fs/fat/dir.c+3−4
@@ -1209,7 +1209,7 @@ EXPORT_SYMBOL_GPL(fat_alloc_new_dir); · 1208 unmodified lines
12091209
12101210 static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots,
12111211 int *nr_cluster, struct msdos_dir_entry **de,
1212− struct buffer_head **bh, loff_t *i_pos)
1212+ struct buffer_head **bh)
12131213 {
12141214 struct super_block *sb = dir->i_sb;
12151215 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
12691269 get_bh(bhs[n]);
12701270 *bh = bhs[n];
12711271 *de = (struct msdos_dir_entry *)((*bh)->b_data + offset);
1272− *i_pos = fat_make_i_pos(sb, *bh, *de);
12731272
12741273 /* Second stage: clear the rest of cluster, and write outs */
12751274 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
12981297 struct buffer_head *bh, *prev, *bhs[3]; /* 32*slots (672bytes) */
12991298 struct msdos_dir_entry *de;
13001299 int err, free_slots, i, nr_bhs;
1301− loff_t pos, i_pos;
1300+ loff_t pos;
13021301
13031302 sinfo->nr_slots = nr_slots;
13041303
@@ -1386,7 +1385,7 @@ found: · 81 unmodified lines
13861385 * add the cluster to dir.
13871386 */
13881387 cluster = fat_add_new_entries(dir, slots, nr_slots, &nr_cluster,
1389− &de, &bh, &i_pos);
1388+ &de, &bh);
13901389 if (cluster < 0) {
13911390 err = cluster;
13921391 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
69286928
69296929 out:
69306930 if (ret != 0) {
6931− if (folios)
6932− ocfs2_unlock_and_free_folios(folios, numfolios);
6931+ ocfs2_unlock_and_free_folios(folios, numfolios);
69336932 numfolios = 0;
69346933 }
69356934
fs/ocfs2/dlm/dlmmaster.c+0−11
@@ -1477,7 +1477,6 @@ way_up_top: · 1476 unmodified lines
14771477 goto send_response;
14781478 } else if (res->owner != DLM_LOCK_RES_OWNER_UNKNOWN) {
14791479 spin_unlock(&res->spinlock);
1480− // mlog(0, "node %u is the master\n", res->owner);
14811480 response = DLM_MASTER_RESP_NO;
14821481 if (mle)
14831482 kmem_cache_free(dlm_mle_cache, mle);
@@ -1493,7 +1492,6 @@ way_up_top: · 9 unmodified lines
14931492 BUG();
14941493 }
14951494
1496− // mlog(0, "lockres is in progress...\n");
14971495 spin_lock(&dlm->master_lock);
14981496 found = dlm_find_mle(dlm, &tmpmle, name, namelen);
14991497 if (!found) {
@@ -1503,8 +1501,6 @@ way_up_top: · 3 unmodified lines
15031501 set_maybe = 1;
15041502 spin_lock(&tmpmle->spinlock);
15051503 if (tmpmle->type == DLM_MLE_BLOCK) {
1506− // mlog(0, "this node is waiting for "
1507− // "lockres to be mastered\n");
15081504 response = DLM_MASTER_RESP_NO;
15091505 } else if (tmpmle->type == DLM_MLE_MIGRATION) {
15101506 mlog(0, "node %u is master, but trying to migrate to "
@@ -1531,8 +1527,6 @@ way_up_top: · 20 unmodified lines
15311527 } else
15321528 response = DLM_MASTER_RESP_NO;
15331529 } else {
1534− // mlog(0, "this node is attempting to "
1535− // "master lockres\n");
15361530 response = DLM_MASTER_RESP_MAYBE;
15371531 }
15381532 if (set_maybe)
@@ -1559,7 +1553,6 @@ way_up_top: · 20 unmodified lines
15591553 found = dlm_find_mle(dlm, &tmpmle, name, namelen);
15601554 if (!found) {
15611555 /* this lockid has never been seen on this node yet */
1562− // mlog(0, "no mle found\n");
15631556 if (!mle) {
15641557 spin_unlock(&dlm->master_lock);
15651558 spin_unlock(&dlm->spinlock);
@@ -1573,8 +1566,6 @@ way_up_top: · 7 unmodified lines
15731566 goto way_up_top;
15741567 }
15751568
1576− // mlog(0, "this is second time thru, already allocated, "
1577− // "add the block.\n");
15781569 dlm_init_mle(mle, DLM_MLE_BLOCK, dlm, NULL, name, namelen);
15791570 set_bit(request->node_idx, mle->maybe_map);
15801571 __dlm_insert_mle(dlm, mle);
@@ -1897,8 +1888,6 @@ ok: · 316 unmodified lines
18971888 spin_unlock(&res->spinlock);
18981889 }
18991890
1900− // mlog(0, "woo! got an assert_master from node %u!\n",
1901− // assert->node_idx);
19021891 if (mle) {
19031892 int extra_ref = 0;
19041893 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
464464 }
465465
466466 if (dlm->reco.dead_node == O2NM_INVALID_NODE_NUM) {
467− // mlog(0, "nothing to recover! sleeping now!\n");
468467 spin_unlock(&dlm->spinlock);
469468 /* return to main thread loop and sleep. */
470469 return 0;
fs/ocfs2/inode.c+8−0
@@ -1495,6 +1495,14 @@ int ocfs2_validate_inode_block(struct super_block *sb, · 1494 unmodified lines
14951495 goto bail;
14961496 }
14971497
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+
14981506 rc = 0;
14991507
15001508 bail:
fs/ocfs2/ioctl.c+7−11
@@ -358,13 +358,11 @@ static int ocfs2_info_handle_freeinode(struct inode *inode, · 357 unmodified lines
358358 goto bail;
359359 }
360360 } else {
361− ocfs2_sprintf_system_inode_name(namebuf,
362− sizeof(namebuf),
363− type, i);
361+ int len = ocfs2_sprintf_system_inode_name(namebuf,
362+ sizeof(namebuf),
363+ type, i);
364364 status = ocfs2_lookup_ino_from_name(osb->sys_root_inode,
365− namebuf,
366− strlen(namebuf),
367− &blkno);
365+ namebuf, len, &blkno);
368366 if (status < 0) {
369367 status = -ENOENT;
370368 goto bail;
@@ -651,12 +649,10 @@ static int ocfs2_info_handle_freefrag(struct inode *inode, · 280 unmodified lines
651649 goto bail;
652650 }
653651 } else {
654− ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type,
655− OCFS2_INVALID_SLOT);
652+ int len = ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf),
653+ type, OCFS2_INVALID_SLOT);
656654 status = ocfs2_lookup_ino_from_name(osb->sys_root_inode,
657− namebuf,
658− strlen(namebuf),
659− &blkno);
655+ namebuf, len, &blkno);
660656 if (status < 0) {
661657 status = -ENOENT;
662658 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
364364 int *vict_bit,
365365 struct buffer_head **ret_bh)
366366 {
367− int ret, i, bits_per_unit = 0;
367+ int ret, i, len, bits_per_unit = 0;
368368 u64 blkno;
369369 char namebuf[40];
370370
@@ -375,9 +375,9 @@ static int ocfs2_find_victim_alloc_group(struct inode *inode, · 4 unmodified lines
375375 struct ocfs2_dinode *ac_dinode;
376376 struct ocfs2_group_desc *bg;
377377
378− ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type, slot);
379− ret = ocfs2_lookup_ino_from_name(osb->sys_root_inode, namebuf,
380− strlen(namebuf), &blkno);
378+ len = ocfs2_sprintf_system_inode_name(namebuf, sizeof(namebuf), type, slot);
379+ ret = ocfs2_lookup_ino_from_name(osb->sys_root_inode, namebuf, len, &blkno);
380+
381381 if (ret) {
382382 ret = -ENOENT;
383383 goto out;
fs/ocfs2/ocfs2_fs.h+1−1
@@ -614,7 +614,7 @@ struct ocfs2_super_block { · 613 unmodified lines
614614 __le16 s_reserved0;
615615 __le32 s_dx_seed[3]; /* seed[0-2] for dx dir hash.
616616 * 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 */
618618 /*140*/
619619
620620 /*
fs/ocfs2/stack_user.c+1−0
@@ -1011,6 +1011,7 @@ static int user_cluster_connect(struct ocfs2_cluster_connection *conn) · 1010 unmodified lines
10111011 printk(KERN_ERR "ocfs2: Could not determine"
10121012 " locking version\n");
10131013 user_cluster_disconnect(conn);
1014+ lc = NULL;
10141015 goto out;
10151016 }
10161017 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
127127 char namebuf[40];
128128 struct inode *inode = NULL;
129129 u64 blkno;
130− int status = 0;
130+ int len, status = 0;
131131
132− ocfs2_sprintf_system_inode_name(namebuf,
133− sizeof(namebuf),
134− type, slot);
132+ len = ocfs2_sprintf_system_inode_name(namebuf,
133+ sizeof(namebuf),
134+ type, slot);
135135
136− status = ocfs2_lookup_ino_from_name(osb->sys_root_inode, namebuf,
137− strlen(namebuf), &blkno);
136+ status = ocfs2_lookup_ino_from_name(osb->sys_root_inode,
137+ namebuf, len, &blkno);
138138 if (status < 0) {
139139 goto bail;
140140 }
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
39473947 tid = task_pid_nr_ns(task, ns);
39483948 if (!tid)
39493949 continue; /* The task has just exited. */
3950− len = snprintf(name, sizeof(name), "%u", tid);
3950+ len = snprintf(name, sizeof(name), "%d", tid);
39513951 if (!proc_fill_cache(file, ctx, name, len,
39523952 proc_task_instantiate, task, NULL)) {
39533953 /* 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
307307 all_done:
308308 *index_block = cur_index_block;
309309 *index_offset = cur_offset;
310− *data_block = cur_data_block;
310+ if (data_block)
311+ *data_block = cur_data_block;
311312
312313 /*
313314 * Scale cache index (cache slot entry) to index
@@ -324,17 +325,15 @@ failed: · 10 unmodified lines
324325 * Get the on-disk location and compressed size of the datablock
325326 * specified by index. Fill_meta_index() does most of the work.
326327 */
327−static int read_blocklist(struct inode *inode, int index, u64 *block)
328+static int read_blocklist_ptrs(struct inode *inode, int index, u64 *start,
329+ int *offset, u64 *block)
328330 {
329− u64 start;
330331 long long blks;
331− int offset;
332332 __le32 size;
333− int res = fill_meta_index(inode, index, &start, &offset, block);
333+ int res = fill_meta_index(inode, index, start, offset, block);
334334
335− TRACE("read_blocklist: res %d, index %d, start 0x%llx, offset"
336− " 0x%x, block 0x%llx\n", res, index, start, offset,
337− *block);
335+ TRACE("read_blocklist: res %d, index %d, start 0x%llx, offset 0x%x, block 0x%llx\n",
336+ res, index, *start, *offset, block ? *block : 0);
338337
339338 if (res < 0)
340339 return res;
@@ -346,22 +345,31 @@ static int read_blocklist(struct inode *inode, int index, u64 *block) · 5 unmodified lines
346345 * extra block indexes needed.
347346 */
348347 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);
350349 if (blks < 0)
351350 return (int) blks;
352− *block += blks;
351+ if (block)
352+ *block += blks;
353353 }
354354
355355 /*
356356 * Read length of block specified by index.
357357 */
358− res = squashfs_read_metadata(inode->i_sb, &size, &start, &offset,
358+ res = squashfs_read_metadata(inode->i_sb, &size, start, offset,
359359 sizeof(size));
360360 if (res < 0)
361361 return res;
362362 return squashfs_block_size(size);
363363 }
364364
365+static 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+
365373 static bool squashfs_fill_page(struct folio *folio,
366374 struct squashfs_cache_entry *buffer, size_t offset,
367375 size_t avail)
@@ -658,7 +666,114 @@ skip_pages: · 290 unmodified lines
658666 kfree(pages);
659667 }
660668
669+static 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+
737+not_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+
745+finished:
746+ kfree(blist);
747+ return offset;
748+}
749+
750+static 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+
661769 const struct address_space_operations squashfs_aops = {
662770 .read_folio = squashfs_read_folio,
663771 .readahead = squashfs_readahead
664772 };
773+
774+const 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
6868 inode->i_mode = le16_to_cpu(sqsh_ino->mode);
6969 inode->i_size = 0;
7070
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+
7175 return err;
7276 }
7377
@@ -140,8 +144,17 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 66 unmodified lines
140144 if (err < 0)
141145 goto failed_read;
142146
147+ inode->i_size = le32_to_cpu(sqsh_ino->file_size);
143148 frag = le32_to_cpu(sqsh_ino->fragment);
144149 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+ }
145158 frag_offset = le32_to_cpu(sqsh_ino->offset);
146159 frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
147160 if (frag_size < 0) {
@@ -155,8 +168,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 7 unmodified lines
155168 }
156169
157170 set_nlink(inode, 1);
158− inode->i_size = le32_to_cpu(sqsh_ino->file_size);
159− inode->i_fop = &generic_ro_fops;
171+ inode->i_fop = &squashfs_file_operations;
160172 inode->i_mode |= S_IFREG;
161173 inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
162174 squashfs_i(inode)->fragment_block = frag_blk;
@@ -165,6 +177,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 2 unmodified lines
165177 squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
166178 squashfs_i(inode)->block_list_start = block;
167179 squashfs_i(inode)->offset = offset;
180+ squashfs_i(inode)->parent = 0;
168181 inode->i_data.a_ops = &squashfs_aops;
169182
170183 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
183196 if (err < 0)
184197 goto failed_read;
185198
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+ }
186204 frag = le32_to_cpu(sqsh_ino->fragment);
187205 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+ }
188214 frag_offset = le32_to_cpu(sqsh_ino->offset);
189215 frag_size = squashfs_frag_lookup(sb, frag, &frag_blk);
190216 if (frag_size < 0) {
@@ -199,9 +225,8 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 8 unmodified lines
199225
200226 xattr_id = le32_to_cpu(sqsh_ino->xattr);
201227 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
202− inode->i_size = le64_to_cpu(sqsh_ino->file_size);
203228 inode->i_op = &squashfs_inode_ops;
204− inode->i_fop = &generic_ro_fops;
229+ inode->i_fop = &squashfs_file_operations;
205230 inode->i_mode |= S_IFREG;
206231 inode->i_blocks = (inode->i_size -
207232 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
212237 squashfs_i(inode)->start = le64_to_cpu(sqsh_ino->start_block);
213238 squashfs_i(inode)->block_list_start = block;
214239 squashfs_i(inode)->offset = offset;
240+ squashfs_i(inode)->parent = 0;
215241 inode->i_data.a_ops = &squashfs_aops;
216242
217243 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
292318 inode->i_mode |= S_IFLNK;
293319 squashfs_i(inode)->start = block;
294320 squashfs_i(inode)->offset = offset;
321+ squashfs_i(inode)->parent = 0;
295322
296323 if (type == SQUASHFS_LSYMLINK_TYPE) {
297324 __le32 xattr;
@@ -329,6 +356,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 31 unmodified lines
329356 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
330357 rdev = le32_to_cpu(sqsh_ino->rdev);
331358 init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
359+ squashfs_i(inode)->parent = 0;
332360
333361 TRACE("Device inode %x:%x, rdev %x\n",
334362 SQUASHFS_INODE_BLK(ino), offset, rdev);
@@ -353,6 +381,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 18 unmodified lines
353381 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
354382 rdev = le32_to_cpu(sqsh_ino->rdev);
355383 init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
384+ squashfs_i(inode)->parent = 0;
356385
357386 TRACE("Device inode %x:%x, rdev %x\n",
358387 SQUASHFS_INODE_BLK(ino), offset, rdev);
@@ -373,6 +402,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 14 unmodified lines
373402 inode->i_mode |= S_IFSOCK;
374403 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
375404 init_special_inode(inode, inode->i_mode, 0);
405+ squashfs_i(inode)->parent = 0;
376406 break;
377407 }
378408 case SQUASHFS_LFIFO_TYPE:
@@ -392,6 +422,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) · 13 unmodified lines
392422 inode->i_op = &squashfs_inode_ops;
393423 set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
394424 init_special_inode(inode, inode->i_mode, 0);
425+ squashfs_i(inode)->parent = 0;
395426 break;
396427 }
397428 default:
fs/squashfs/squashfs.h+1−0
@@ -107,6 +107,7 @@ extern const struct address_space_operations squashfs_aops; · 106 unmodified lines
107107
108108 /* inode.c */
109109 extern const struct inode_operations squashfs_inode_ops;
110+extern const struct file_operations squashfs_file_operations;
110111
111112 /* namei.c */
112113 extern 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
208208 #define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
209209 #define SQUASHFS_META_ENTRIES 127
210210 #define SQUASHFS_META_SLOTS 8
211+#define SQUASHFS_SCAN_INDEXES 1024
211212
212213 struct meta_entry {
213214 u64 data_block;
fs/squashfs/squashfs_fs_i.h+1−1
@@ -16,6 +16,7 @@ struct squashfs_inode_info { · 15 unmodified lines
1616 u64 xattr;
1717 unsigned int xattr_size;
1818 int xattr_count;
19+ int parent;
1920 union {
2021 struct {
2122 u64 fragment_block;
@@ -27,7 +28,6 @@ struct squashfs_inode_info { · 5 unmodified lines
2728 u64 dir_idx_start;
2829 int dir_idx_offset;
2930 int dir_idx_cnt;
30− int parent;
3131 };
3232 };
3333 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
334334 xa_init_flags(&ida->xa, IDA_INIT_FLAGS);
335335 }
336336
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−
345337 static inline bool ida_is_empty(const struct ida *ida)
346338 {
347339 return xa_empty(&ida->xa);
include/linux/kernel.h+17−4
@@ -164,11 +164,23 @@ extern int root_mountflags; · 163 unmodified lines
164164
165165 extern bool early_boot_irqs_disabled;
166166
167−/*
168− * Values used for system_state. Ordering of the states must not be changed
167+/**
168+ * 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
169181 * as code checks for <, <=, >, >= STATE.
170182 */
171−extern enum system_states {
183+enum system_states {
172184 SYSTEM_BOOTING,
173185 SYSTEM_SCHEDULING,
174186 SYSTEM_FREEING_INITMEM,
@@ -177,7 +189,8 @@ extern enum system_states { · 2 unmodified lines
177189 SYSTEM_POWER_OFF,
178190 SYSTEM_RESTART,
179191 SYSTEM_SUSPEND,
180−} system_state;
192+};
193+extern enum system_states system_state;
181194
182195 /*
183196 * General tracing related utility functions - trace_printk(),
include/linux/kexec.h+4−1
@@ -395,6 +395,9 @@ struct kimage { · 394 unmodified lines
395395
396396 /* Information for loading purgatory */
397397 struct purgatory_info purgatory_info;
398+
399+ /* Force carrying over the DTB from the current boot */
400+ bool force_dtb;
398401 #endif
399402
400403 #ifdef CONFIG_CRASH_HOTPLUG
@@ -461,7 +464,7 @@ bool kexec_load_permitted(int kexec_image_type); · 60 unmodified lines
461464 /* List of defined/legal kexec file flags */
462465 #define KEXEC_FILE_FLAGS (KEXEC_FILE_UNLOAD | KEXEC_FILE_ON_CRASH | \
463466 KEXEC_FILE_NO_INITRAMFS | KEXEC_FILE_DEBUG | \
464− KEXEC_FILE_NO_CMA)
467+ KEXEC_FILE_NO_CMA | KEXEC_FILE_FORCE_DTB)
465468
466469 /* flag to track if kexec reboot is in progress */
467470 extern bool kexec_in_progress;
include/linux/kexec_handover.h+6−0
@@ -40,6 +40,7 @@ struct kho_serialization; · 39 unmodified lines
4040
4141 #ifdef CONFIG_KEXEC_HANDOVER
4242 bool kho_is_enabled(void);
43+bool is_kho_boot(void);
4344
4445 int kho_preserve_folio(struct folio *folio);
4546 int kho_preserve_phys(phys_addr_t phys, size_t size);
@@ -60,6 +61,11 @@ static inline bool kho_is_enabled(void) · 14 unmodified lines
6061 return false;
6162 }
6263
64+static inline bool is_kho_boot(void)
65+{
66+ return false;
67+}
68+
6369 static inline int kho_preserve_folio(struct folio *folio)
6470 {
6571 return -EOPNOTSUPP;
include/linux/list.h+8−0
@@ -20,8 +20,16 @@ · 19 unmodified lines
2020 * using the generic single-entry routines.
2121 */
2222
23+/**
24+ * LIST_HEAD_INIT - initialize a &struct list_head's links to point to itself
25+ * @name: name of the list_head
26+ */
2327 #define LIST_HEAD_INIT(name) { &(name), &(name) }
2428
29+/**
30+ * LIST_HEAD - definition of a &struct list_head with initialization values
31+ * @name: name of the list_head
32+ */
2533 #define LIST_HEAD(name) \
2634 struct list_head name = LIST_HEAD_INIT(name)
2735
include/linux/moduleparam.h+13−0
@@ -349,6 +349,19 @@ static inline void kernel_param_unlock(struct module *mod) · 348 unmodified lines
349349 __module_param_call("", name, &param_ops_##type, &var, perm, \
350350 -1, KERNEL_PARAM_FL_UNSAFE)
351351
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+
352365 #endif /* !MODULE */
353366
354367 /**
include/linux/nvmem-provider.h+1−1
@@ -103,7 +103,7 @@ struct nvmem_cell_info { · 102 unmodified lines
103103 *
104104 * Note: A default "nvmem<id>" name will be assigned to the device if
105105 * 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.
107107 *
108108 * Note: Specifying name and setting id to -1 implies a unique device
109109 * whose name is provided as-is (kept unaltered).
include/linux/panic.h+6−0
@@ -43,6 +43,12 @@ void abort(void); · 42 unmodified lines
4343 extern atomic_t panic_cpu;
4444 #define PANIC_CPU_INVALID -1
4545
46+bool panic_try_start(void);
47+void panic_reset(void);
48+bool panic_in_progress(void);
49+bool panic_on_this_cpu(void);
50+bool panic_on_other_cpu(void);
51+
4652 /*
4753 * Only to be used by arch init code. If the user over-wrote the default
4854 * 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
330330
331331 #endif
332332
333−bool this_cpu_in_panic(void);
334−
335333 #ifdef CONFIG_SMP
336334 extern int __printk_cpu_sync_try_get(void);
337335 extern 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
210210 * pins the final release of task.io_context. Also protects ->cpuset and
211211 * ->cgroup.subsys[]. And ->vfork_done. And ->sysvshm.shm_clist.
212212 *
213− * Nests both inside and outside of read_lock(&tasklist_lock).
214− * It must not be nested with write_lock_irq(&tasklist_lock),
215− * neither inside nor outside.
213+ * Nests inside of read_lock(&tasklist_lock). It must not be nested with
214+ * write_lock_irq(&tasklist_lock), neither inside nor outside.
216215 */
217216 static inline void task_lock(struct task_struct *p)
218217 {
include/uapi/linux/kexec.h+4−0
@@ -22,12 +22,16 @@ · 21 unmodified lines
2222 * KEXEC_FILE_ON_CRASH : Load/unload operation belongs to kdump image.
2323 * KEXEC_FILE_NO_INITRAMFS : No initramfs is being loaded. Ignore the initrd
2424 * 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.
2528 */
2629 #define KEXEC_FILE_UNLOAD 0x00000001
2730 #define KEXEC_FILE_ON_CRASH 0x00000002
2831 #define KEXEC_FILE_NO_INITRAMFS 0x00000004
2932 #define KEXEC_FILE_DEBUG 0x00000008
3033 #define KEXEC_FILE_NO_CMA 0x00000010
34+#define KEXEC_FILE_FORCE_DTB 0x00000020
3135
3236 /* These values match the ELF architecture values.
3337 * 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
545545 const char *unused, void *arg)
546546 {
547547 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 };
548554
549555 /* Handle params aliased to sysctls */
550556 if (sysctl_is_alias(param))
@@ -552,6 +558,12 @@ static int __init unknown_bootoption(char *param, char *val, · 1 unmodified line
552558
553559 repair_env_string(param, val);
554560
561+ /* Handle bootloader identifier */
562+ for (int i = 0; bootloader[i]; i++) {
563+ if (strstarts(param, bootloader[i]))
564+ return 0;
565+ }
566+
555567 /* Handle obsolete-style parameters */
556568 if (obsolete_checksetup(param))
557569 return 0;
kernel/Kconfig.kexec+11−0
@@ -148,6 +148,17 @@ config CRASH_DM_CRYPT_CONFIGS · 147 unmodified lines
148148 CRASH_DM_CRYPT cannot directly select CONFIGFS_FS, because that
149149 is required to be built-in.
150150
151+config 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+
151162 config CRASH_HOTPLUG
152163 bool "Update the crash elfcorehdr on system configuration changes"
153164 default y
kernel/Makefile+1−0
@@ -78,6 +78,7 @@ obj-$(CONFIG_CRASH_RESERVE) += crash_reserve.o · 77 unmodified lines
7878 obj-$(CONFIG_KEXEC_CORE) += kexec_core.o
7979 obj-$(CONFIG_CRASH_DUMP) += crash_core.o
8080 obj-$(CONFIG_CRASH_DM_CRYPT) += crash_dump_dm_crypt.o
81+obj-$(CONFIG_CRASH_DUMP_KUNIT_TEST) += crash_core_test.o
8182 obj-$(CONFIG_KEXEC) += kexec.o
8283 obj-$(CONFIG_KEXEC_FILE) += kexec_file.o
8384 obj-$(CONFIG_KEXEC_ELF) += kexec_elf.o
kernel/crash_core.c+18−12
@@ -22,6 +22,7 @@ · 21 unmodified lines
2222 #include <linux/btf.h>
2323 #include <linux/objtool.h>
2424 #include <linux/delay.h>
25+#include <linux/panic.h>
2526
2627 #include <asm/page.h>
2728 #include <asm/sections.h>
@@ -143,17 +144,7 @@ STACK_FRAME_NON_STANDARD(__crash_kexec); · 115 unmodified lines
143144
144145 __bpf_kfunc void crash_kexec(struct pt_regs *regs)
145146 {
146− int old_cpu, this_cpu;
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)) {
147+ if (panic_try_start()) {
157148 /* This is the 1st CPU which comes here, so go ahead. */
158149 __crash_kexec(regs);
159150
@@ -161,7 +152,7 @@ __bpf_kfunc void crash_kexec(struct pt_regs *regs) · 1 unmodified line
161152 * Reset panic_cpu to allow another panic()/crash_kexec()
162153 * call.
163154 */
164− atomic_set(&panic_cpu, PANIC_CPU_INVALID);
155+ panic_reset();
165156 }
166157 }
167158
@@ -274,6 +265,20 @@ int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map, · 106 unmodified lines
274265 return 0;
275266 }
276267
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+ */
277282 int crash_exclude_mem_range(struct crash_mem *mem,
278283 unsigned long long mstart, unsigned long long mend)
279284 {
@@ -333,6 +338,7 @@ int crash_exclude_mem_range(struct crash_mem *mem, · 53 unmodified lines
333338
334339 return 0;
335340 }
341+EXPORT_SYMBOL_GPL(crash_exclude_mem_range);
336342
337343 ssize_t crash_get_memory_size(void)
338344 {
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
6+static 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
38+static 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
59+struct 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+
71+static 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+
109+static const struct range single_range_b = { .start = 100, .end = 199 };
110+
111+static 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+
265+static 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+
280+static 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+
314+static 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+ */
328+static 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+
334+static 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+
340+kunit_test_suite(crash_exclude_mem_range_suite);
341+
342+MODULE_DESCRIPTION("crash dump KUnit test suite");
343+MODULE_LICENSE("GPL");
kernel/fork.c+6−12
@@ -2132,9 +2132,7 @@ __latent_entropy struct task_struct *copy_process( · 2131 unmodified lines
21322132
21332133 p->pagefault_disabled = 0;
21342134
2135−#ifdef CONFIG_LOCKDEP
21362135 lockdep_init_task(p);
2137−#endif
21382136
21392137 p->blocked_on = NULL; /* not blocked yet */
21402138
@@ -2547,11 +2545,9 @@ struct task_struct * __init fork_idle(int cpu) · 406 unmodified lines
25472545 struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node)
25482546 {
25492547 unsigned long flags = CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|
2550− CLONE_IO;
2548+ CLONE_IO|CLONE_VM|CLONE_UNTRACED;
25512549 struct kernel_clone_args args = {
2552− .flags = ((lower_32_bits(flags) | CLONE_VM |
2553− CLONE_UNTRACED) & ~CSIGNAL),
2554− .exit_signal = (lower_32_bits(flags) & CSIGNAL),
2550+ .flags = flags,
25552551 .fn = fn,
25562552 .fn_arg = arg,
25572553 .io_thread = 1,
@@ -2663,9 +2659,8 @@ pid_t kernel_thread(int (*fn)(void *), void *arg, const char *name, · 105 unmodified lines
26632659 unsigned long flags)
26642660 {
26652661 struct kernel_clone_args args = {
2666− .flags = ((lower_32_bits(flags) | CLONE_VM |
2667− CLONE_UNTRACED) & ~CSIGNAL),
2668− .exit_signal = (lower_32_bits(flags) & CSIGNAL),
2662+ .flags = ((flags | CLONE_VM | CLONE_UNTRACED) & ~CSIGNAL),
2663+ .exit_signal = (flags & CSIGNAL),
26692664 .fn = fn,
26702665 .fn_arg = arg,
26712666 .name = name,
@@ -2681,9 +2676,8 @@ pid_t kernel_thread(int (*fn)(void *), void *arg, const char *name, · 9 unmodified lines
26812676 pid_t user_mode_thread(int (*fn)(void *), void *arg, unsigned long flags)
26822677 {
26832678 struct kernel_clone_args args = {
2684− .flags = ((lower_32_bits(flags) | CLONE_VM |
2685− CLONE_UNTRACED) & ~CSIGNAL),
2686− .exit_signal = (lower_32_bits(flags) & CSIGNAL),
2679+ .flags = ((flags | CLONE_VM | CLONE_UNTRACED) & ~CSIGNAL),
2680+ .exit_signal = (flags & CSIGNAL),
26872681 .fn = fn,
26882682 .fn_arg = arg,
26892683 };
kernel/hung_task.c+41−37
@@ -95,9 +95,41 @@ static struct notifier_block panic_block = { · 94 unmodified lines
9595 .notifier_call = hung_task_panic,
9696 };
9797
98+static 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+}
98130
99131 #ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
100−static void debug_show_blocker(struct task_struct *task)
132+static void debug_show_blocker(struct task_struct *task, unsigned long timeout)
101133 {
102134 struct task_struct *g, *t;
103135 unsigned long owner, blocker, blocker_type;
@@ -174,41 +206,21 @@ static void debug_show_blocker(struct task_struct *task) · 70 unmodified lines
174206 t->pid, rwsem_blocked_by);
175207 break;
176208 }
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);
178212 return;
179213 }
180214 }
181215 #else
182−static inline void debug_show_blocker(struct task_struct *task)
216+static inline void debug_show_blocker(struct task_struct *task, unsigned long timeout)
183217 {
184218 }
185219 #endif
186220
187221 static void check_hung_task(struct task_struct *t, unsigned long timeout)
188222 {
189− unsigned long switch_count = t->nvcsw + t->nivcsw;
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))
223+ if (!task_is_hung(t, timeout))
212224 return;
213225
214226 /*
@@ -243,7 +255,7 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) · 28 unmodified lines
243255 pr_err("\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\""
244256 " disables this message.\n");
245257 sched_show_task(t);
246− debug_show_blocker(t);
258+ debug_show_blocker(t, timeout);
247259 hung_task_show_lock = true;
248260
249261 if (sysctl_hung_task_all_cpu_backtrace)
@@ -299,7 +311,6 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) · 49 unmodified lines
299311 hung_task_show_lock = false;
300312 rcu_read_lock();
301313 for_each_process_thread(g, t) {
302− unsigned int state;
303314
304315 if (!max_count--)
305316 goto unlock;
@@ -308,15 +319,8 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout) · 2 unmodified lines
308319 goto unlock;
309320 last_break = jiffies;
310321 }
311− /*
312− * skip the TASK_KILLABLE tasks -- these can be killed
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);
322+
323+ check_hung_task(t, timeout);
320324 }
321325 unlock:
322326 rcu_read_unlock();
kernel/kallsyms_selftest.c+1−1
@@ -264,7 +264,7 @@ static int test_kallsyms_basic_function(void) · 263 unmodified lines
264264 char namebuf[KSYM_NAME_LEN];
265265 struct test_stat *stat, *stat2;
266266
267− stat = kmalloc(sizeof(*stat) * 2, GFP_KERNEL);
267+ stat = kmalloc_array(2, sizeof(*stat), GFP_KERNEL);
268268 if (!stat)
269269 return -ENOMEM;
270270 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
978978 memcpy(dst_entries, src_entries, bytes_to_move);
979979 entries_moved = bytes_to_move >> entry_size_log;
980980
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+
981990 switch (mode) {
982991 case KCOV_MODE_TRACE_PC:
983992 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
233233 if (!image)
234234 return NULL;
235235
236− image->head = 0;
237236 image->entry = &image->head;
238237 image->last_entry = &image->head;
239238 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
255255 }
256256
257257 image->no_cma = !!(flags & KEXEC_FILE_NO_CMA);
258+ image->force_dtb = flags & KEXEC_FILE_FORCE_DTB;
258259
259260 if (cmdline_len) {
260261 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
987987 return kho_in.fdt_phys ? phys_to_virt(kho_in.fdt_phys) : NULL;
988988 }
989989
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+ */
1004+bool is_kho_boot(void)
1005+{
1006+ return !!kho_get_fdt();
1007+}
1008+EXPORT_SYMBOL_GPL(is_kho_boot);
1009+
9901010 /**
9911011 * kho_retrieve_subtree - retrieve a preserved sub FDT by its name.
9921012 * @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
12691289 int err = 0;
12701290 struct kexec_buf scratch;
12711291
1272− if (!kho_enable)
1292+ if (!kho_out.finalized)
12731293 return 0;
12741294
12751295 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
5353 #define sysctl_oops_all_cpu_backtrace 0
5454 #endif /* CONFIG_SMP */
5555
56−int panic_on_oops = CONFIG_PANIC_ON_OOPS_VALUE;
56+int panic_on_oops = IS_ENABLED(CONFIG_PANIC_ON_OOPS);
5757 static unsigned long tainted_mask =
5858 IS_ENABLED(CONFIG_RANDSTRUCT) ? (1 << TAINT_RANDSTRUCT) : 0;
5959 static int pause_on_oops;
@@ -67,6 +67,7 @@ static unsigned int warn_limit __read_mostly; · 7 unmodified lines
6767 static bool panic_console_replay;
6868
6969 bool panic_triggering_all_cpu_backtrace;
70+static bool panic_this_cpu_backtrace_printed;
7071
7172 int panic_timeout = CONFIG_PANIC_TIMEOUT;
7273 EXPORT_SYMBOL_GPL(panic_timeout);
@@ -77,6 +78,11 @@ ATOMIC_NOTIFIER_HEAD(panic_notifier_list); · 4 unmodified lines
7778
7879 EXPORT_SYMBOL(panic_notifier_list);
7980
81+static 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+
8086 #ifdef CONFIG_SYSCTL
8187
8288 /*
@@ -125,7 +131,7 @@ static int proc_taint(const struct ctl_table *table, int write, · 42 unmodified lines
125131 static int sysctl_panic_print_handler(const struct ctl_table *table, int write,
126132 void *buffer, size_t *lenp, loff_t *ppos)
127133 {
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();
129135 return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
130136 }
131137
@@ -294,6 +300,59 @@ void __weak crash_smp_send_stop(void) · 162 unmodified lines
294300
295301 atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID);
296302
303+bool 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+}
317+EXPORT_SYMBOL(panic_try_start);
318+
319+void panic_reset(void)
320+{
321+ atomic_set(&panic_cpu, PANIC_CPU_INVALID);
322+}
323+EXPORT_SYMBOL(panic_reset);
324+
325+bool panic_in_progress(void)
326+{
327+ return unlikely(atomic_read(&panic_cpu) != PANIC_CPU_INVALID);
328+}
329+EXPORT_SYMBOL(panic_in_progress);
330+
331+/* Return true if a panic is in progress on the current CPU. */
332+bool 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+}
342+EXPORT_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+ */
350+bool panic_on_other_cpu(void)
351+{
352+ return (panic_in_progress() && !panic_on_this_cpu());
353+}
354+EXPORT_SYMBOL(panic_on_other_cpu);
355+
297356 /*
298357 * A variant of panic() called from NMI context. We return if we've already
299358 * 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
302361 */
303362 void nmi_panic(struct pt_regs *regs, const char *msg)
304363 {
305− int old_cpu, this_cpu;
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))
364+ if (panic_try_start())
312365 panic("%s", msg);
313− else if (old_cpu != this_cpu)
366+ else if (panic_on_other_cpu())
314367 nmi_panic_self_stop(regs);
315368 }
316369 EXPORT_SYMBOL(nmi_panic);
@@ -328,6 +381,19 @@ void check_panic_on_warn(const char *origin) · 11 unmodified lines
328381 origin, limit);
329382 }
330383
384+static 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+
331397 /*
332398 * Helper that triggers the NMI backtrace (if set in panic_print)
333399 * 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
335401 */
336402 static void panic_other_cpus_shutdown(bool crash_kexec)
337403 {
338− if (panic_print & SYS_INFO_ALL_CPU_BT) {
339− /* Temporary allow non-panic CPUs to write their backtraces. */
340− panic_triggering_all_cpu_backtrace = true;
341− trigger_all_cpu_backtrace();
342− panic_triggering_all_cpu_backtrace = false;
343− }
404+ if (panic_print & SYS_INFO_ALL_CPU_BT)
405+ panic_trigger_all_cpu_backtrace();
344406
345407 /*
346408 * 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
368430 static char buf[1024];
369431 long i, i_next = 0, len;
370432 int state = 0;
371− int old_cpu, this_cpu;
372433 bool _crash_kexec_post_notifiers = crash_kexec_post_notifiers;
373434
374435 if (panic_on_warn) {
@@ -405,13 +466,10 @@ void vpanic(const char *fmt, va_list args) · 30 unmodified lines
405466 * `old_cpu == this_cpu' means we came from nmi_panic() which sets
406467 * panic_cpu to this CPU. In this case, this is also the 1st CPU.
407468 */
408− old_cpu = PANIC_CPU_INVALID;
409− this_cpu = raw_smp_processor_id();
410−
411469 /* atomic_try_cmpxchg updates old_cpu on failure */
412− if (atomic_try_cmpxchg(&panic_cpu, &old_cpu, this_cpu)) {
470+ if (panic_try_start()) {
413471 /* go ahead */
414− } else if (old_cpu != this_cpu)
472+ } else if (panic_on_other_cpu())
415473 panic_smp_self_stop();
416474
417475 console_verbose();
@@ -422,13 +480,15 @@ void vpanic(const char *fmt, va_list args) · 4 unmodified lines
422480 buf[len - 1] = '\0';
423481
424482 pr_emerg("Kernel panic - not syncing: %s\n", buf);
425−#ifdef CONFIG_DEBUG_BUGVERBOSE
426483 /*
427484 * Avoid nested stack-dumping if a panic occurs during oops processing
428485 */
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)) {
430489 dump_stack();
431−#endif
490+ panic_this_cpu_backtrace_printed = true;
491+ }
432492
433493 /*
434494 * 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
937997 #endif
938998
939999 core_param(panic, panic_timeout, int, 0644);
940−core_param(panic_print, panic_print, ulong, 0644);
9411000 core_param(pause_on_oops, pause_on_oops, int, 0644);
9421001 core_param(panic_on_warn, panic_on_warn, int, 0644);
9431002 core_param(crash_kexec_post_notifiers, crash_kexec_post_notifiers, bool, 0644);
9441003 core_param(panic_console_replay, panic_console_replay, bool, 0644);
9451004
1005+static 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+
1011+static 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+
1017+static 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+
9461023 static int __init oops_setup(char *s)
9471024 {
9481025 if (!s)
kernel/printk/internal.h+0−1
@@ -332,7 +332,6 @@ struct printk_message { · 331 unmodified lines
332332 unsigned long dropped;
333333 };
334334
335−bool other_cpu_in_panic(void);
336335 bool printk_get_next_message(struct printk_message *pmsg, u64 seq,
337336 bool is_extended, bool may_supress);
338337
kernel/printk/nbcon.c+7−7
@@ -12,6 +12,7 @@ · 11 unmodified lines
1212 #include <linux/irqflags.h>
1313 #include <linux/kthread.h>
1414 #include <linux/minmax.h>
15+#include <linux/panic.h>
1516 #include <linux/percpu.h>
1617 #include <linux/preempt.h>
1718 #include <linux/slab.h>
@@ -254,7 +255,7 @@ static int nbcon_context_try_acquire_direct(struct nbcon_context *ctxt, · 236 unmodified lines
254255 * opportunity to perform any necessary cleanup if they were
255256 * interrupted by the panic CPU while printing.
256257 */
257− if (other_cpu_in_panic() &&
258+ if (panic_on_other_cpu() &&
258259 (!is_reacquire || cur->unsafe_takeover)) {
259260 return -EPERM;
260261 }
@@ -309,7 +310,7 @@ static bool nbcon_waiter_matches(struct nbcon_state *cur, int expected_prio) · 48 unmodified lines
309310 * Event #2 implies the new context is PANIC.
310311 * Event #3 occurs when panic() has flushed the console.
311312 * Event #4 occurs when a non-panic CPU reacquires.
312− * Event #5 is not possible due to the other_cpu_in_panic() check
313+ * Event #5 is not possible due to the panic_on_other_cpu() check
313314 * in nbcon_context_try_acquire_handover().
314315 */
315316
@@ -348,7 +349,7 @@ static int nbcon_context_try_acquire_requested(struct nbcon_context *ctxt, · 32 unmodified lines
348349 struct nbcon_state new;
349350
350351 /* Note that the caller must still remove the request! */
351− if (other_cpu_in_panic())
352+ if (panic_on_other_cpu())
352353 return -EPERM;
353354
354355 /*
@@ -446,7 +447,7 @@ static int nbcon_context_try_acquire_handover(struct nbcon_context *ctxt, · 91 unmodified lines
446447 * nbcon_waiter_matches(). In particular, the assumption that
447448 * lower priorities are ignored during panic.
448449 */
449− if (other_cpu_in_panic())
450+ if (panic_on_other_cpu())
450451 return -EPERM;
451452
452453 /* Handover is not possible on the same CPU. */
@@ -589,7 +590,6 @@ static struct printk_buffers panic_nbcon_pbufs; · 136 unmodified lines
589590 */
590591 static bool nbcon_context_try_acquire(struct nbcon_context *ctxt, bool is_reacquire)
591592 {
592− unsigned int cpu = smp_processor_id();
593593 struct console *con = ctxt->console;
594594 struct nbcon_state cur;
595595 int err;
@@ -614,7 +614,7 @@ out: · 18 unmodified lines
614614 /* Acquire succeeded. */
615615
616616 /* Assign the appropriate buffer for this context. */
617− if (atomic_read(&panic_cpu) == cpu)
617+ if (panic_on_this_cpu())
618618 ctxt->pbufs = &panic_nbcon_pbufs;
619619 else
620620 ctxt->pbufs = con->pbufs;
@@ -1394,7 +1394,7 @@ enum nbcon_prio nbcon_get_default_prio(void) · 773 unmodified lines
13941394 {
13951395 unsigned int *cpu_emergency_nesting;
13961396
1397− if (this_cpu_in_panic())
1397+ if (panic_on_this_cpu())
13981398 return NBCON_PRIO_PANIC;
13991399
14001400 cpu_emergency_nesting = nbcon_get_cpu_emergency_nesting();
kernel/printk/printk.c+5−32
@@ -48,6 +48,7 @@ · 47 unmodified lines
4848 #include <linux/sched/clock.h>
4949 #include <linux/sched/debug.h>
5050 #include <linux/sched/task_stack.h>
51+#include <linux/panic.h>
5152
5253 #include <linux/uaccess.h>
5354 #include <asm/sections.h>
@@ -345,34 +346,6 @@ static void __up_console_sem(unsigned long ip) · 291 unmodified lines
345346 }
346347 #define up_console_sem() __up_console_sem(_RET_IP_)
347348
348−static 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. */
354−bool 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− */
371−bool other_cpu_in_panic(void)
372−{
373− return (panic_in_progress() && !this_cpu_in_panic());
374−}
375−
376349 /*
377350 * This is used for debugging the mess that is the VT code by
378351 * 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
24072380 * non-panic CPUs are generating any messages, they will be
24082381 * silently dropped.
24092382 */
2410− if (other_cpu_in_panic() &&
2383+ if (panic_on_other_cpu() &&
24112384 !debug_non_panic_cpus &&
24122385 !panic_triggering_all_cpu_backtrace)
24132386 return 0;
@@ -2843,7 +2816,7 @@ void console_lock(void) · 429 unmodified lines
28432816 might_sleep();
28442817
28452818 /* On panic, the console_lock must be left to the panic cpu. */
2846− while (other_cpu_in_panic())
2819+ while (panic_on_other_cpu())
28472820 msleep(1000);
28482821
28492822 down_console_sem();
@@ -2863,7 +2836,7 @@ EXPORT_SYMBOL(console_lock); · 13 unmodified lines
28632836 int console_trylock(void)
28642837 {
28652838 /* On panic, the console_lock must be left to the panic cpu. */
2866− if (other_cpu_in_panic())
2839+ if (panic_on_other_cpu())
28672840 return 0;
28682841 if (down_trylock_console_sem())
28692842 return 0;
@@ -3243,7 +3216,7 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove · 373 unmodified lines
32433216 any_progress = true;
32443217
32453218 /* Allow panic_cpu to take over the consoles safely. */
3246− if (other_cpu_in_panic())
3219+ if (panic_on_other_cpu())
32473220 goto abandon;
32483221
32493222 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
21432143 * But it would have the sequence number returned
21442144 * by "prb_next_reserve_seq() - 1".
21452145 */
2146− if (this_cpu_in_panic() &&
2146+ if (panic_on_this_cpu() &&
21472147 (!debug_non_panic_cpus || legacy_allow_panic_sync) &&
21482148 ((*seq + 1) < prb_next_reserve_seq(rb))) {
21492149 (*seq)++;
kernel/sys.c+30−2
@@ -1734,6 +1734,7 @@ SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, · 1733 unmodified lines
17341734 struct rlimit old, new;
17351735 struct task_struct *tsk;
17361736 unsigned int checkflags = 0;
1737+ bool need_tasklist;
17371738 int ret;
17381739
17391740 if (old_rlim)
@@ -1760,8 +1761,25 @@ SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, · 20 unmodified lines
17601761 get_task_struct(tsk);
17611762 rcu_read_unlock();
17621763
1763− ret = do_prlimit(tsk, resource, new_rlim ? &new : NULL,
1764− old_rlim ? &old : NULL);
1764+ need_tasklist = !same_thread_group(tsk, current);
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);
17651783
17661784 if (!ret && old_rlim) {
17671785 rlim_to_rlim64(&old, &old64);
@@ -2515,7 +2533,17 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, · 747 unmodified lines
25152533 error = -EINVAL;
25162534 break;
25172535 }
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);
25182545 me->pdeath_signal = arg2;
2546+ read_unlock(&tasklist_lock);
25192547 break;
25202548 case PR_GET_PDEATHSIG:
25212549 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
425425 */
426426 static u16 get_16bit_precision(u64 data_ns)
427427 {
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;
429433 }
430434
431435 static void update_cpustat(void)
@@ -444,6 +448,14 @@ static void update_cpustat(void) · 12 unmodified lines
444448 old_stat = __this_cpu_read(cpustat_old[i]);
445449 new_stat = get_16bit_precision(cpustat[tracked_stats[i]]);
446450 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;
447459 __this_cpu_write(cpustat_util[tail][i], util);
448460 __this_cpu_write(cpustat_old[i], new_stat);
449461 }
@@ -455,17 +467,17 @@ static void print_cpustat(void) · 5 unmodified lines
455467 {
456468 int i, group;
457469 u8 tail = __this_cpu_read(cpustat_tail);
458− u64 sample_period_second = sample_period;
470+ u64 sample_period_msecond = sample_period;
459471
460− do_div(sample_period_second, NSEC_PER_SEC);
472+ do_div(sample_period_msecond, NSEC_PER_MSEC);
461473
462474 /*
463475 * Outputting the "watchdog" prefix on every line is redundant and not
464476 * concise, and the original alarm information is sufficient for
465477 * positioning in logs, hence here printk() is used instead of pr_crit().
466478 */
467− printk(KERN_CRIT "CPU#%d Utilization every %llus during lockup:\n",
468− smp_processor_id(), sample_period_second);
479+ printk(KERN_CRIT "CPU#%d Utilization every %llums during lockup:\n",
480+ smp_processor_id(), sample_period_msecond);
469481
470482 for (i = 0; i < NUM_SAMPLE_PERIODS; i++) {
471483 group = (tail + i) % NUM_SAMPLE_PERIODS;
@@ -740,6 +752,12 @@ static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer) · 268 unmodified lines
740752 if (!watchdog_enabled)
741753 return HRTIMER_NORESTART;
742754
755+ /*
756+ * pass the buddy check if a panic is in process
757+ */
758+ if (panic_in_progress())
759+ return HRTIMER_NORESTART;
760+
743761 watchdog_hardlockup_kick();
744762
745763 /* kick the softlockup detector */
kernel/watchdog_perf.c+4−0
@@ -12,6 +12,7 @@ · 11 unmodified lines
1212
1313 #define pr_fmt(fmt) "NMI watchdog: " fmt
1414
15+#include <linux/panic.h>
1516 #include <linux/nmi.h>
1617 #include <linux/atomic.h>
1718 #include <linux/module.h>
@@ -108,6 +109,9 @@ static void watchdog_overflow_callback(struct perf_event *event, · 90 unmodified lines
108109 /* Ensure the watchdog never gets throttled */
109110 event->hw.interrupts = 0;
110111
112+ if (panic_in_progress())
113+ return;
114+
111115 if (!watchdog_check_timestamp())
112116 return;
113117
lib/Kconfig.debug+0−6
@@ -1067,12 +1067,6 @@ config PANIC_ON_OOPS · 1066 unmodified lines
10671067
10681068 Say N if unsure.
10691069
1070−config 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−
10761070 config PANIC_TIMEOUT
10771071 int "panic timeout"
10781072 default 0
lib/alloc_tag.c+2−1
@@ -9,6 +9,7 @@ · 8 unmodified lines
99 #include <linux/proc_fs.h>
1010 #include <linux/seq_buf.h>
1111 #include <linux/seq_file.h>
12+#include <linux/string_choices.h>
1213 #include <linux/vmalloc.h>
1314 #include <linux/kmemleak.h>
1415
@@ -728,7 +729,7 @@ static int __init setup_early_mem_profiling(char *str) · 713 unmodified lines
728729 }
729730 mem_profiling_support = true;
730731 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));
732733 }
733734
734735 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
653653 * walks to remove a single object from the victim.
654654 */
655655 for (;;) {
656− if (!btree_last(victim, geo, key))
656+ val = btree_last(victim, geo, key);
657+ if (!val)
657658 break;
658− val = btree_lookup(victim, geo, key);
659659 err = btree_insert(target, geo, key, val, gfp);
660660 if (err)
661661 return err;
lib/decompress.c+10−11
@@ -49,15 +49,15 @@ struct compress_format { · 48 unmodified lines
4949 };
5050
5151 static const struct compress_format compressed_formats[] __initconst = {
52− { {0x1f, 0x8b}, "gzip", gunzip },
53− { {0x1f, 0x9e}, "gzip", gunzip },
54− { {0x42, 0x5a}, "bzip2", bunzip2 },
55− { {0x5d, 0x00}, "lzma", unlzma },
56− { {0xfd, 0x37}, "xz", unxz },
57− { {0x89, 0x4c}, "lzo", unlzo },
58− { {0x02, 0x21}, "lz4", unlz4 },
59− { {0x28, 0xb5}, "zstd", unzstd },
60− { {0, 0}, NULL, NULL }
52+ { .magic = {0x1f, 0x8b}, .name = "gzip", .decompressor = gunzip },
53+ { .magic = {0x1f, 0x9e}, .name = "gzip", .decompressor = gunzip },
54+ { .magic = {0x42, 0x5a}, .name = "bzip2", .decompressor = bunzip2 },
55+ { .magic = {0x5d, 0x00}, .name = "lzma", .decompressor = unlzma },
56+ { .magic = {0xfd, 0x37}, .name = "xz", .decompressor = unxz },
57+ { .magic = {0x89, 0x4c}, .name = "lzo", .decompressor = unlzo },
58+ { .magic = {0x02, 0x21}, .name = "lz4", .decompressor = unlz4 },
59+ { .magic = {0x28, 0xb5}, .name = "zstd", .decompressor = unzstd },
60+ { /* sentinel */ }
6161 };
6262
6363 decompress_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
7373
7474 pr_debug("Compressed data magic: %#.2x %#.2x\n", inbuf[0], inbuf[1]);
7575
76− for (cf = compressed_formats; cf->name; cf++) {
76+ for (cf = compressed_formats; cf->name; cf++)
7777 if (!memcmp(inbuf, cf->magic, 2))
7878 break;
7979
80− }
8180 if (name)
8281 *name = cf->name;
8382 return cf->decompressor;
lib/digsig.c+0−1
@@ -159,7 +159,6 @@ static int digsig_verify_rsa(struct key *key, · 158 unmodified lines
159159
160160 len = mlen;
161161 head = len - l;
162− memset(out1, 0, head);
163162 memcpy(out1 + head, p, l);
164163
165164 kfree(p);
lib/dump_stack.c+1−1
@@ -102,7 +102,7 @@ static void __dump_stack(const char *log_lvl) · 101 unmodified lines
102102 */
103103 asmlinkage __visible void dump_stack_lvl(const char *log_lvl)
104104 {
105− bool in_panic = this_cpu_in_panic();
105+ bool in_panic = panic_on_this_cpu();
106106 unsigned long flags;
107107
108108 /*
lib/fault-inject-usercopy.c+1−3
@@ -22,10 +22,8 @@ static int __init fail_usercopy_debugfs(void) · 21 unmodified lines
2222
2323 dir = fault_create_debugfs_attr("fail_usercopy", NULL,
2424 &fail_usercopy.attr);
25− if (IS_ERR(dir))
26− return PTR_ERR(dir);
2725
28− return 0;
26+ return PTR_ERR_OR_ZERO(dir);
2927 }
3028
3129 late_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
899899 if (!name)
900900 name = of_node_full_name(np_pool);
901901 }
902− if (pdev)
902+ if (pdev) {
903903 pool = gen_pool_get(&pdev->dev, name);
904+ put_device(&pdev->dev);
905+ }
906+
904907 of_node_put(np_pool);
905908
906909 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
7575 struct ref_tracker *tracker;
7676
7777 stats = kmalloc(struct_size(stats, stacks, limit),
78− GFP_NOWAIT | __GFP_NOWARN);
78+ GFP_NOWAIT);
7979 if (!stats)
8080 return ERR_PTR(-ENOMEM);
8181 stats->total = 0;
@@ -159,7 +159,7 @@ __ref_tracker_dir_pr_ostream(struct ref_tracker_dir *dir, · 77 unmodified lines
159159 return;
160160 }
161161
162− sbuf = kmalloc(STACK_BUF_SIZE, GFP_NOWAIT | __GFP_NOWARN);
162+ sbuf = kmalloc(STACK_BUF_SIZE, GFP_NOWAIT);
163163
164164 for (i = 0, skipped = stats->total; i < stats->count; ++i) {
165165 stack = stats->stacks[i].stack_handle;
@@ -306,7 +306,7 @@ int ref_tracker_free(struct ref_tracker_dir *dir, · 140 unmodified lines
306306 }
307307 nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 1);
308308 stack_handle = stack_depot_save(entries, nr_entries,
309− GFP_NOWAIT | __GFP_NOWARN);
309+ GFP_NOWAIT);
310310
311311 spin_lock_irqsave(&dir->lock, flags);
312312 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
5555 void *buffer, size_t *lenp,
5656 loff_t *ppos)
5757 {
58− char names[sizeof(sys_info_avail) + 1];
58+ char names[sizeof(sys_info_avail)];
5959 struct ctl_table table;
6060 unsigned long *si_bits_global;
6161
@@ -81,6 +81,7 @@ int sysctl_sys_info_handler(const struct ctl_table *ro_table, int write, · 19 unmodified lines
8181 char *delim = "";
8282 int i, len = 0;
8383
84+ names[0] = '\0';
8485 for (i = 0; i < ARRAY_SIZE(si_names); i++) {
8586 if (*si_bits_global & si_names[i].bit) {
8687 len += scnprintf(names + len, sizeof(names) - len,
lib/test_firmware.c+4−3
@@ -26,6 +26,7 @@ · 25 unmodified lines
2626 #include <linux/kthread.h>
2727 #include <linux/vmalloc.h>
2828 #include <linux/efi_embedded_fw.h>
29+#include <linux/string_choices.h>
2930
3031 MODULE_IMPORT_NS("TEST_FIRMWARE");
3132
@@ -304,17 +305,17 @@ static ssize_t config_show(struct device *dev, · 272 unmodified lines
304305 "FW_ACTION_NOUEVENT");
305306 len += scnprintf(buf + len, PAGE_SIZE - len,
306307 "into_buf:\t\t%s\n",
307− test_fw_config->into_buf ? "true" : "false");
308+ str_true_false(test_fw_config->into_buf));
308309 len += scnprintf(buf + len, PAGE_SIZE - len,
309310 "buf_size:\t%zu\n", test_fw_config->buf_size);
310311 len += scnprintf(buf + len, PAGE_SIZE - len,
311312 "file_offset:\t%zu\n", test_fw_config->file_offset);
312313 len += scnprintf(buf + len, PAGE_SIZE - len,
313314 "partial:\t\t%s\n",
314− test_fw_config->partial ? "true" : "false");
315+ str_true_false(test_fw_config->partial));
315316 len += scnprintf(buf + len, PAGE_SIZE - len,
316317 "sync_direct:\t\t%s\n",
317− test_fw_config->sync_direct ? "true" : "false");
318+ str_true_false(test_fw_config->sync_direct));
318319 len += scnprintf(buf + len, PAGE_SIZE - len,
319320 "read_fw_idx:\t%u\n", test_fw_config->read_fw_idx);
320321 if (test_fw_config->upload_name)
scripts/checkpatch.pl+9−5
@@ -2636,6 +2636,11 @@ sub exclude_global_initialisers { · 2635 unmodified lines
26362636 $realfile =~ m@/bpf/.*\.bpf\.c$@;
26372637 }
26382638
2639+sub is_userspace {
2640+ my ($realfile) = @_;
2641+ return ($realfile =~ m@^tools/@ || $realfile =~ m@^scripts/@);
2642+}
2643+
26392644 sub process {
26402645 my $filename = shift;
26412646
@@ -3294,7 +3299,7 @@ sub process { · 652 unmodified lines
32943299 # file delta changes
32953300 $line =~ /^\s*(?:[\w\.\-\+]*\/)++[\w\.\-\+]+:/ ||
32963301 # filename then :
3297− $line =~ /^\s*(?:Fixes:|$link_tags_search|$signature_tags)/i ||
3302+ $line =~ /^\s*(?:Fixes:|https?:|$link_tags_search|$signature_tags)/i ||
32983303 # A Fixes:, link or signature tag line
32993304 $commit_log_possible_stack_dump)) {
33003305 WARN("COMMIT_LOG_LONG_LINE",
@@ -7018,21 +7023,20 @@ sub process { · 3717 unmodified lines
70187023 # }
70197024 # }
70207025 # }
7021−
70227026 # strcpy uses that should likely be strscpy
7023− if ($line =~ /\bstrcpy\s*\(/) {
7027+ if ($line =~ /\bstrcpy\s*\(/ && !is_userspace($realfile)) {
70247028 WARN("STRCPY",
70257029 "Prefer strscpy over strcpy - see: https://github.com/KSPP/linux/issues/88\n" . $herecurr);
70267030 }
70277031
70287032 # strlcpy uses that should likely be strscpy
7029− if ($line =~ /\bstrlcpy\s*\(/) {
7033+ if ($line =~ /\bstrlcpy\s*\(/ && !is_userspace($realfile)) {
70307034 WARN("STRLCPY",
70317035 "Prefer strscpy over strlcpy - see: https://github.com/KSPP/linux/issues/89\n" . $herecurr);
70327036 }
70337037
70347038 # strncpy uses that should likely be strscpy or strscpy_pad
7035− if ($line =~ /\bstrncpy\s*\(/) {
7039+ if ($line =~ /\bstrncpy\s*\(/ && !is_userspace($realfile)) {
70367040 WARN("STRNCPY",
70377041 "Prefer strscpy, strscpy_pad, or __nonstring over strncpy - see: https://github.com/KSPP/linux/issues/90\n" . $herecurr);
70387042 }
scripts/coccinelle/api/platform_no_drv_owner.cocci+9−0
@@ -10,12 +10,21 @@ virtual org · 9 unmodified lines
1010 virtual report
1111
1212 @match1@
13+declarer name builtin_i2c_driver;
14+declarer name builtin_platform_driver;
15+declarer name builtin_platform_driver_probe;
1316 declarer name module_i2c_driver;
1417 declarer name module_platform_driver;
1518 declarer name module_platform_driver_probe;
1619 identifier __driver;
1720 @@
1821 (
22+ builtin_i2c_driver(__driver);
23+|
24+ builtin_platform_driver(__driver);
25+|
26+ builtin_platform_driver_probe(__driver, ...);
27+|
1928 module_i2c_driver(__driver);
2029 |
2130 module_platform_driver(__driver);
scripts/coccinelle/misc/of_table.cocci+7−7
@@ -1,5 +1,5 @@
11 // SPDX-License-Identifier: GPL-2.0
2−/// Make sure (of/i2c/platform)_device_id tables are NULL terminated
2+/// Make sure (of/i2c/platform/spi)_device_id tables are NULL terminated
33 //
44 // Keywords: of_table i2c_table platform_table
55 // Confidence: Medium
@@ -15,14 +15,14 @@ identifier var, arr; · 9 unmodified lines
1515 expression E;
1616 @@
1717 (
18−struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {
18+struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
1919 ...,
2020 {
2121 .var = E,
2222 * }
2323 };
2424 |
25−struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {
25+struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
2626 ...,
2727 * { ..., E, ... },
2828 };
@@ -33,7 +33,7 @@ identifier var, arr; · 4 unmodified lines
3333 expression E;
3434 @@
3535 (
36−struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {
36+struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
3737 ...,
3838 {
3939 .var = E,
@@ -42,7 +42,7 @@ struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = { · 2 unmodified lines
4242 + { }
4343 };
4444 |
45−struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {
45+struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
4646 ...,
4747 { ..., E, ... },
4848 + { },
@@ -55,7 +55,7 @@ identifier var, arr; · 6 unmodified lines
5555 expression E;
5656 @@
5757 (
58−struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {
58+struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
5959 ...,
6060 {
6161 .var = E,
@@ -63,7 +63,7 @@ struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = { · 1 unmodified line
6363 @p1
6464 };
6565 |
66−struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {
66+struct \(of_device_id \| i2c_device_id \| platform_device_id \| spi_device_id\) arr[] = {
6767 ...,
6868 { ..., E, ... }
6969 @p1
tools/accounting/delaytop.c+427−144
@@ -42,14 +42,13 @@ · 41 unmodified lines
4242 #include <linux/genetlink.h>
4343 #include <linux/taskstats.h>
4444 #include <linux/cgroupstats.h>
45+#include <stddef.h>
4546
46−#define PSI_CPU_SOME "/proc/pressure/cpu"
47−#define PSI_CPU_FULL "/proc/pressure/cpu"
48−#define PSI_MEMORY_SOME "/proc/pressure/memory"
49−#define PSI_MEMORY_FULL "/proc/pressure/memory"
50−#define PSI_IO_SOME "/proc/pressure/io"
51−#define PSI_IO_FULL "/proc/pressure/io"
52−#define PSI_IRQ_FULL "/proc/pressure/irq"
47+#define PSI_PATH "/proc/pressure"
48+#define PSI_CPU_PATH "/proc/pressure/cpu"
49+#define PSI_MEMORY_PATH "/proc/pressure/memory"
50+#define PSI_IO_PATH "/proc/pressure/io"
51+#define PSI_IRQ_PATH "/proc/pressure/irq"
5352
5453 #define NLA_NEXT(na) ((struct nlattr *)((char *)(na) + NLA_ALIGN((na)->nla_len)))
5554 #define NLA_DATA(na) ((void *)((char *)(na) + NLA_HDRLEN))
@@ -61,24 +60,28 @@ · 5 unmodified lines
6160 #define TASK_COMM_LEN 16
6261 #define MAX_MSG_SIZE 1024
6362 #define MAX_TASKS 1000
63+#define MAX_BUF_LEN 256
6464 #define SET_TASK_STAT(task_count, field) tasks[task_count].field = stats.field
6565 #define BOOL_FPRINT(stream, fmt, ...) \
6666 ({ \
6767 int ret = fprintf(stream, fmt, ##__VA_ARGS__); \
6868 ret >= 0; \
6969 })
70+#define TASK_AVG(task, field) average_ms((task).field##_delay_total, (task).field##_count)
7071 #define PSI_LINE_FORMAT "%-12s %6.1f%%/%6.1f%%/%6.1f%%/%8llu(ms)\n"
71−
72−/* Program settings structure */
73−struct config {
74− int delay; /* Update interval in seconds */
75− int iterations; /* Number of iterations, 0 == infinite */
76− int max_processes; /* Maximum number of processes to show */
77− char sort_field; /* Field to sort by */
78− int output_one_time; /* Output once and exit */
79− int monitor_pid; /* Monitor specific PID */
80− char *container_path; /* Path to container cgroup */
81−};
72+#define DELAY_FMT_DEFAULT "%8.2f %8.2f %8.2f %8.2f\n"
73+#define DELAY_FMT_MEMVERBOSE "%8.2f %8.2f %8.2f %8.2f %8.2f %8.2f\n"
74+#define SORT_FIELD(name, cmd, modes) \
75+ {#name, #cmd, \
76+ offsetof(struct task_info, name##_delay_total), \
77+ offsetof(struct task_info, name##_count), \
78+ modes}
79+#define END_FIELD {NULL, 0, 0}
80+
81+/* Display mode types */
82+#define MODE_TYPE_ALL (0xFFFFFFFF)
83+#define MODE_DEFAULT (1 << 0)
84+#define MODE_MEMVERBOSE (1 << 1)
8285
8386 /* PSI statistics structure */
8487 struct psi_stats {
@@ -119,6 +122,8 @@ struct task_info { · 34 unmodified lines
119122 unsigned long long wpcopy_delay_total;
120123 unsigned long long irq_count;
121124 unsigned long long irq_delay_total;
125+ unsigned long long mem_count;
126+ unsigned long long mem_delay_total;
122127 };
123128
124129 /* Container statistics structure */
@@ -130,6 +135,27 @@ struct container_stats { · 5 unmodified lines
130135 int nr_io_wait; /* Number of processes in IO wait */
131136 };
132137
138+/* Delay field structure */
139+struct 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 */
148+struct 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+
133159 /* Global variables */
134160 static struct config cfg;
135161 static struct psi_stats psi;
@@ -137,6 +163,19 @@ static struct task_info tasks[MAX_TASKS]; · 1 unmodified line
137163 static int task_count;
138164 static int running = 1;
139165 static struct container_stats container_stats;
166+static 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+};
178+static int sort_selected;
140179
141180 /* Netlink socket variables */
142181 static int nl_sd = -1;
@@ -158,18 +197,75 @@ static void disable_raw_mode(void) · 15 unmodified lines
158197 tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);
159198 }
160199
200+/* Find field descriptor by command line */
201+static 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 */
214+static 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 */
231+static 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 */
237+static 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+
161255 /* Display usage information and command line options */
162256 static void usage(void)
163257 {
164258 printf("Usage: delaytop [Options]\n"
165259 "Options:\n"
166− " -h, --help Show this help message and exit\n"
167− " -d, --delay=SECONDS Set refresh interval (default: 2 seconds, min: 1)\n"
168− " -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"
170− " -o, --once Display once and exit\n"
171− " -p, --pid=PID Monitor only the specified PID\n"
172− " -C, --container=PATH Monitor the container at specified cgroup path\n");
260+ " -h, --help Show this help message and exit\n"
261+ " -d, --delay=SECONDS Set refresh interval (default: 2 seconds, min: 1)\n"
262+ " -n, --iterations=COUNT Set number of updates (default: 0 = infinite)\n"
263+ " -P, --processes=NUMBER Set maximum number of processes to show (default: 20, max: 1000)\n"
264+ " -o, --once Display once and exit\n"
265+ " -p, --pid=PID Monitor only the specified PID\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");
173269 exit(0);
174270 }
175271
@@ -177,6 +273,7 @@ static void usage(void) · 1 unmodified line
177273 static void parse_args(int argc, char **argv)
178274 {
179275 int c;
276+ const struct field_desc *field;
180277 struct option long_options[] = {
181278 {"help", no_argument, 0, 'h'},
182279 {"delay", required_argument, 0, 'd'},
@@ -184,7 +281,9 @@ static void parse_args(int argc, char **argv) · 1 unmodified line
184281 {"pid", required_argument, 0, 'p'},
185282 {"once", no_argument, 0, 'o'},
186283 {"processes", required_argument, 0, 'P'},
284+ {"sort", required_argument, 0, 's'},
187285 {"container", required_argument, 0, 'C'},
286+ {"memverbose", no_argument, 0, 'M'},
188287 {0, 0, 0, 0}
189288 };
190289
@@ -192,15 +291,16 @@ static void parse_args(int argc, char **argv) · 1 unmodified line
192291 cfg.delay = 2;
193292 cfg.iterations = 0;
194293 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 */
196295 cfg.output_one_time = 0;
197296 cfg.monitor_pid = 0; /* 0 means monitor all PIDs */
198297 cfg.container_path = NULL;
298+ cfg.display_mode = MODE_DEFAULT;
199299
200300 while (1) {
201301 int option_index = 0;
202302
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);
204304 if (c == -1)
205305 break;
206306
@@ -247,6 +347,26 @@ static void parse_args(int argc, char **argv) · 40 unmodified lines
247347 case 'C':
248348 cfg.container_path = strdup(optarg);
249349 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;
250370 default:
251371 fprintf(stderr, "Try 'delaytop --help' for more information.\n");
252372 exit(1);
@@ -254,6 +374,25 @@ static void parse_args(int argc, char **argv) · 1 unmodified line
254374 }
255375 }
256376
377+/* Calculate average delay in milliseconds for overall memory */
378+static 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+
387+static 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+
257396 /* Create a raw netlink socket and bind */
258397 static int create_nl_socket(void)
259398 {
@@ -358,87 +497,134 @@ static int get_family_id(int sd) · 98 unmodified lines
358497 return id;
359498 }
360499
361−static void read_psi_stats(void)
500+static int read_psi_stats(void)
362501 {
363502 FILE *fp;
364503 char line[256];
365504 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+
366514 /* Zero all fields */
367515 memset(&psi, 0, sizeof(psi));
516+
368517 /* CPU pressure */
369− fp = fopen(PSI_CPU_SOME, "r");
518+ fp = fopen(PSI_CPU_PATH, "r");
370519 if (fp) {
371520 while (fgets(line, sizeof(line), fp)) {
372521 if (strncmp(line, "some", 4) == 0) {
373522 ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
374523 &psi.cpu_some_avg10, &psi.cpu_some_avg60,
375524 &psi.cpu_some_avg300, &psi.cpu_some_total);
376− if (ret != 4)
525+ if (ret != 4) {
377526 fprintf(stderr, "Failed to parse CPU some PSI data\n");
527+ error_count++;
528+ }
378529 } else if (strncmp(line, "full", 4) == 0) {
379530 ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
380531 &psi.cpu_full_avg10, &psi.cpu_full_avg60,
381532 &psi.cpu_full_avg300, &psi.cpu_full_total);
382− if (ret != 4)
533+ if (ret != 4) {
383534 fprintf(stderr, "Failed to parse CPU full PSI data\n");
535+ error_count++;
536+ }
384537 }
385538 }
386539 fclose(fp);
540+ } else {
541+ fprintf(stderr, "Warning: Failed to open %s\n", PSI_CPU_PATH);
542+ error_count++;
387543 }
544+
388545 /* Memory pressure */
389− fp = fopen(PSI_MEMORY_SOME, "r");
546+ fp = fopen(PSI_MEMORY_PATH, "r");
390547 if (fp) {
391548 while (fgets(line, sizeof(line), fp)) {
392549 if (strncmp(line, "some", 4) == 0) {
393550 ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
394551 &psi.memory_some_avg10, &psi.memory_some_avg60,
395552 &psi.memory_some_avg300, &psi.memory_some_total);
396− if (ret != 4)
553+ if (ret != 4) {
397554 fprintf(stderr, "Failed to parse Memory some PSI data\n");
555+ error_count++;
556+ }
398557 } else if (strncmp(line, "full", 4) == 0) {
399558 ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
400559 &psi.memory_full_avg10, &psi.memory_full_avg60,
401560 &psi.memory_full_avg300, &psi.memory_full_total);
402− }
403− if (ret != 4)
561+ if (ret != 4) {
404562 fprintf(stderr, "Failed to parse Memory full PSI data\n");
563+ error_count++;
564+ }
565+ }
405566 }
406567 fclose(fp);
568+ } else {
569+ fprintf(stderr, "Warning: Failed to open %s\n", PSI_MEMORY_PATH);
570+ error_count++;
407571 }
572+
408573 /* IO pressure */
409− fp = fopen(PSI_IO_SOME, "r");
574+ fp = fopen(PSI_IO_PATH, "r");
410575 if (fp) {
411576 while (fgets(line, sizeof(line), fp)) {
412577 if (strncmp(line, "some", 4) == 0) {
413578 ret = sscanf(line, "some avg10=%lf avg60=%lf avg300=%lf total=%llu",
414579 &psi.io_some_avg10, &psi.io_some_avg60,
415580 &psi.io_some_avg300, &psi.io_some_total);
416− if (ret != 4)
581+ if (ret != 4) {
417582 fprintf(stderr, "Failed to parse IO some PSI data\n");
583+ error_count++;
584+ }
418585 } else if (strncmp(line, "full", 4) == 0) {
419586 ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
420587 &psi.io_full_avg10, &psi.io_full_avg60,
421588 &psi.io_full_avg300, &psi.io_full_total);
422− if (ret != 4)
589+ if (ret != 4) {
423590 fprintf(stderr, "Failed to parse IO full PSI data\n");
591+ error_count++;
592+ }
424593 }
425594 }
426595 fclose(fp);
596+ } else {
597+ fprintf(stderr, "Warning: Failed to open %s\n", PSI_IO_PATH);
598+ error_count++;
427599 }
600+
428601 /* IRQ pressure (only full) */
429− fp = fopen(PSI_IRQ_FULL, "r");
602+ fp = fopen(PSI_IRQ_PATH, "r");
430603 if (fp) {
431604 while (fgets(line, sizeof(line), fp)) {
432605 if (strncmp(line, "full", 4) == 0) {
433606 ret = sscanf(line, "full avg10=%lf avg60=%lf avg300=%lf total=%llu",
434607 &psi.irq_full_avg10, &psi.irq_full_avg60,
435608 &psi.irq_full_avg300, &psi.irq_full_total);
436− if (ret != 4)
609+ if (ret != 4) {
437610 fprintf(stderr, "Failed to parse IRQ full PSI data\n");
611+ error_count++;
612+ }
438613 }
439614 }
440615 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;
441625 }
626+
627+ return 0;
442628 }
443629
444630 static 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
527713 SET_TASK_STAT(task_count, wpcopy_delay_total);
528714 SET_TASK_STAT(task_count, irq_count);
529715 SET_TASK_STAT(task_count, irq_delay_total);
716+ set_mem_count(&tasks[task_count]);
717+ set_mem_delay_total(&tasks[task_count]);
530718 task_count++;
531719 }
532720 break;
@@ -587,19 +775,23 @@ static int compare_tasks(const void *a, const void *b) · 54 unmodified lines
587775 {
588776 const struct task_info *t1 = (const struct task_info *)a;
589777 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;
590782 double avg1, avg2;
591783
592− switch (cfg.sort_field) {
593− case 'c': /* CPU */
594− avg1 = average_ms(t1->cpu_delay_total, t1->cpu_count);
595− avg2 = average_ms(t2->cpu_delay_total, t2->cpu_count);
596− if (avg1 != avg2)
597− return avg2 > avg1 ? 1 : -1;
598− return t2->cpu_delay_total > t1->cpu_delay_total ? 1 : -1;
784+ total1 = *(unsigned long long *)((char *)t1 + cfg.sort_field->total_offset);
785+ total2 = *(unsigned long long *)((char *)t2 + cfg.sort_field->total_offset);
786+ count1 = *(unsigned long *)((char *)t1 + cfg.sort_field->count_offset);
787+ count2 = *(unsigned long *)((char *)t2 + cfg.sort_field->count_offset);
599788
600− default:
601− return t2->cpu_delay_total > t1->cpu_delay_total ? 1 : -1;
602− }
789+ avg1 = average_ms(total1, count1);
790+ avg2 = average_ms(total2, count2);
791+ if (avg1 != avg2)
792+ return avg2 > avg1 ? 1 : -1;
793+
794+ return 0;
603795 }
604796
605797 /* Sort tasks by selected field */
@@ -673,7 +865,7 @@ static void get_container_stats(void) · 67 unmodified lines
673865 }
674866
675867 /* Display results to stdout or log file */
676−static void display_results(void)
868+static void display_results(int psi_ret)
677869 {
678870 time_t now = time(NULL);
679871 struct tm *tm_now = localtime(&now);
@@ -686,49 +878,53 @@ static void display_results(void) · 6 unmodified lines
686878 suc &= BOOL_FPRINT(out, "\033[H\033[J");
687879
688880 /* PSI output (one-line, no cat style) */
689− suc &= BOOL_FPRINT(out, "System Pressure Information: (avg10/avg60/avg300/total)\n");
690− suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
691− "CPU some:",
692− psi.cpu_some_avg10,
693− psi.cpu_some_avg60,
694− psi.cpu_some_avg300,
695− psi.cpu_some_total / 1000);
696− suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
697− "CPU full:",
698− psi.cpu_full_avg10,
699− psi.cpu_full_avg60,
700− psi.cpu_full_avg300,
701− psi.cpu_full_total / 1000);
702− suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
703− "Memory full:",
704− psi.memory_full_avg10,
705− psi.memory_full_avg60,
706− psi.memory_full_avg300,
707− psi.memory_full_total / 1000);
708− suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
709− "Memory some:",
710− psi.memory_some_avg10,
711− psi.memory_some_avg60,
712− psi.memory_some_avg300,
713− psi.memory_some_total / 1000);
714− suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
715− "IO full:",
716− psi.io_full_avg10,
717− psi.io_full_avg60,
718− psi.io_full_avg300,
719− psi.io_full_total / 1000);
720− suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
721− "IO some:",
722− psi.io_some_avg10,
723− psi.io_some_avg60,
724− psi.io_some_avg300,
725− psi.io_some_total / 1000);
726− suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
727− "IRQ full:",
728− psi.irq_full_avg10,
729− psi.irq_full_avg60,
730− psi.irq_full_avg300,
731− psi.irq_full_total / 1000);
881+ suc &= BOOL_FPRINT(out, "System Pressure Information: (avg10/avg60vg300/total)\n");
882+ if (psi_ret) {
883+ suc &= BOOL_FPRINT(out, " PSI not found: check if psi=1 enabled in cmdline\n");
884+ } else {
885+ suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
886+ "CPU some:",
887+ psi.cpu_some_avg10,
888+ psi.cpu_some_avg60,
889+ psi.cpu_some_avg300,
890+ psi.cpu_some_total / 1000);
891+ suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
892+ "CPU full:",
893+ psi.cpu_full_avg10,
894+ psi.cpu_full_avg60,
895+ psi.cpu_full_avg300,
896+ psi.cpu_full_total / 1000);
897+ suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
898+ "Memory full:",
899+ psi.memory_full_avg10,
900+ psi.memory_full_avg60,
901+ psi.memory_full_avg300,
902+ psi.memory_full_total / 1000);
903+ suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
904+ "Memory some:",
905+ psi.memory_some_avg10,
906+ psi.memory_some_avg60,
907+ psi.memory_some_avg300,
908+ psi.memory_some_total / 1000);
909+ suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
910+ "IO full:",
911+ psi.io_full_avg10,
912+ psi.io_full_avg60,
913+ psi.io_full_avg300,
914+ psi.io_full_total / 1000);
915+ suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
916+ "IO some:",
917+ psi.io_some_avg10,
918+ psi.io_some_avg60,
919+ psi.io_some_avg300,
920+ psi.io_some_total / 1000);
921+ suc &= BOOL_FPRINT(out, PSI_LINE_FORMAT,
922+ "IRQ full:",
923+ psi.irq_full_avg10,
924+ psi.irq_full_avg60,
925+ psi.irq_full_avg300,
926+ psi.irq_full_total / 1000);
927+ }
732928
733929 if (cfg.container_path) {
734930 suc &= BOOL_FPRINT(out, "Container Information (%s):\n", cfg.container_path);
@@ -738,29 +934,59 @@ static void display_results(void) · 3 unmodified lines
738934 container_stats.nr_stopped, container_stats.nr_uninterruptible,
739935 container_stats.nr_io_wait);
740936 }
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)");
747937
748− suc &= BOOL_FPRINT(out, "-----------------------------------------------");
749− suc &= BOOL_FPRINT(out, "----------------------------------------------\n");
938+ /* Interacive command */
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+
750970 count = task_count < cfg.max_processes ? task_count : cfg.max_processes;
751971
752972 for (i = 0; i < count; i++) {
753− suc &= BOOL_FPRINT(out, "%5d %5d %-15s",
973+ suc &= BOOL_FPRINT(out, "%8d %8d %-15s",
754974 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",
756− average_ms(tasks[i].cpu_delay_total, tasks[i].cpu_count),
757− average_ms(tasks[i].blkio_delay_total, tasks[i].blkio_count),
758− average_ms(tasks[i].swapin_delay_total, tasks[i].swapin_count),
759− average_ms(tasks[i].freepages_delay_total, tasks[i].freepages_count),
760− average_ms(tasks[i].thrashing_delay_total, tasks[i].thrashing_count),
761− average_ms(tasks[i].compact_delay_total, tasks[i].compact_count),
762− average_ms(tasks[i].wpcopy_delay_total, tasks[i].wpcopy_count),
763− average_ms(tasks[i].irq_delay_total, tasks[i].irq_count));
975+ if (cfg.display_mode == MODE_MEMVERBOSE) {
976+ suc &= BOOL_FPRINT(out, DELAY_FMT_MEMVERBOSE,
977+ TASK_AVG(tasks[i], mem),
978+ TASK_AVG(tasks[i], swapin),
979+ TASK_AVG(tasks[i], freepages),
980+ TASK_AVG(tasks[i], thrashing),
981+ TASK_AVG(tasks[i], compact),
982+ TASK_AVG(tasks[i], wpcopy));
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+ }
764990 }
765991
766992 suc &= BOOL_FPRINT(out, "\n");
@@ -769,11 +995,79 @@ static void display_results(void) · 2 unmodified lines
769995 perror("Error writing to output");
770996 }
771997
998+/* Check for keyboard input with timeout based on cfg.delay */
999+static 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
1018+static 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 */
1028+static 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+
7721064 /* Main function */
7731065 int main(int argc, char **argv)
7741066 {
1067+ const struct field_desc *field;
7751068 int iterations = 0;
776− int use_q_quit = 0;
1069+ int psi_ret = 0;
1070+ char keypress;
7771071
7781072 /* Parse command line arguments */
7791073 parse_args(argc, argv);
@@ -793,17 +1087,24 @@ int main(int argc, char **argv) · 13 unmodified lines
7931087 exit(1);
7941088 }
7951089
796− if (!cfg.output_one_time) {
797− use_q_quit = 1;
798− enable_raw_mode();
799− printf("Press 'q' to quit.\n");
800− fflush(stdout);
801− }
1090+ /* Set terminal to non-canonical mode for interaction */
1091+ enable_raw_mode();
8021092
8031093 /* Main loop */
8041094 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+
8051106 /* Read PSI statistics */
806− read_psi_stats();
1107+ psi_ret = read_psi_stats();
8071108
8081109 /* Get container stats if container path provided */
8091110 if (cfg.container_path)
@@ -816,7 +1117,7 @@ int main(int argc, char **argv) · 6 unmodified lines
8161117 sort_tasks();
8171118
8181119 /* Display results to stdout or log file */
819− display_results();
1120+ display_results(psi_ret);
8201121
8211122 /* Check for iterations */
8221123 if (cfg.iterations > 0 && ++iterations >= cfg.iterations)
@@ -826,32 +1127,14 @@ int main(int argc, char **argv) · 3 unmodified lines
8261127 if (cfg.output_one_time)
8271128 break;
8281129
829− /* Check for 'q' key to quit */
830− if (use_q_quit) {
831− struct timeval tv = {cfg.delay, 0};
832− fd_set readfds;
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− }
1130+ /* Keypress for interactive usage */
1131+ keypress = check_for_keypress();
1132+ if (keypress)
1133+ handle_keypress(keypress, &running);
8501134 }
8511135
8521136 /* Restore terminal mode */
853− if (use_q_quit)
854− disable_raw_mode();
1137+ disable_raw_mode();
8551138
8561139 /* Cleanup */
8571140 close(nl_sd);
tools/testing/radix-tree/idr-test.c+7−9
@@ -499,19 +499,17 @@ void ida_check_random(void) · 498 unmodified lines
499499 goto repeat;
500500 }
501501
502−void ida_simple_get_remove_test(void)
502+void ida_alloc_free_test(void)
503503 {
504504 DEFINE_IDA(ida);
505505 unsigned long i;
506506
507− for (i = 0; i < 10000; i++) {
508− assert(ida_simple_get(&ida, 0, 20000, GFP_KERNEL) == i);
509− }
510− assert(ida_simple_get(&ida, 5, 30, GFP_KERNEL) < 0);
507+ for (i = 0; i < 10000; i++)
508+ assert(ida_alloc_max(&ida, 20000, GFP_KERNEL) == i);
509+ assert(ida_alloc_range(&ida, 5, 30, GFP_KERNEL) < 0);
511510
512− for (i = 0; i < 10000; i++) {
513− ida_simple_remove(&ida, i);
514− }
511+ for (i = 0; i < 10000; i++)
512+ ida_free(&ida, i);
515513 assert(ida_is_empty(&ida));
516514
517515 ida_destroy(&ida);
@@ -524,7 +522,7 @@ void user_ida_checks(void) · 6 unmodified lines
524522 ida_check_nomem();
525523 ida_check_conv_user();
526524 ida_check_random();
527− ida_simple_get_remove_test();
525+ ida_alloc_free_test();
528526
529527 radix_tree_cpu_dead(1);
530528 }
tools/testing/selftests/proc/.gitignore+1−0
@@ -7,6 +7,7 @@ · 6 unmodified lines
77 /proc-loadavg-001
88 /proc-maps-race
99 /proc-multiple-procfs
10+/proc-net-dev-lseek
1011 /proc-empty-vm
1112 /proc-pid-vm
1213 /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
1010 TEST_GEN_PROGS += proc-2-is-kthread
1111 TEST_GEN_PROGS += proc-loadavg-001
1212 TEST_GEN_PROGS += proc-maps-race
13+TEST_GEN_PROGS += proc-net-dev-lseek
1314 TEST_GEN_PROGS += proc-empty-vm
1415 TEST_GEN_PROGS += proc-pid-vm
1516 TEST_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+ */
30+int 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
4747 #include <sys/resource.h>
4848 #include <linux/fs.h>
4949
50+#ifndef __maybe_unused
51+#define __maybe_unused __attribute__((__unused__))
52+#endif
53+
5054 #include "../kselftest.h"
5155
5256 static 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
218222 * 2: vsyscall VMA is r-xp vsyscall=emulate
219223 */
220224 static volatile int g_vsyscall;
221−static const char *str_vsyscall;
225+static const char *str_vsyscall __maybe_unused;
222226
223−static const char str_vsyscall_0[] = "";
224−static const char str_vsyscall_1[] =
227+static const char str_vsyscall_0[] __maybe_unused = "";
228+static const char str_vsyscall_1[] __maybe_unused =
225229 "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]\n";
226−static const char str_vsyscall_2[] =
230+static const char str_vsyscall_2[] __maybe_unused =
227231 "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n";
228232
229233 #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