- The 7 patch series "powerpc/crash: use generic crashkernel

reservation" from Sourabh Jain changes powerpc's kexec code to use more
   of the generic layers.
 
 - The 2 patch series "get_maintainer: report subsystem status
   separately" from Vlastimil Babka makes some long-requested improvements
   to the get_maintainer output.
 
 - The 4 patch series "ucount: Simplify refcounting with rcuref_t" from
   Sebastian Siewior cleans up and optimizing the refcounting in the ucount
   code.
 
 - The 12 patch series "reboot: support runtime configuration of
   emergency hw_protection action" from Ahmad Fatoum improves the ability
   for a driver to perform an emergency system shutdown or reboot.
 
 - The 16 patch series "Converge on using secs_to_jiffies() part two"
   from Easwar Hariharan performs further migrations from
   msecs_to_jiffies() to secs_to_jiffies().
 
 - The 7 patch series "lib/interval_tree: add some test cases and
   cleanup" from Wei Yang permits more userspace testing of kernel library
   code, adds some more tests and performs some cleanups.
 
 - The 2 patch series "hung_task: Dump the blocking task stacktrace" from
   Masami Hiramatsu arranges for the hung_task detector to dump the stack
   of the blocking task and not just that of the blocked task.
 
 - The 4 patch series "resource: Split and use DEFINE_RES*() macros" from
   Andy Shevchenko provides some cleanups to the resource definition
   macros.
 
 - Plus the usual shower of singleton patches - please see the individual
   changelogs for details.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQTTMBEPP41GrTpTJgfdBJ7gKXxAjgUCZ+nuqwAKCRDdBJ7gKXxA
 jtNqAQDxqJpjWkzn4yN9CNSs1ivVx3fr6SqazlYCrt3u89WQvwEA1oRrGpETzUGq
 r6khQUIcQImPPcjFqEFpuiSOU0MBZA0=
 =Kii8
 -----END PGP SIGNATURE-----

Merge tag 'mm-nonmm-stable-2025-03-30-18-23' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull non-MM updates from Andrew Morton:

 - The series "powerpc/crash: use generic crashkernel reservation" from
   Sourabh Jain changes powerpc's kexec code to use more of the generic
   layers.

 - The series "get_maintainer: report subsystem status separately" from
   Vlastimil Babka makes some long-requested improvements to the
   get_maintainer output.

 - The series "ucount: Simplify refcounting with rcuref_t" from
   Sebastian Siewior cleans up and optimizing the refcounting in the
   ucount code.

 - The series "reboot: support runtime configuration of emergency
   hw_protection action" from Ahmad Fatoum improves the ability for a
   driver to perform an emergency system shutdown or reboot.

 - The series "Converge on using secs_to_jiffies() part two" from Easwar
   Hariharan performs further migrations from msecs_to_jiffies() to
   secs_to_jiffies().

 - The series "lib/interval_tree: add some test cases and cleanup" from
   Wei Yang permits more userspace testing of kernel library code, adds
   some more tests and performs some cleanups.

 - The series "hung_task: Dump the blocking task stacktrace" from Masami
   Hiramatsu arranges for the hung_task detector to dump the stack of
   the blocking task and not just that of the blocked task.

 - The series "resource: Split and use DEFINE_RES*() macros" from Andy
   Shevchenko provides some cleanups to the resource definition macros.

 - Plus the usual shower of singleton patches - please see the
   individual changelogs for details.

* tag 'mm-nonmm-stable-2025-03-30-18-23' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (77 commits)
  mailmap: consolidate email addresses of Alexander Sverdlin
  fs/procfs: fix the comment above proc_pid_wchan()
  relay: use kasprintf() instead of fixed buffer formatting
  resource: replace open coded variant of DEFINE_RES()
  resource: replace open coded variants of DEFINE_RES_*_NAMED()
  resource: replace open coded variant of DEFINE_RES_NAMED_DESC()
  resource: split DEFINE_RES_NAMED_DESC() out of DEFINE_RES_NAMED()
  samples: add hung_task detector mutex blocking sample
  hung_task: show the blocker task if the task is hung on mutex
  kexec_core: accept unaccepted kexec segments' destination addresses
  watchdog/perf: optimize bytes copied and remove manual NUL-termination
  lib/interval_tree: fix the comment of interval_tree_span_iter_next_gap()
  lib/interval_tree: skip the check before go to the right subtree
  lib/interval_tree: add test case for span iteration
  lib/interval_tree: add test case for interval_tree_iter_xxx() helpers
  lib/rbtree: add random seed
  lib/rbtree: split tests
  lib/rbtree: enable userland test suite for rbtree related data structure
  checkpatch: describe --min-conf-desc-length
  scripts/gdb/symbols: determine KASLR offset on s390
  ...
This commit is contained in:
Linus Torvalds 2025-04-01 10:06:52 -07:00
commit d6b02199cd
107 changed files with 1392 additions and 627 deletions

View File

@ -31,6 +31,13 @@ Alexander Lobakin <alobakin@pm.me> <alobakin@marvell.com>
Alexander Lobakin <alobakin@pm.me> <bloodyreaper@yandex.ru>
Alexander Mikhalitsyn <alexander@mihalicyn.com> <alexander.mikhalitsyn@virtuozzo.com>
Alexander Mikhalitsyn <alexander@mihalicyn.com> <aleksandr.mikhalitsyn@canonical.com>
Alexander Sverdlin <alexander.sverdlin@gmail.com> <alexander.sverdlin.ext@nsn.com>
Alexander Sverdlin <alexander.sverdlin@gmail.com> <alexander.sverdlin@gmx.de>
Alexander Sverdlin <alexander.sverdlin@gmail.com> <alexander.sverdlin@nokia.com>
Alexander Sverdlin <alexander.sverdlin@gmail.com> <alexander.sverdlin@nsn.com>
Alexander Sverdlin <alexander.sverdlin@gmail.com> <alexander.sverdlin@siemens.com>
Alexander Sverdlin <alexander.sverdlin@gmail.com> <alexander.sverdlin@sysgo.com>
Alexander Sverdlin <alexander.sverdlin@gmail.com> <subaparts@yandex.ru>
Alexandre Belloni <alexandre.belloni@bootlin.com> <alexandre.belloni@free-electrons.com>
Alexandre Ghiti <alex@ghiti.fr> <alexandre.ghiti@canonical.com>
Alexei Avshalom Lazar <quic_ailizaro@quicinc.com> <ailizaro@codeaurora.org>
@ -153,7 +160,6 @@ Carlos Bilbao <carlos.bilbao@kernel.org> <carlos.bilbao@amd.com>
Carlos Bilbao <carlos.bilbao@kernel.org> <carlos.bilbao.osdev@gmail.com>
Carlos Bilbao <carlos.bilbao@kernel.org> <bilbao@vt.edu>
Changbin Du <changbin.du@intel.com> <changbin.du@gmail.com>
Changbin Du <changbin.du@intel.com> <changbin.du@intel.com>
Chao Yu <chao@kernel.org> <chao2.yu@samsung.com>
Chao Yu <chao@kernel.org> <yuchao0@huawei.com>
Chester Lin <chester62515@gmail.com> <clin@suse.com>
@ -271,6 +277,7 @@ Hamza Mahfooz <hamzamahfooz@linux.microsoft.com> <hamza.mahfooz@amd.com>
Hanjun Guo <guohanjun@huawei.com> <hanjun.guo@linaro.org>
Hans Verkuil <hverkuil@xs4all.nl> <hansverk@cisco.com>
Hans Verkuil <hverkuil@xs4all.nl> <hverkuil-cisco@xs4all.nl>
Harry Yoo <harry.yoo@oracle.com> <42.hyeyoo@gmail.com>
Heiko Carstens <hca@linux.ibm.com> <h.carstens@de.ibm.com>
Heiko Carstens <hca@linux.ibm.com> <heiko.carstens@de.ibm.com>
Heiko Stuebner <heiko@sntech.de> <heiko.stuebner@bqreaders.com>
@ -305,7 +312,6 @@ Jan Glauber <jan.glauber@gmail.com> <jglauber@cavium.com>
Jan Kuliga <jtkuliga.kdev@gmail.com> <jankul@alatek.krakow.pl>
Jarkko Sakkinen <jarkko@kernel.org> <jarkko.sakkinen@linux.intel.com>
Jarkko Sakkinen <jarkko@kernel.org> <jarkko@profian.com>
Jarkko Sakkinen <jarkko@kernel.org> <jarkko.sakkinen@parity.io>
Jason Gunthorpe <jgg@ziepe.ca> <jgg@mellanox.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgg@nvidia.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgunthorpe@obsidianresearch.com>
@ -762,7 +768,6 @@ Vinod Koul <vkoul@kernel.org> <vkoul@infradead.org>
Viresh Kumar <vireshk@kernel.org> <viresh.kumar2@arm.com>
Viresh Kumar <vireshk@kernel.org> <viresh.kumar@st.com>
Viresh Kumar <vireshk@kernel.org> <viresh.linux@gmail.com>
Viresh Kumar <viresh.kumar@linaro.org> <viresh.kumar@linaro.org>
Viresh Kumar <viresh.kumar@linaro.org> <viresh.kumar@linaro.com>
Vishnu Dasa <vishnu.dasa@broadcom.com> <vdasa@vmware.com>
Vivek Aknurwar <quic_viveka@quicinc.com> <viveka@codeaurora.org>

View File

@ -30,3 +30,11 @@ KernelVersion: 5.11
Contact: Matteo Croce <mcroce@microsoft.com>
Description: Don't wait for any other CPUs on reboot and
avoid anything that could hang.
What: /sys/kernel/reboot/hw_protection
Date: April 2025
KernelVersion: 6.15
Contact: Ahmad Fatoum <a.fatoum@pengutronix.de>
Description: Hardware protection action taken on critical events like
overtemperature or imminent voltage loss.
Valid values are: reboot shutdown

View File

@ -1954,6 +1954,12 @@
which allow the hypervisor to 'idle' the guest
on lock contention.
hw_protection= [HW]
Format: reboot | shutdown
Hardware protection action taken on critical events like
overtemperature or imminent voltage loss.
i2c_bus= [HW] Override the default board specific I2C bus speed
or register an additional I2C bus that is not
registered from board initialization code.

View File

@ -82,9 +82,8 @@ patternProperties:
$ref: /schemas/types.yaml#/definitions/string
description: |
The action the OS should perform after the critical temperature is reached.
By default the system will shutdown as a safe action to prevent damage
to the hardware, if the property is not set.
The shutdown action should be always the default and preferred one.
If the property is not set, it is up to the system to select the correct
action. The recommended and preferred default is shutdown.
Choose 'reboot' with care, as the hardware may be in thermal stress,
thus leading to infinite reboots that may cause damage to the hardware.
Make sure the firmware/bootloader will act as the last resort and take

View File

@ -413,18 +413,21 @@ This function serves as an arbitrator to set the state of a cooling
device. It sets the cooling device to the deepest cooling state if
possible.
5. thermal_emergency_poweroff
=============================
5. Critical Events
==================
On an event of critical trip temperature crossing the thermal framework
shuts down the system by calling hw_protection_shutdown(). The
hw_protection_shutdown() first attempts to perform an orderly shutdown
but accepts a delay after which it proceeds doing a forced power-off
or as last resort an emergency_restart.
On an event of critical trip temperature crossing, the thermal framework
will trigger a hardware protection power-off (shutdown) or reboot,
depending on configuration.
At first, the kernel will attempt an orderly power-off or reboot, but
accepts a delay after which it proceeds to do a forced power-off or
reboot, respectively. If this fails, ``emergency_restart()`` is invoked
as last resort.
The delay should be carefully profiled so as to give adequate time for
orderly poweroff.
orderly power-off or reboot.
If the delay is set to 0 emergency poweroff will not be supported. So a
carefully profiled non-zero positive value is a must for emergency
poweroff to be triggered.
If the delay is set to 0, the emergency action will not be supported. So a
carefully profiled non-zero positive value is a must for the emergency
action to be triggered.

View File

@ -128,6 +128,16 @@ process running on the system, which is named after the process ID (PID).
The link 'self' points to the process reading the file system. Each process
subdirectory has the entries listed in Table 1-1.
A process can read its own information from /proc/PID/* with no extra
permissions. When reading /proc/PID/* information for other processes, reading
process is required to have either CAP_SYS_PTRACE capability with
PTRACE_MODE_READ access permissions, or, alternatively, CAP_PERFMON
capability. This applies to all read-only information like `maps`, `environ`,
`pagemap`, etc. The only exception is `mem` file due to its read-write nature,
which requires CAP_SYS_PTRACE capabilities with more elevated
PTRACE_MODE_ATTACH permissions; CAP_PERFMON capability does not grant access
to /proc/PID/mem for other processes.
Note that an open file descriptor to /proc/<pid> or to any of its
contained files or subdirectories does not prevent <pid> being reused
for some other process in the event that <pid> exits. Operations on

View File

@ -18802,6 +18802,7 @@ F: mm/percpu*.c
PER-TASK DELAY ACCOUNTING
M: Balbir Singh <bsingharora@gmail.com>
M: Yang Yang <yang.yang29@zte.com.cn>
S: Maintained
F: include/linux/delayacct.h
F: kernel/delayacct.c
@ -22153,7 +22154,7 @@ M: Joonsoo Kim <iamjoonsoo.kim@lge.com>
M: Andrew Morton <akpm@linux-foundation.org>
M: Vlastimil Babka <vbabka@suse.cz>
R: Roman Gushchin <roman.gushchin@linux.dev>
R: Hyeonggon Yoo <42.hyeyoo@gmail.com>
R: Harry Yoo <harry.yoo@oracle.com>
L: linux-mm@kvack.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/vbabka/slab.git

View File

@ -98,21 +98,19 @@ static void __init arch_reserve_crashkernel(void)
{
unsigned long long low_size = 0;
unsigned long long crash_base, crash_size;
char *cmdline = boot_command_line;
bool high = false;
int ret;
if (!IS_ENABLED(CONFIG_CRASH_RESERVE))
return;
ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
&crash_size, &crash_base,
&low_size, &high);
if (ret)
return;
reserve_crashkernel_generic(cmdline, crash_size, crash_base,
low_size, high);
reserve_crashkernel_generic(crash_size, crash_base, low_size, high);
}
static phys_addr_t __init max_zone_phys(phys_addr_t zone_limit)

View File

@ -259,18 +259,17 @@ static void __init arch_reserve_crashkernel(void)
int ret;
unsigned long long low_size = 0;
unsigned long long crash_base, crash_size;
char *cmdline = boot_command_line;
bool high = false;
if (!IS_ENABLED(CONFIG_CRASH_RESERVE))
return;
ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
&crash_size, &crash_base, &low_size, &high);
if (ret)
return;
reserve_crashkernel_generic(cmdline, crash_size, crash_base, low_size, high);
reserve_crashkernel_generic(crash_size, crash_base, low_size, high);
}
static void __init fdt_setup(void)

View File

@ -716,6 +716,9 @@ config ARCH_SUPPORTS_CRASH_HOTPLUG
def_bool y
depends on PPC64
config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
def_bool CRASH_RESERVE
config FA_DUMP
bool "Firmware-assisted dump"
depends on CRASH_DUMP && PPC64 && (PPC_RTAS || PPC_POWERNV)

View File

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_POWERPC_CRASH_RESERVE_H
#define _ASM_POWERPC_CRASH_RESERVE_H
/* crash kernel regions are Page size agliged */
#define CRASH_ALIGN PAGE_SIZE
#endif /* _ASM_POWERPC_CRASH_RESERVE_H */

View File

@ -94,8 +94,10 @@ int arch_kexec_kernel_image_probe(struct kimage *image, void *buf, unsigned long
int arch_kimage_file_post_load_cleanup(struct kimage *image);
#define arch_kimage_file_post_load_cleanup arch_kimage_file_post_load_cleanup
int arch_kexec_locate_mem_hole(struct kexec_buf *kbuf);
#define arch_kexec_locate_mem_hole arch_kexec_locate_mem_hole
int arch_check_excluded_range(struct kimage *image, unsigned long start,
unsigned long end);
#define arch_check_excluded_range arch_check_excluded_range
int load_crashdump_segments_ppc64(struct kimage *image,
struct kexec_buf *kbuf);
@ -112,9 +114,9 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, struct crash_mem
#ifdef CONFIG_CRASH_RESERVE
int __init overlaps_crashkernel(unsigned long start, unsigned long size);
extern void reserve_crashkernel(void);
extern void arch_reserve_crashkernel(void);
#else
static inline void reserve_crashkernel(void) {}
static inline void arch_reserve_crashkernel(void) {}
static inline int overlaps_crashkernel(unsigned long start, unsigned long size) { return 0; }
#endif

View File

@ -860,7 +860,7 @@ void __init early_init_devtree(void *params)
*/
if (fadump_reserve_mem() == 0)
#endif
reserve_crashkernel();
arch_reserve_crashkernel();
early_reserve_mem();
if (memory_limit > memblock_phys_mem_size())

View File

@ -58,38 +58,20 @@ void machine_kexec(struct kimage *image)
}
#ifdef CONFIG_CRASH_RESERVE
void __init reserve_crashkernel(void)
static unsigned long long __init get_crash_base(unsigned long long crash_base)
{
unsigned long long crash_size, crash_base, total_mem_sz;
int ret;
total_mem_sz = memory_limit ? memory_limit : memblock_phys_mem_size();
/* use common parsing */
ret = parse_crashkernel(boot_command_line, total_mem_sz,
&crash_size, &crash_base, NULL, NULL);
if (ret == 0 && crash_size > 0) {
crashk_res.start = crash_base;
crashk_res.end = crash_base + crash_size - 1;
}
if (crashk_res.end == crashk_res.start) {
crashk_res.start = crashk_res.end = 0;
return;
}
/* We might have got these values via the command line or the
* device tree, either way sanitise them now. */
crash_size = resource_size(&crashk_res);
#ifndef CONFIG_NONSTATIC_KERNEL
if (crashk_res.start != KDUMP_KERNELBASE)
if (crash_base != KDUMP_KERNELBASE)
printk("Crash kernel location must be 0x%x\n",
KDUMP_KERNELBASE);
crashk_res.start = KDUMP_KERNELBASE;
return KDUMP_KERNELBASE;
#else
if (!crashk_res.start) {
unsigned long long crash_base_align;
if (!crash_base) {
#ifdef CONFIG_PPC64
/*
* On the LPAR platform place the crash kernel to mid of
@ -101,53 +83,51 @@ void __init reserve_crashkernel(void)
* kernel starts at 128MB offset on other platforms.
*/
if (firmware_has_feature(FW_FEATURE_LPAR))
crashk_res.start = min_t(u64, ppc64_rma_size / 2, SZ_512M);
crash_base = min_t(u64, ppc64_rma_size / 2, SZ_512M);
else
crashk_res.start = min_t(u64, ppc64_rma_size / 2, SZ_128M);
crash_base = min_t(u64, ppc64_rma_size / 2, SZ_128M);
#else
crashk_res.start = KDUMP_KERNELBASE;
crash_base = KDUMP_KERNELBASE;
#endif
}
crash_base = PAGE_ALIGN(crashk_res.start);
if (crash_base != crashk_res.start) {
printk("Crash kernel base must be aligned to 0x%lx\n",
PAGE_SIZE);
crashk_res.start = crash_base;
}
crash_base_align = PAGE_ALIGN(crash_base);
if (crash_base != crash_base_align)
pr_warn("Crash kernel base must be aligned to 0x%lx\n", PAGE_SIZE);
return crash_base_align;
#endif
crash_size = PAGE_ALIGN(crash_size);
crashk_res.end = crashk_res.start + crash_size - 1;
}
void __init arch_reserve_crashkernel(void)
{
unsigned long long crash_size, crash_base, crash_end;
unsigned long long kernel_start, kernel_size;
unsigned long long total_mem_sz;
int ret;
total_mem_sz = memory_limit ? memory_limit : memblock_phys_mem_size();
/* use common parsing */
ret = parse_crashkernel(boot_command_line, total_mem_sz, &crash_size,
&crash_base, NULL, NULL);
if (ret)
return;
crash_base = get_crash_base(crash_base);
crash_end = crash_base + crash_size - 1;
kernel_start = __pa(_stext);
kernel_size = _end - _stext;
/* The crash region must not overlap the current kernel */
if (overlaps_crashkernel(__pa(_stext), _end - _stext)) {
printk(KERN_WARNING
"Crash kernel can not overlap current kernel\n");
crashk_res.start = crashk_res.end = 0;
if ((kernel_start + kernel_size > crash_base) && (kernel_start <= crash_end)) {
pr_warn("Crash kernel can not overlap current kernel\n");
return;
}
/* Crash kernel trumps memory limit */
if (memory_limit && memory_limit <= crashk_res.end) {
memory_limit = crashk_res.end + 1;
total_mem_sz = memory_limit;
printk("Adjusted memory limit for crashkernel, now 0x%llx\n",
memory_limit);
}
printk(KERN_INFO "Reserving %ldMB of memory at %ldMB "
"for crashkernel (System RAM: %ldMB)\n",
(unsigned long)(crash_size >> 20),
(unsigned long)(crashk_res.start >> 20),
(unsigned long)(total_mem_sz >> 20));
if (!memblock_is_region_memory(crashk_res.start, crash_size) ||
memblock_reserve(crashk_res.start, crash_size)) {
pr_err("Failed to reserve memory for crashkernel!\n");
crashk_res.start = crashk_res.end = 0;
return;
}
reserve_crashkernel_generic(crash_size, crash_base, 0, false);
}
int __init overlaps_crashkernel(unsigned long start, unsigned long size)

View File

@ -49,201 +49,18 @@ const struct kexec_file_ops * const kexec_file_loaders[] = {
NULL
};
/**
* __locate_mem_hole_top_down - Looks top down for a large enough memory hole
* in the memory regions between buf_min & buf_max
* for the buffer. If found, sets kbuf->mem.
* @kbuf: Buffer contents and memory parameters.
* @buf_min: Minimum address for the buffer.
* @buf_max: Maximum address for the buffer.
*
* Returns 0 on success, negative errno on error.
*/
static int __locate_mem_hole_top_down(struct kexec_buf *kbuf,
u64 buf_min, u64 buf_max)
int arch_check_excluded_range(struct kimage *image, unsigned long start,
unsigned long end)
{
int ret = -EADDRNOTAVAIL;
phys_addr_t start, end;
u64 i;
struct crash_mem *emem;
int i;
for_each_mem_range_rev(i, &start, &end) {
/*
* memblock uses [start, end) convention while it is
* [start, end] here. Fix the off-by-one to have the
* same convention.
*/
end -= 1;
emem = image->arch.exclude_ranges;
for (i = 0; i < emem->nr_ranges; i++)
if (start < emem->ranges[i].end && end > emem->ranges[i].start)
return 1;
if (start > buf_max)
continue;
/* Memory hole not found */
if (end < buf_min)
break;
/* Adjust memory region based on the given range */
if (start < buf_min)
start = buf_min;
if (end > buf_max)
end = buf_max;
start = ALIGN(start, kbuf->buf_align);
if (start < end && (end - start + 1) >= kbuf->memsz) {
/* Suitable memory range found. Set kbuf->mem */
kbuf->mem = ALIGN_DOWN(end - kbuf->memsz + 1,
kbuf->buf_align);
ret = 0;
break;
}
}
return ret;
}
/**
* locate_mem_hole_top_down_ppc64 - Skip special memory regions to find a
* suitable buffer with top down approach.
* @kbuf: Buffer contents and memory parameters.
* @buf_min: Minimum address for the buffer.
* @buf_max: Maximum address for the buffer.
* @emem: Exclude memory ranges.
*
* Returns 0 on success, negative errno on error.
*/
static int locate_mem_hole_top_down_ppc64(struct kexec_buf *kbuf,
u64 buf_min, u64 buf_max,
const struct crash_mem *emem)
{
int i, ret = 0, err = -EADDRNOTAVAIL;
u64 start, end, tmin, tmax;
tmax = buf_max;
for (i = (emem->nr_ranges - 1); i >= 0; i--) {
start = emem->ranges[i].start;
end = emem->ranges[i].end;
if (start > tmax)
continue;
if (end < tmax) {
tmin = (end < buf_min ? buf_min : end + 1);
ret = __locate_mem_hole_top_down(kbuf, tmin, tmax);
if (!ret)
return 0;
}
tmax = start - 1;
if (tmax < buf_min) {
ret = err;
break;
}
ret = 0;
}
if (!ret) {
tmin = buf_min;
ret = __locate_mem_hole_top_down(kbuf, tmin, tmax);
}
return ret;
}
/**
* __locate_mem_hole_bottom_up - Looks bottom up for a large enough memory hole
* in the memory regions between buf_min & buf_max
* for the buffer. If found, sets kbuf->mem.
* @kbuf: Buffer contents and memory parameters.
* @buf_min: Minimum address for the buffer.
* @buf_max: Maximum address for the buffer.
*
* Returns 0 on success, negative errno on error.
*/
static int __locate_mem_hole_bottom_up(struct kexec_buf *kbuf,
u64 buf_min, u64 buf_max)
{
int ret = -EADDRNOTAVAIL;
phys_addr_t start, end;
u64 i;
for_each_mem_range(i, &start, &end) {
/*
* memblock uses [start, end) convention while it is
* [start, end] here. Fix the off-by-one to have the
* same convention.
*/
end -= 1;
if (end < buf_min)
continue;
/* Memory hole not found */
if (start > buf_max)
break;
/* Adjust memory region based on the given range */
if (start < buf_min)
start = buf_min;
if (end > buf_max)
end = buf_max;
start = ALIGN(start, kbuf->buf_align);
if (start < end && (end - start + 1) >= kbuf->memsz) {
/* Suitable memory range found. Set kbuf->mem */
kbuf->mem = start;
ret = 0;
break;
}
}
return ret;
}
/**
* locate_mem_hole_bottom_up_ppc64 - Skip special memory regions to find a
* suitable buffer with bottom up approach.
* @kbuf: Buffer contents and memory parameters.
* @buf_min: Minimum address for the buffer.
* @buf_max: Maximum address for the buffer.
* @emem: Exclude memory ranges.
*
* Returns 0 on success, negative errno on error.
*/
static int locate_mem_hole_bottom_up_ppc64(struct kexec_buf *kbuf,
u64 buf_min, u64 buf_max,
const struct crash_mem *emem)
{
int i, ret = 0, err = -EADDRNOTAVAIL;
u64 start, end, tmin, tmax;
tmin = buf_min;
for (i = 0; i < emem->nr_ranges; i++) {
start = emem->ranges[i].start;
end = emem->ranges[i].end;
if (end < tmin)
continue;
if (start > tmin) {
tmax = (start > buf_max ? buf_max : start - 1);
ret = __locate_mem_hole_bottom_up(kbuf, tmin, tmax);
if (!ret)
return 0;
}
tmin = end + 1;
if (tmin > buf_max) {
ret = err;
break;
}
ret = 0;
}
if (!ret) {
tmax = buf_max;
ret = __locate_mem_hole_bottom_up(kbuf, tmin, tmax);
}
return ret;
return 0;
}
#ifdef CONFIG_CRASH_DUMP
@ -1004,64 +821,6 @@ out:
return ret;
}
/**
* arch_kexec_locate_mem_hole - Skip special memory regions like rtas, opal,
* tce-table, reserved-ranges & such (exclude
* memory ranges) as they can't be used for kexec
* segment buffer. Sets kbuf->mem when a suitable
* memory hole is found.
* @kbuf: Buffer contents and memory parameters.
*
* Assumes minimum of PAGE_SIZE alignment for kbuf->memsz & kbuf->buf_align.
*
* Returns 0 on success, negative errno on error.
*/
int arch_kexec_locate_mem_hole(struct kexec_buf *kbuf)
{
struct crash_mem **emem;
u64 buf_min, buf_max;
int ret;
/* Look up the exclude ranges list while locating the memory hole */
emem = &(kbuf->image->arch.exclude_ranges);
if (!(*emem) || ((*emem)->nr_ranges == 0)) {
pr_warn("No exclude range list. Using the default locate mem hole method\n");
return kexec_locate_mem_hole(kbuf);
}
buf_min = kbuf->buf_min;
buf_max = kbuf->buf_max;
/* Segments for kdump kernel should be within crashkernel region */
if (IS_ENABLED(CONFIG_CRASH_DUMP) && kbuf->image->type == KEXEC_TYPE_CRASH) {
buf_min = (buf_min < crashk_res.start ?
crashk_res.start : buf_min);
buf_max = (buf_max > crashk_res.end ?
crashk_res.end : buf_max);
}
if (buf_min > buf_max) {
pr_err("Invalid buffer min and/or max values\n");
return -EINVAL;
}
if (kbuf->top_down)
ret = locate_mem_hole_top_down_ppc64(kbuf, buf_min, buf_max,
*emem);
else
ret = locate_mem_hole_bottom_up_ppc64(kbuf, buf_min, buf_max,
*emem);
/* Add the buffer allocated to the exclude list for the next lookup */
if (!ret) {
add_mem_range(emem, kbuf->mem, kbuf->memsz);
sort_memory_ranges(*emem, true);
} else {
pr_err("Failed to locate memory buffer of size %lu\n",
kbuf->memsz);
}
return ret;
}
/**
* arch_kexec_kernel_image_probe - Does additional handling needed to setup
* kexec segments.

View File

@ -338,7 +338,7 @@ static int __init add_system_ram_resources(void)
*/
res->end = end - 1;
res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
WARN_ON(request_resource(&iomem_resource, res) < 0);
WARN_ON(insert_resource(&iomem_resource, res) < 0);
}
}

View File

@ -1393,21 +1393,19 @@ static void __init arch_reserve_crashkernel(void)
{
unsigned long long low_size = 0;
unsigned long long crash_base, crash_size;
char *cmdline = boot_command_line;
bool high = false;
int ret;
if (!IS_ENABLED(CONFIG_CRASH_RESERVE))
return;
ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
&crash_size, &crash_base,
&low_size, &high);
if (ret)
return;
reserve_crashkernel_generic(cmdline, crash_size, crash_base,
low_size, high);
reserve_crashkernel_generic(crash_size, crash_base, low_size, high);
}
void __init paging_init(void)

View File

@ -578,14 +578,13 @@ static void __init memblock_x86_reserve_range_setup_data(void)
static void __init arch_reserve_crashkernel(void)
{
unsigned long long crash_base, crash_size, low_size = 0;
char *cmdline = boot_command_line;
bool high = false;
int ret;
if (!IS_ENABLED(CONFIG_CRASH_RESERVE))
return;
ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
&crash_size, &crash_base,
&low_size, &high);
if (ret)
@ -596,8 +595,7 @@ static void __init arch_reserve_crashkernel(void)
return;
}
reserve_crashkernel_generic(cmdline, crash_size, crash_base,
low_size, high);
reserve_crashkernel_generic(crash_size, crash_base, low_size, high);
}
static struct resource standard_io_resources[] = {

View File

@ -2586,7 +2586,7 @@ int hl_cs_ioctl(struct drm_device *ddev, void *data, struct drm_file *file_priv)
cs_seq = args->in.seq;
timeout = flags & HL_CS_FLAGS_CUSTOM_TIMEOUT
? msecs_to_jiffies(args->in.timeout * 1000)
? secs_to_jiffies(args->in.timeout)
: hpriv->hdev->timeout_jiffies;
switch (cs_type) {

View File

@ -1403,7 +1403,7 @@ static ssize_t hl_timeout_locked_write(struct file *f, const char __user *buf,
return rc;
if (value)
hdev->timeout_jiffies = msecs_to_jiffies(value * 1000);
hdev->timeout_jiffies = secs_to_jiffies(value);
else
hdev->timeout_jiffies = MAX_SCHEDULE_TIMEOUT;

View File

@ -2091,7 +2091,7 @@ int hl_device_cond_reset(struct hl_device *hdev, u32 flags, u64 event_mask)
dev_dbg(hdev->dev, "Device is going to be hard-reset in %u sec unless being released\n",
hdev->device_release_watchdog_timeout_sec);
schedule_delayed_work(&hdev->device_release_watchdog_work.reset_work,
msecs_to_jiffies(hdev->device_release_watchdog_timeout_sec * 1000));
secs_to_jiffies(hdev->device_release_watchdog_timeout_sec));
hdev->reset_info.watchdog_active = 1;
out:
spin_unlock(&hdev->reset_info.lock);

View File

@ -386,7 +386,7 @@ static int fixup_device_params(struct hl_device *hdev)
hdev->fw_comms_poll_interval_usec = HL_FW_STATUS_POLL_INTERVAL_USEC;
if (tmp_timeout)
hdev->timeout_jiffies = msecs_to_jiffies(tmp_timeout * MSEC_PER_SEC);
hdev->timeout_jiffies = secs_to_jiffies(tmp_timeout);
else
hdev->timeout_jiffies = MAX_SCHEDULE_TIMEOUT;

View File

@ -160,8 +160,7 @@ void zpodd_on_suspend(struct ata_device *dev)
return;
}
expires = zpodd->last_ready +
msecs_to_jiffies(zpodd_poweroff_delay * 1000);
expires = zpodd->last_ready + secs_to_jiffies(zpodd_poweroff_delay);
if (time_before(jiffies, expires))
return;

View File

@ -160,7 +160,7 @@ static int __wait_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie)
wait_event_timeout(cmdq->waitq,
!crsqe->is_in_used ||
test_bit(ERR_DEVICE_DETACHED, &cmdq->flags),
msecs_to_jiffies(rcfw->max_timeout * 1000));
secs_to_jiffies(rcfw->max_timeout));
if (!crsqe->is_in_used)
return 0;

View File

@ -4469,11 +4469,9 @@ static void nvme_fw_act_work(struct work_struct *work)
nvme_auth_stop(ctrl);
if (ctrl->mtfa)
fw_act_timeout = jiffies +
msecs_to_jiffies(ctrl->mtfa * 100);
fw_act_timeout = jiffies + msecs_to_jiffies(ctrl->mtfa * 100);
else
fw_act_timeout = jiffies +
msecs_to_jiffies(admin_timeout * 1000);
fw_act_timeout = jiffies + secs_to_jiffies(admin_timeout);
nvme_quiesce_io_queues(ctrl);
while (nvme_ctrl_pp_status(ctrl)) {

View File

@ -455,7 +455,7 @@ static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data)
blocking_notifier_call_chain(&ec_dev->panic_notifier, 0, ec_dev);
kobject_uevent_env(&ec_dev->dev->kobj, KOBJ_CHANGE, (char **)env);
/* Begin orderly shutdown. EC will force reset after a short period. */
hw_protection_shutdown("CrOS EC Panic", -1);
__hw_protection_trigger("CrOS EC Panic", -1, HWPROT_ACT_SHUTDOWN);
/* Do not query for other events after a panic is reported */
return;
}

View File

@ -502,8 +502,7 @@ static int da9030_battery_probe(struct platform_device *pdev)
/* 10 seconds between monitor runs unless platform defines other
interval */
charger->interval = msecs_to_jiffies(
(pdata->batmon_interval ? : 10) * 1000);
charger->interval = secs_to_jiffies(pdata->batmon_interval ? : 10);
charger->charge_milliamp = pdata->charge_milliamp;
charger->charge_millivolt = pdata->charge_millivolt;

View File

@ -5282,8 +5282,8 @@ static void regulator_handle_critical(struct regulator_dev *rdev,
if (!reason)
return;
hw_protection_shutdown(reason,
rdev->constraints->uv_less_critical_window_ms);
hw_protection_trigger(reason,
rdev->constraints->uv_less_critical_window_ms);
}
/**

View File

@ -64,16 +64,16 @@ static void regulator_notifier_isr_work(struct work_struct *work)
reread:
if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) {
if (!d->die)
return hw_protection_shutdown("Regulator HW failure? - no IC recovery",
REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
return hw_protection_trigger("Regulator HW failure? - no IC recovery",
REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
ret = d->die(rid);
/*
* If the 'last resort' IC recovery failed we will have
* nothing else left to do...
*/
if (ret)
return hw_protection_shutdown("Regulator HW failure. IC recovery failed",
REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
return hw_protection_trigger("Regulator HW failure. IC recovery failed",
REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
/*
* If h->die() was implemented we assume recovery has been
@ -263,14 +263,14 @@ fail_out:
if (d->fatal_cnt && h->retry_cnt > d->fatal_cnt) {
/* If we have no recovery, just try shut down straight away */
if (!d->die) {
hw_protection_shutdown("Regulator failure. Retry count exceeded",
REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
hw_protection_trigger("Regulator failure. Retry count exceeded",
REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
} else {
ret = d->die(rid);
/* If die() failed shut down as a last attempt to save the HW */
if (ret)
hw_protection_shutdown("Regulator failure. Recovery failed",
REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
hw_protection_trigger("Regulator failure. Recovery failed",
REGULATOR_FORCED_SAFETY_SHUTDOWN_WAIT_MS);
}
}

View File

@ -369,7 +369,8 @@ void thermal_governor_update_tz(struct thermal_zone_device *tz,
tz->governor->update_tz(tz, reason);
}
static void thermal_zone_device_halt(struct thermal_zone_device *tz, bool shutdown)
static void thermal_zone_device_halt(struct thermal_zone_device *tz,
enum hw_protection_action action)
{
/*
* poweroff_delay_ms must be a carefully profiled positive value.
@ -380,21 +381,23 @@ static void thermal_zone_device_halt(struct thermal_zone_device *tz, bool shutdo
dev_emerg(&tz->device, "%s: critical temperature reached\n", tz->type);
if (shutdown)
hw_protection_shutdown(msg, poweroff_delay_ms);
else
hw_protection_reboot(msg, poweroff_delay_ms);
__hw_protection_trigger(msg, poweroff_delay_ms, action);
}
void thermal_zone_device_critical(struct thermal_zone_device *tz)
{
thermal_zone_device_halt(tz, true);
thermal_zone_device_halt(tz, HWPROT_ACT_DEFAULT);
}
EXPORT_SYMBOL(thermal_zone_device_critical);
void thermal_zone_device_critical_shutdown(struct thermal_zone_device *tz)
{
thermal_zone_device_halt(tz, HWPROT_ACT_SHUTDOWN);
}
void thermal_zone_device_critical_reboot(struct thermal_zone_device *tz)
{
thermal_zone_device_halt(tz, false);
thermal_zone_device_halt(tz, HWPROT_ACT_REBOOT);
}
static void handle_critical_trips(struct thermal_zone_device *tz,

View File

@ -262,6 +262,7 @@ int thermal_build_list_of_policies(char *buf);
void __thermal_zone_device_update(struct thermal_zone_device *tz,
enum thermal_notify_event event);
void thermal_zone_device_critical_reboot(struct thermal_zone_device *tz);
void thermal_zone_device_critical_shutdown(struct thermal_zone_device *tz);
void thermal_governor_update_tz(struct thermal_zone_device *tz,
enum thermal_notify_event reason);

View File

@ -405,9 +405,12 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
of_ops.should_bind = thermal_of_should_bind;
ret = of_property_read_string(np, "critical-action", &action);
if (!ret)
if (!of_ops.critical && !strcasecmp(action, "reboot"))
if (!ret && !of_ops.critical) {
if (!strcasecmp(action, "reboot"))
of_ops.critical = thermal_zone_device_critical_reboot;
else if (!strcasecmp(action, "shutdown"))
of_ops.critical = thermal_zone_device_critical_shutdown;
}
tz = thermal_zone_device_register_with_trips(np->name, trips, ntrips,
data, &of_ops, &tzp,

View File

@ -1564,7 +1564,7 @@ static int transaction_kthread(void *arg)
do {
cannot_commit = false;
delay = msecs_to_jiffies(fs_info->commit_interval * 1000);
delay = secs_to_jiffies(fs_info->commit_interval);
mutex_lock(&fs_info->transaction_kthread_mutex);
spin_lock(&fs_info->trans_lock);
@ -1579,9 +1579,9 @@ static int transaction_kthread(void *arg)
cur->state < TRANS_STATE_COMMIT_PREP &&
delta < fs_info->commit_interval) {
spin_unlock(&fs_info->trans_lock);
delay -= msecs_to_jiffies((delta - 1) * 1000);
delay -= secs_to_jiffies(delta - 1);
delay = min(delay,
msecs_to_jiffies(fs_info->commit_interval * 1000));
secs_to_jiffies(fs_info->commit_interval));
goto sleep;
}
transid = cur->transid;

View File

@ -1803,6 +1803,14 @@ static int __ocfs2_find_path(struct ocfs2_caching_info *ci,
el = root_el;
while (el->l_tree_depth) {
if (unlikely(le16_to_cpu(el->l_tree_depth) >= OCFS2_MAX_PATH_DEPTH)) {
ocfs2_error(ocfs2_metadata_cache_get_super(ci),
"Owner %llu has invalid tree depth %u in extent list\n",
(unsigned long long)ocfs2_metadata_cache_owner(ci),
le16_to_cpu(el->l_tree_depth));
ret = -EROFS;
goto out;
}
if (le16_to_cpu(el->l_next_free_rec) == 0) {
ocfs2_error(ocfs2_metadata_cache_get_super(ci),
"Owner %llu has empty extent list at depth %u\n",

View File

@ -46,7 +46,6 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh = NULL;
struct buffer_head *buffer_cache_bh = NULL;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
void *kaddr;
trace_ocfs2_symlink_get_block(
(unsigned long long)OCFS2_I(inode)->ip_blkno,
@ -91,17 +90,11 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock,
* could've happened. Since we've got a reference on
* the bh, even if it commits while we're doing the
* copy, the data is still good. */
if (buffer_jbd(buffer_cache_bh)
&& ocfs2_inode_is_new(inode)) {
kaddr = kmap_atomic(bh_result->b_page);
if (!kaddr) {
mlog(ML_ERROR, "couldn't kmap!\n");
goto bail;
}
memcpy(kaddr + (bh_result->b_size * iblock),
buffer_cache_bh->b_data,
bh_result->b_size);
kunmap_atomic(kaddr);
if (buffer_jbd(buffer_cache_bh) && ocfs2_inode_is_new(inode)) {
memcpy_to_folio(bh_result->b_folio,
bh_result->b_size * iblock,
buffer_cache_bh->b_data,
bh_result->b_size);
set_buffer_uptodate(bh_result);
}
brelse(buffer_cache_bh);

View File

@ -273,7 +273,7 @@ ssize_t ocfs2_quota_write(struct super_block *sb, int type,
if (new)
memset(bh->b_data, 0, sb->s_blocksize);
memcpy(bh->b_data + offset, data, len);
flush_dcache_page(bh->b_page);
flush_dcache_folio(bh->b_folio);
set_buffer_uptodate(bh);
unlock_buffer(bh);
ocfs2_set_buffer_uptodate(INODE_CACHE(gqinode), bh);

View File

@ -416,7 +416,7 @@ static const struct file_operations proc_pid_cmdline_ops = {
#ifdef CONFIG_KALLSYMS
/*
* Provides a wchan file via kallsyms in a proper one-value-per-file format.
* Returns the resolved symbol. If that fails, simply return the address.
* Returns the resolved symbol to user space.
*/
static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task)

View File

@ -230,7 +230,7 @@ xfs_blockgc_queue(
rcu_read_lock();
if (radix_tree_tagged(&pag->pag_ici_root, XFS_ICI_BLOCKGC_TAG))
queue_delayed_work(mp->m_blockgc_wq, &pag->pag_blockgc_work,
msecs_to_jiffies(xfs_blockgc_secs * 1000));
secs_to_jiffies(xfs_blockgc_secs));
rcu_read_unlock();
}

View File

@ -569,8 +569,8 @@ retry_timeout_seconds_store(
if (val == -1)
cfg->retry_timeout = XFS_ERR_RETRY_FOREVER;
else {
cfg->retry_timeout = msecs_to_jiffies(val * MSEC_PER_SEC);
ASSERT(msecs_to_jiffies(val * MSEC_PER_SEC) < LONG_MAX);
cfg->retry_timeout = secs_to_jiffies(val);
ASSERT(secs_to_jiffies(val) < LONG_MAX);
}
return count;
}
@ -687,8 +687,8 @@ xfs_error_sysfs_init_class(
if (init[i].retry_timeout == XFS_ERR_RETRY_FOREVER)
cfg->retry_timeout = XFS_ERR_RETRY_FOREVER;
else
cfg->retry_timeout = msecs_to_jiffies(
init[i].retry_timeout * MSEC_PER_SEC);
cfg->retry_timeout =
secs_to_jiffies(init[i].retry_timeout);
}
return 0;

View File

@ -148,7 +148,7 @@ static inline int suspend_disable_secondary_cpus(void)
}
static inline void suspend_enable_secondary_cpus(void)
{
return thaw_secondary_cpus();
thaw_secondary_cpus();
}
#else /* !CONFIG_PM_SLEEP_SMP */

View File

@ -32,13 +32,12 @@ int __init parse_crashkernel(char *cmdline, unsigned long long system_ram,
#define CRASH_ADDR_HIGH_MAX memblock_end_of_DRAM()
#endif
void __init reserve_crashkernel_generic(char *cmdline,
unsigned long long crash_size,
unsigned long long crash_base,
unsigned long long crash_low_size,
bool high);
void __init reserve_crashkernel_generic(unsigned long long crash_size,
unsigned long long crash_base,
unsigned long long crash_low_size,
bool high);
#else
static inline void __init reserve_crashkernel_generic(char *cmdline,
static inline void __init reserve_crashkernel_generic(
unsigned long long crash_size,
unsigned long long crash_base,
unsigned long long crash_low_size,

View File

@ -104,12 +104,8 @@ ITPREFIX ## _subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE last) \
if (ITSTART(node) <= last) { /* Cond1 */ \
if (start <= ITLAST(node)) /* Cond2 */ \
return node; /* node is leftmost match */ \
if (node->ITRB.rb_right) { \
node = rb_entry(node->ITRB.rb_right, \
ITSTRUCT, ITRB); \
if (start <= node->ITSUBTREE) \
continue; \
} \
node = rb_entry(node->ITRB.rb_right, ITSTRUCT, ITRB); \
continue; \
} \
return NULL; /* No match */ \
} \

View File

@ -154,15 +154,20 @@ enum {
};
/* helpers to define resources */
#define DEFINE_RES_NAMED(_start, _size, _name, _flags) \
#define DEFINE_RES_NAMED_DESC(_start, _size, _name, _flags, _desc) \
(struct resource) { \
.start = (_start), \
.end = (_start) + (_size) - 1, \
.name = (_name), \
.flags = (_flags), \
.desc = IORES_DESC_NONE, \
.desc = (_desc), \
}
#define DEFINE_RES_NAMED(_start, _size, _name, _flags) \
DEFINE_RES_NAMED_DESC(_start, _size, _name, _flags, IORES_DESC_NONE)
#define DEFINE_RES(_start, _size, _flags) \
DEFINE_RES_NAMED(_start, _size, NULL, _flags)
#define DEFINE_RES_IO_NAMED(_start, _size, _name) \
DEFINE_RES_NAMED((_start), (_size), (_name), IORESOURCE_IO)
#define DEFINE_RES_IO(_start, _size) \

View File

@ -203,6 +203,15 @@ static inline int arch_kimage_file_post_load_cleanup(struct kimage *image)
}
#endif
#ifndef arch_check_excluded_range
static inline int arch_check_excluded_range(struct kimage *image,
unsigned long start,
unsigned long end)
{
return 0;
}
#endif
#ifdef CONFIG_KEXEC_SIG
#ifdef CONFIG_SIGNED_PE_FILE_VERIFICATION
int kexec_kernel_verify_pe_sig(const char *kernel, unsigned long kernel_len);

View File

@ -28,6 +28,7 @@ struct hlist_nulls_node {
#define NULLS_MARKER(value) (1UL | (((long)value) << 1))
#define INIT_HLIST_NULLS_HEAD(ptr, nulls) \
((ptr)->first = (struct hlist_nulls_node *) NULLS_MARKER(nulls))
#define HLIST_NULLS_HEAD_INIT(nulls) {.first = (struct hlist_nulls_node *)NULLS_MARKER(nulls)}
#define hlist_nulls_entry(ptr, type, member) container_of(ptr,type,member)

View File

@ -218,7 +218,7 @@ static size_t parent(size_t i, unsigned int lsbit, size_t size)
/* Initialize a min-heap. */
static __always_inline
void __min_heap_init_inline(min_heap_char *heap, void *data, int size)
void __min_heap_init_inline(min_heap_char *heap, void *data, size_t size)
{
heap->nr = 0;
heap->size = size;
@ -254,7 +254,7 @@ bool __min_heap_full_inline(min_heap_char *heap)
/* Sift the element at pos down the heap. */
static __always_inline
void __min_heap_sift_down_inline(min_heap_char *heap, int pos, size_t elem_size,
void __min_heap_sift_down_inline(min_heap_char *heap, size_t pos, size_t elem_size,
const struct min_heap_callbacks *func, void *args)
{
const unsigned long lsbit = elem_size & -elem_size;
@ -324,7 +324,7 @@ static __always_inline
void __min_heapify_all_inline(min_heap_char *heap, size_t elem_size,
const struct min_heap_callbacks *func, void *args)
{
int i;
ssize_t i;
for (i = heap->nr / 2 - 1; i >= 0; i--)
__min_heap_sift_down_inline(heap, i, elem_size, func, args);
@ -379,7 +379,7 @@ bool __min_heap_push_inline(min_heap_char *heap, const void *element, size_t ele
const struct min_heap_callbacks *func, void *args)
{
void *data = heap->data;
int pos;
size_t pos;
if (WARN_ONCE(heap->nr >= heap->size, "Pushing on a full heap"))
return false;
@ -428,10 +428,10 @@ bool __min_heap_del_inline(min_heap_char *heap, size_t elem_size, size_t idx,
__min_heap_del_inline(container_of(&(_heap)->nr, min_heap_char, nr), \
__minheap_obj_size(_heap), _idx, _func, _args)
void __min_heap_init(min_heap_char *heap, void *data, int size);
void __min_heap_init(min_heap_char *heap, void *data, size_t size);
void *__min_heap_peek(struct min_heap_char *heap);
bool __min_heap_full(min_heap_char *heap);
void __min_heap_sift_down(min_heap_char *heap, int pos, size_t elem_size,
void __min_heap_sift_down(min_heap_char *heap, size_t pos, size_t elem_size,
const struct min_heap_callbacks *func, void *args);
void __min_heap_sift_up(min_heap_char *heap, size_t elem_size, size_t idx,
const struct min_heap_callbacks *func, void *args);

View File

@ -202,4 +202,6 @@ DEFINE_GUARD(mutex, struct mutex *, mutex_lock(_T), mutex_unlock(_T))
DEFINE_GUARD_COND(mutex, _try, mutex_trylock(_T))
DEFINE_GUARD_COND(mutex, _intr, mutex_lock_interruptible(_T) == 0)
extern unsigned long mutex_get_owner(struct mutex *lock);
#endif /* __LINUX_MUTEX_H */

View File

@ -177,16 +177,38 @@ void ctrl_alt_del(void);
extern void orderly_poweroff(bool force);
extern void orderly_reboot(void);
void __hw_protection_shutdown(const char *reason, int ms_until_forced, bool shutdown);
static inline void hw_protection_reboot(const char *reason, int ms_until_forced)
{
__hw_protection_shutdown(reason, ms_until_forced, false);
}
/**
* enum hw_protection_action - Hardware protection action
*
* @HWPROT_ACT_DEFAULT:
* The default action should be taken. This is HWPROT_ACT_SHUTDOWN
* by default, but can be overridden.
* @HWPROT_ACT_SHUTDOWN:
* The system should be shut down (powered off) for HW protection.
* @HWPROT_ACT_REBOOT:
* The system should be rebooted for HW protection.
*/
enum hw_protection_action { HWPROT_ACT_DEFAULT, HWPROT_ACT_SHUTDOWN, HWPROT_ACT_REBOOT };
static inline void hw_protection_shutdown(const char *reason, int ms_until_forced)
void __hw_protection_trigger(const char *reason, int ms_until_forced,
enum hw_protection_action action);
/**
* hw_protection_trigger - Trigger default emergency system hardware protection action
*
* @reason: Reason of emergency shutdown or reboot to be printed.
* @ms_until_forced: Time to wait for orderly shutdown or reboot before
* triggering it. Negative value disables the forced
* shutdown or reboot.
*
* Initiate an emergency system shutdown or reboot in order to protect
* hardware from further damage. The exact action taken is controllable at
* runtime and defaults to shutdown.
*/
static inline void hw_protection_trigger(const char *reason, int ms_until_forced)
{
__hw_protection_shutdown(reason, ms_until_forced, true);
__hw_protection_trigger(reason, ms_until_forced, HWPROT_ACT_DEFAULT);
}
/*

View File

@ -1259,7 +1259,7 @@ static inline int rhashtable_replace_fast(
static inline void rhltable_walk_enter(struct rhltable *hlt,
struct rhashtable_iter *iter)
{
return rhashtable_walk_enter(&hlt->ht, iter);
rhashtable_walk_enter(&hlt->ht, iter);
}
/**
@ -1275,12 +1275,12 @@ static inline void rhltable_free_and_destroy(struct rhltable *hlt,
void *arg),
void *arg)
{
return rhashtable_free_and_destroy(&hlt->ht, free_fn, arg);
rhashtable_free_and_destroy(&hlt->ht, free_fn, arg);
}
static inline void rhltable_destroy(struct rhltable *hlt)
{
return rhltable_free_and_destroy(hlt, NULL, NULL);
rhltable_free_and_destroy(hlt, NULL, NULL);
}
#endif /* _LINUX_RHASHTABLE_H */

View File

@ -1239,6 +1239,10 @@ struct task_struct {
struct mutex_waiter *blocked_on;
#endif
#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
struct mutex *blocker_mutex;
#endif
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
int non_block_count;
#endif

View File

@ -92,6 +92,7 @@ typedef unsigned char unchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned long long ullong;
#ifndef __BIT_TYPES_DEFINED__
#define __BIT_TYPES_DEFINED__

View File

@ -5,8 +5,10 @@
#include <linux/kref.h>
#include <linux/nsproxy.h>
#include <linux/ns_common.h>
#include <linux/rculist_nulls.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
#include <linux/rcuref.h>
#include <linux/rwsem.h>
#include <linux/sysctl.h>
#include <linux/err.h>
@ -115,10 +117,11 @@ struct user_namespace {
} __randomize_layout;
struct ucounts {
struct hlist_node node;
struct hlist_nulls_node node;
struct user_namespace *ns;
kuid_t uid;
atomic_t count;
struct rcu_head rcu;
rcuref_t count;
atomic_long_t ucount[UCOUNT_COUNTS];
atomic_long_t rlimit[UCOUNT_RLIMIT_COUNTS];
};
@ -131,9 +134,15 @@ void retire_userns_sysctls(struct user_namespace *ns);
struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, enum ucount_type type);
void dec_ucount(struct ucounts *ucounts, enum ucount_type type);
struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid);
struct ucounts * __must_check get_ucounts(struct ucounts *ucounts);
void put_ucounts(struct ucounts *ucounts);
static inline struct ucounts * __must_check get_ucounts(struct ucounts *ucounts)
{
if (rcuref_get(&ucounts->count))
return ucounts;
return NULL;
}
static inline long get_rlimit_value(struct ucounts *ucounts, enum rlimit_type type)
{
return atomic_long_read(&ucounts->rlimit[type]);

View File

@ -275,6 +275,7 @@ struct vfs_ns_cap_data {
/* Allow setting encryption key on loopback filesystem */
/* Allow setting zone reclaim policy */
/* Allow everything under CAP_BPF and CAP_PERFMON for backward compatibility */
/* Allow setting hardware protection emergency action */
#define CAP_SYS_ADMIN 21

View File

@ -375,11 +375,10 @@ static int __init reserve_crashkernel_low(unsigned long long low_size)
return 0;
}
void __init reserve_crashkernel_generic(char *cmdline,
unsigned long long crash_size,
unsigned long long crash_base,
unsigned long long crash_low_size,
bool high)
void __init reserve_crashkernel_generic(unsigned long long crash_size,
unsigned long long crash_base,
unsigned long long crash_low_size,
bool high)
{
unsigned long long search_end = CRASH_ADDR_LOW_MAX, search_base = 0;
bool fixed_base = false;

View File

@ -1582,6 +1582,17 @@ struct mm_struct *get_task_mm(struct task_struct *task)
}
EXPORT_SYMBOL_GPL(get_task_mm);
static bool may_access_mm(struct mm_struct *mm, struct task_struct *task, unsigned int mode)
{
if (mm == current->mm)
return true;
if (ptrace_may_access(task, mode))
return true;
if ((mode & PTRACE_MODE_READ) && perfmon_capable())
return true;
return false;
}
struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
{
struct mm_struct *mm;
@ -1594,7 +1605,7 @@ struct mm_struct *mm_access(struct task_struct *task, unsigned int mode)
mm = get_task_mm(task);
if (!mm) {
mm = ERR_PTR(-ESRCH);
} else if (mm != current->mm && !ptrace_may_access(task, mode)) {
} else if (!may_access_mm(mm, task, mode)) {
mmput(mm);
mm = ERR_PTR(-EACCES);
}

View File

@ -93,6 +93,43 @@ static struct notifier_block panic_block = {
.notifier_call = hung_task_panic,
};
#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
static void debug_show_blocker(struct task_struct *task)
{
struct task_struct *g, *t;
unsigned long owner;
struct mutex *lock;
RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "No rcu lock held");
lock = READ_ONCE(task->blocker_mutex);
if (!lock)
return;
owner = mutex_get_owner(lock);
if (unlikely(!owner)) {
pr_err("INFO: task %s:%d is blocked on a mutex, but the owner is not found.\n",
task->comm, task->pid);
return;
}
/* Ensure the owner information is correct. */
for_each_process_thread(g, t) {
if ((unsigned long)t == owner) {
pr_err("INFO: task %s:%d is blocked on a mutex likely owned by task %s:%d.\n",
task->comm, task->pid, t->comm, t->pid);
sched_show_task(t);
return;
}
}
}
#else
static inline void debug_show_blocker(struct task_struct *task)
{
}
#endif
static void check_hung_task(struct task_struct *t, unsigned long timeout)
{
unsigned long switch_count = t->nvcsw + t->nivcsw;
@ -152,6 +189,7 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout)
pr_err("\"echo 0 > /proc/sys/kernel/hung_task_timeout_secs\""
" disables this message.\n");
sched_show_task(t);
debug_show_blocker(t);
hung_task_show_lock = true;
if (sysctl_hung_task_all_cpu_backtrace)

View File

@ -210,6 +210,16 @@ int sanity_check_segment_list(struct kimage *image)
}
#endif
/*
* The destination addresses are searched from system RAM rather than
* being allocated from the buddy allocator, so they are not guaranteed
* to be accepted by the current kernel. Accept the destination
* addresses before kexec swaps their content with the segments' source
* pages to avoid accessing memory before it is accepted.
*/
for (i = 0; i < nr_segments; i++)
accept_memory(image->segment[i].mem, image->segment[i].memsz);
return 0;
}

View File

@ -390,7 +390,7 @@ int kexec_elf_load(struct kimage *image, struct elfhdr *ehdr,
struct kexec_buf *kbuf,
unsigned long *lowest_load_addr)
{
unsigned long lowest_addr = UINT_MAX;
unsigned long lowest_addr = ULONG_MAX;
int ret;
size_t i;

View File

@ -464,6 +464,12 @@ static int locate_mem_hole_top_down(unsigned long start, unsigned long end,
continue;
}
/* Make sure this does not conflict with exclude range */
if (arch_check_excluded_range(image, temp_start, temp_end)) {
temp_start = temp_start - PAGE_SIZE;
continue;
}
/* We found a suitable memory range */
break;
} while (1);
@ -498,6 +504,12 @@ static int locate_mem_hole_bottom_up(unsigned long start, unsigned long end,
continue;
}
/* Make sure this does not conflict with exclude range */
if (arch_check_excluded_range(image, temp_start, temp_end)) {
temp_start = temp_start + PAGE_SIZE;
continue;
}
/* We found a suitable memory range */
break;
} while (1);

View File

@ -72,6 +72,14 @@ static inline unsigned long __owner_flags(unsigned long owner)
return owner & MUTEX_FLAGS;
}
/* Do not use the return value as a pointer directly. */
unsigned long mutex_get_owner(struct mutex *lock)
{
unsigned long owner = atomic_long_read(&lock->owner);
return (unsigned long)__owner_task(owner);
}
/*
* Returns: __mutex_owner(lock) on failure or NULL on success.
*/
@ -182,6 +190,9 @@ static void
__mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter,
struct list_head *list)
{
#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
WRITE_ONCE(current->blocker_mutex, lock);
#endif
debug_mutex_add_waiter(lock, waiter, current);
list_add_tail(&waiter->list, list);
@ -197,6 +208,9 @@ __mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter)
__mutex_clear_flag(lock, MUTEX_FLAGS);
debug_mutex_remove_waiter(lock, waiter, current);
#ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER
WRITE_ONCE(current->blocker_mutex, NULL);
#endif
}
/*

View File

@ -36,6 +36,8 @@ enum reboot_mode reboot_mode DEFAULT_REBOOT_MODE;
EXPORT_SYMBOL_GPL(reboot_mode);
enum reboot_mode panic_reboot_mode = REBOOT_UNDEFINED;
static enum hw_protection_action hw_protection_action = HWPROT_ACT_SHUTDOWN;
/*
* This variable is used privately to keep track of whether or not
* reboot_type is still set to its default value (i.e., reboot= hasn't
@ -229,6 +231,9 @@ EXPORT_SYMBOL(unregister_restart_handler);
/**
* do_kernel_restart - Execute kernel restart handler call chain
*
* @cmd: pointer to buffer containing command to execute for restart
* or %NULL
*
* Calls functions registered with register_restart_handler.
*
* Expected to be called from machine_restart as last step of the restart
@ -933,61 +938,86 @@ void orderly_reboot(void)
}
EXPORT_SYMBOL_GPL(orderly_reboot);
static const char *hw_protection_action_str(enum hw_protection_action action)
{
switch (action) {
case HWPROT_ACT_SHUTDOWN:
return "shutdown";
case HWPROT_ACT_REBOOT:
return "reboot";
default:
return "undefined";
}
}
static enum hw_protection_action hw_failure_emergency_action;
/**
* hw_failure_emergency_poweroff_func - emergency poweroff work after a known delay
* @work: work_struct associated with the emergency poweroff function
* hw_failure_emergency_action_func - emergency action work after a known delay
* @work: work_struct associated with the emergency action function
*
* This function is called in very critical situations to force
* a kernel poweroff after a configurable timeout value.
* a kernel poweroff or reboot after a configurable timeout value.
*/
static void hw_failure_emergency_poweroff_func(struct work_struct *work)
static void hw_failure_emergency_action_func(struct work_struct *work)
{
const char *action_str = hw_protection_action_str(hw_failure_emergency_action);
pr_emerg("Hardware protection timed-out. Trying forced %s\n",
action_str);
/*
* We have reached here after the emergency shutdown waiting period has
* expired. This means orderly_poweroff has not been able to shut off
* the system for some reason.
* We have reached here after the emergency action waiting period has
* expired. This means orderly_poweroff/reboot has not been able to
* shut off the system for some reason.
*
* Try to shut down the system immediately using kernel_power_off
* if populated
* Try to shut off the system immediately if possible
*/
pr_emerg("Hardware protection timed-out. Trying forced poweroff\n");
kernel_power_off();
if (hw_failure_emergency_action == HWPROT_ACT_REBOOT)
kernel_restart(NULL);
else
kernel_power_off();
/*
* Worst of the worst case trigger emergency restart
*/
pr_emerg("Hardware protection shutdown failed. Trying emergency restart\n");
pr_emerg("Hardware protection %s failed. Trying emergency restart\n",
action_str);
emergency_restart();
}
static DECLARE_DELAYED_WORK(hw_failure_emergency_poweroff_work,
hw_failure_emergency_poweroff_func);
static DECLARE_DELAYED_WORK(hw_failure_emergency_action_work,
hw_failure_emergency_action_func);
/**
* hw_failure_emergency_poweroff - Trigger an emergency system poweroff
* hw_failure_emergency_schedule - Schedule an emergency system shutdown or reboot
*
* @action: The hardware protection action to be taken
* @action_delay_ms: Time in milliseconds to elapse before triggering action
*
* This may be called from any critical situation to trigger a system shutdown
* after a given period of time. If time is negative this is not scheduled.
* or reboot after a given period of time.
* If time is negative this is not scheduled.
*/
static void hw_failure_emergency_poweroff(int poweroff_delay_ms)
static void hw_failure_emergency_schedule(enum hw_protection_action action,
int action_delay_ms)
{
if (poweroff_delay_ms <= 0)
if (action_delay_ms <= 0)
return;
schedule_delayed_work(&hw_failure_emergency_poweroff_work,
msecs_to_jiffies(poweroff_delay_ms));
hw_failure_emergency_action = action;
schedule_delayed_work(&hw_failure_emergency_action_work,
msecs_to_jiffies(action_delay_ms));
}
/**
* __hw_protection_shutdown - Trigger an emergency system shutdown or reboot
* __hw_protection_trigger - Trigger an emergency system shutdown or reboot
*
* @reason: Reason of emergency shutdown or reboot to be printed.
* @ms_until_forced: Time to wait for orderly shutdown or reboot before
* triggering it. Negative value disables the forced
* shutdown or reboot.
* @shutdown: If true, indicates that a shutdown will happen
* after the critical tempeature is reached.
* If false, indicates that a reboot will happen
* after the critical tempeature is reached.
* @action: The hardware protection action to be taken.
*
* Initiate an emergency system shutdown or reboot in order to protect
* hardware from further damage. Usage examples include a thermal protection.
@ -995,11 +1025,16 @@ static void hw_failure_emergency_poweroff(int poweroff_delay_ms)
* pending even if the previous request has given a large timeout for forced
* shutdown/reboot.
*/
void __hw_protection_shutdown(const char *reason, int ms_until_forced, bool shutdown)
void __hw_protection_trigger(const char *reason, int ms_until_forced,
enum hw_protection_action action)
{
static atomic_t allow_proceed = ATOMIC_INIT(1);
pr_emerg("HARDWARE PROTECTION shutdown (%s)\n", reason);
if (action == HWPROT_ACT_DEFAULT)
action = hw_protection_action;
pr_emerg("HARDWARE PROTECTION %s (%s)\n",
hw_protection_action_str(action), reason);
/* Shutdown should be initiated only once. */
if (!atomic_dec_and_test(&allow_proceed))
@ -1009,13 +1044,55 @@ void __hw_protection_shutdown(const char *reason, int ms_until_forced, bool shut
* Queue a backup emergency shutdown in the event of
* orderly_poweroff failure
*/
hw_failure_emergency_poweroff(ms_until_forced);
if (shutdown)
orderly_poweroff(true);
else
hw_failure_emergency_schedule(action, ms_until_forced);
if (action == HWPROT_ACT_REBOOT)
orderly_reboot();
else
orderly_poweroff(true);
}
EXPORT_SYMBOL_GPL(__hw_protection_shutdown);
EXPORT_SYMBOL_GPL(__hw_protection_trigger);
static bool hw_protection_action_parse(const char *str,
enum hw_protection_action *action)
{
if (sysfs_streq(str, "shutdown"))
*action = HWPROT_ACT_SHUTDOWN;
else if (sysfs_streq(str, "reboot"))
*action = HWPROT_ACT_REBOOT;
else
return false;
return true;
}
static int __init hw_protection_setup(char *str)
{
hw_protection_action_parse(str, &hw_protection_action);
return 1;
}
__setup("hw_protection=", hw_protection_setup);
#ifdef CONFIG_SYSFS
static ssize_t hw_protection_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sysfs_emit(buf, "%s\n",
hw_protection_action_str(hw_protection_action));
}
static ssize_t hw_protection_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf,
size_t count)
{
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (!hw_protection_action_parse(buf, &hw_protection_action))
return -EINVAL;
return count;
}
static struct kobj_attribute hw_protection_attr = __ATTR_RW(hw_protection);
#endif
static int __init reboot_setup(char *str)
{
@ -1276,6 +1353,7 @@ static struct kobj_attribute reboot_cpu_attr = __ATTR_RW(cpu);
#endif
static struct attribute *reboot_attrs[] = {
&hw_protection_attr.attr,
&reboot_mode_attr.attr,
#ifdef CONFIG_X86
&reboot_force_attr.attr,

View File

@ -351,10 +351,9 @@ static struct dentry *relay_create_buf_file(struct rchan *chan,
struct dentry *dentry;
char *tmpname;
tmpname = kzalloc(NAME_MAX + 1, GFP_KERNEL);
tmpname = kasprintf(GFP_KERNEL, "%s%d", chan->base_filename, cpu);
if (!tmpname)
return NULL;
snprintf(tmpname, NAME_MAX, "%s%d", chan->base_filename, cpu);
/* Create file in fs */
dentry = chan->cb->create_buf_file(tmpname, chan->parent,

View File

@ -561,8 +561,7 @@ static int __region_intersects(struct resource *parent, resource_size_t start,
struct resource res, o;
bool covered;
res.start = start;
res.end = start + size - 1;
res = DEFINE_RES(start, size, 0);
for (p = parent->child; p ; p = p->sibling) {
if (!resource_intersection(p, &res, &o))
@ -1714,18 +1713,13 @@ static int __init reserve_setup(char *str)
* I/O port space; otherwise assume it's memory.
*/
if (io_start < 0x10000) {
res->flags = IORESOURCE_IO;
*res = DEFINE_RES_IO_NAMED(io_start, io_num, "reserved");
parent = &ioport_resource;
} else {
res->flags = IORESOURCE_MEM;
*res = DEFINE_RES_MEM_NAMED(io_start, io_num, "reserved");
parent = &iomem_resource;
}
res->name = "reserved";
res->start = io_start;
res->end = io_start + io_num - 1;
res->flags |= IORESOURCE_BUSY;
res->desc = IORES_DESC_NONE;
res->child = NULL;
if (request_resource(parent, res) == 0)
reserved = x+1;
}
@ -1975,11 +1969,7 @@ get_free_mem_region(struct device *dev, struct resource *base,
*/
revoke_iomem(res);
} else {
res->start = addr;
res->end = addr + size - 1;
res->name = name;
res->desc = desc;
res->flags = IORESOURCE_MEM;
*res = DEFINE_RES_NAMED_DESC(addr, size, name, IORESOURCE_MEM, desc);
/*
* Only succeed if the resource hosts an exclusive

View File

@ -176,9 +176,10 @@ static bool recalc_sigpending_tsk(struct task_struct *t)
void recalc_sigpending(void)
{
if (!recalc_sigpending_tsk(current) && !freezing(current))
clear_thread_flag(TIF_SIGPENDING);
if (!recalc_sigpending_tsk(current) && !freezing(current)) {
if (unlikely(test_thread_flag(TIF_SIGPENDING)))
clear_thread_flag(TIF_SIGPENDING);
}
}
EXPORT_SYMBOL(recalc_sigpending);

View File

@ -11,11 +11,14 @@
struct ucounts init_ucounts = {
.ns = &init_user_ns,
.uid = GLOBAL_ROOT_UID,
.count = ATOMIC_INIT(1),
.count = RCUREF_INIT(1),
};
#define UCOUNTS_HASHTABLE_BITS 10
static struct hlist_head ucounts_hashtable[(1 << UCOUNTS_HASHTABLE_BITS)];
#define UCOUNTS_HASHTABLE_ENTRIES (1 << UCOUNTS_HASHTABLE_BITS)
static struct hlist_nulls_head ucounts_hashtable[UCOUNTS_HASHTABLE_ENTRIES] = {
[0 ... UCOUNTS_HASHTABLE_ENTRIES - 1] = HLIST_NULLS_HEAD_INIT(0)
};
static DEFINE_SPINLOCK(ucounts_lock);
#define ucounts_hashfn(ns, uid) \
@ -24,7 +27,6 @@ static DEFINE_SPINLOCK(ucounts_lock);
#define ucounts_hashentry(ns, uid) \
(ucounts_hashtable + ucounts_hashfn(ns, uid))
#ifdef CONFIG_SYSCTL
static struct ctl_table_set *
set_lookup(struct ctl_table_root *root)
@ -127,88 +129,73 @@ void retire_userns_sysctls(struct user_namespace *ns)
#endif
}
static struct ucounts *find_ucounts(struct user_namespace *ns, kuid_t uid, struct hlist_head *hashent)
static struct ucounts *find_ucounts(struct user_namespace *ns, kuid_t uid,
struct hlist_nulls_head *hashent)
{
struct ucounts *ucounts;
struct hlist_nulls_node *pos;
hlist_for_each_entry(ucounts, hashent, node) {
if (uid_eq(ucounts->uid, uid) && (ucounts->ns == ns))
return ucounts;
guard(rcu)();
hlist_nulls_for_each_entry_rcu(ucounts, pos, hashent, node) {
if (uid_eq(ucounts->uid, uid) && (ucounts->ns == ns)) {
if (rcuref_get(&ucounts->count))
return ucounts;
}
}
return NULL;
}
static void hlist_add_ucounts(struct ucounts *ucounts)
{
struct hlist_head *hashent = ucounts_hashentry(ucounts->ns, ucounts->uid);
struct hlist_nulls_head *hashent = ucounts_hashentry(ucounts->ns, ucounts->uid);
spin_lock_irq(&ucounts_lock);
hlist_add_head(&ucounts->node, hashent);
hlist_nulls_add_head_rcu(&ucounts->node, hashent);
spin_unlock_irq(&ucounts_lock);
}
static inline bool get_ucounts_or_wrap(struct ucounts *ucounts)
{
/* Returns true on a successful get, false if the count wraps. */
return !atomic_add_negative(1, &ucounts->count);
}
struct ucounts *get_ucounts(struct ucounts *ucounts)
{
if (!get_ucounts_or_wrap(ucounts)) {
put_ucounts(ucounts);
ucounts = NULL;
}
return ucounts;
}
struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid)
{
struct hlist_head *hashent = ucounts_hashentry(ns, uid);
bool wrapped;
struct ucounts *ucounts, *new = NULL;
struct hlist_nulls_head *hashent = ucounts_hashentry(ns, uid);
struct ucounts *ucounts, *new;
ucounts = find_ucounts(ns, uid, hashent);
if (ucounts)
return ucounts;
new = kzalloc(sizeof(*new), GFP_KERNEL);
if (!new)
return NULL;
new->ns = ns;
new->uid = uid;
rcuref_init(&new->count, 1);
spin_lock_irq(&ucounts_lock);
ucounts = find_ucounts(ns, uid, hashent);
if (!ucounts) {
if (ucounts) {
spin_unlock_irq(&ucounts_lock);
new = kzalloc(sizeof(*new), GFP_KERNEL);
if (!new)
return NULL;
new->ns = ns;
new->uid = uid;
atomic_set(&new->count, 1);
spin_lock_irq(&ucounts_lock);
ucounts = find_ucounts(ns, uid, hashent);
if (!ucounts) {
hlist_add_head(&new->node, hashent);
get_user_ns(new->ns);
spin_unlock_irq(&ucounts_lock);
return new;
}
kfree(new);
return ucounts;
}
wrapped = !get_ucounts_or_wrap(ucounts);
hlist_nulls_add_head_rcu(&new->node, hashent);
get_user_ns(new->ns);
spin_unlock_irq(&ucounts_lock);
kfree(new);
if (wrapped) {
put_ucounts(ucounts);
return NULL;
}
return ucounts;
return new;
}
void put_ucounts(struct ucounts *ucounts)
{
unsigned long flags;
if (atomic_dec_and_lock_irqsave(&ucounts->count, &ucounts_lock, flags)) {
hlist_del_init(&ucounts->node);
if (rcuref_put(&ucounts->count)) {
spin_lock_irqsave(&ucounts_lock, flags);
hlist_nulls_del_rcu(&ucounts->node);
spin_unlock_irqrestore(&ucounts_lock, flags);
put_user_ns(ucounts->ns);
kfree(ucounts);
kfree_rcu(ucounts, rcu);
}
}

View File

@ -269,12 +269,10 @@ void __init hardlockup_config_perf_event(const char *str)
} else {
unsigned int len = comma - str;
if (len >= sizeof(buf))
if (len > sizeof(buf))
return;
if (strscpy(buf, str, sizeof(buf)) < 0)
return;
buf[len] = 0;
strscpy(buf, str, len);
if (kstrtoull(buf, 16, &config))
return;
}

View File

@ -1280,6 +1280,17 @@ config BOOTPARAM_HUNG_TASK_PANIC
Say N if unsure.
config DETECT_HUNG_TASK_BLOCKER
bool "Dump Hung Tasks Blocker"
depends on DETECT_HUNG_TASK
depends on !PREEMPT_RT
default y
help
Say Y here to show the blocker task's stacktrace who acquires
the mutex lock which "hung tasks" are waiting.
This will add overhead a bit but shows suspicious tasks and
call trace if it comes from waiting a mutex.
config WQ_WATCHDOG
bool "Detect Workqueue Stalls"
depends on DEBUG_KERNEL

View File

@ -20,9 +20,15 @@ EXPORT_SYMBOL_GPL(interval_tree_iter_next);
/*
* Roll nodes[1] into nodes[0] by advancing nodes[1] to the end of a contiguous
* span of nodes. This makes nodes[0]->last the end of that contiguous used span
* indexes that started at the original nodes[1]->start. nodes[1] is now the
* first node starting the next used span. A hole span is between nodes[0]->last
* and nodes[1]->start. nodes[1] must be !NULL.
* of indexes that started at the original nodes[1]->start.
*
* If there is an interior hole, nodes[1] is now the first node starting the
* next used span. A hole span is between nodes[0]->last and nodes[1]->start.
*
* If there is a tailing hole, nodes[1] is now NULL. A hole span is between
* nodes[0]->last and last_index.
*
* If the contiguous used range span to last_index, nodes[1] is set to NULL.
*/
static void
interval_tree_span_iter_next_gap(struct interval_tree_span_iter *state)

View File

@ -5,6 +5,8 @@
#include <linux/prandom.h>
#include <linux/slab.h>
#include <asm/timex.h>
#include <linux/bitmap.h>
#include <linux/maple_tree.h>
#define __param(type, name, init, msg) \
static type name = init; \
@ -19,6 +21,7 @@ __param(int, search_loops, 1000, "Number of iterations searching the tree");
__param(bool, search_all, false, "Searches will iterate all nodes in the tree");
__param(uint, max_endpoint, ~0, "Largest value for the interval's endpoint");
__param(ullong, seed, 3141592653589793238ULL, "Random seed");
static struct rb_root_cached root = RB_ROOT_CACHED;
static struct interval_tree_node *nodes = NULL;
@ -59,26 +62,13 @@ static void init(void)
queries[i] = (prandom_u32_state(&rnd) >> 4) % max_endpoint;
}
static int interval_tree_test_init(void)
static int basic_check(void)
{
int i, j;
unsigned long results;
cycles_t time1, time2, time;
nodes = kmalloc_array(nnodes, sizeof(struct interval_tree_node),
GFP_KERNEL);
if (!nodes)
return -ENOMEM;
queries = kmalloc_array(nsearches, sizeof(int), GFP_KERNEL);
if (!queries) {
kfree(nodes);
return -ENOMEM;
}
printk(KERN_ALERT "interval tree insert/remove");
prandom_seed_state(&rnd, 3141592653589793238ULL);
init();
time1 = get_cycles();
@ -96,8 +86,19 @@ static int interval_tree_test_init(void)
time = div_u64(time, perf_loops);
printk(" -> %llu cycles\n", (unsigned long long)time);
return 0;
}
static int search_check(void)
{
int i, j;
unsigned long results;
cycles_t time1, time2, time;
printk(KERN_ALERT "interval tree search");
init();
for (j = 0; j < nnodes; j++)
interval_tree_insert(nodes + j, &root);
@ -120,6 +121,214 @@ static int interval_tree_test_init(void)
printk(" -> %llu cycles (%lu results)\n",
(unsigned long long)time, results);
for (j = 0; j < nnodes; j++)
interval_tree_remove(nodes + j, &root);
return 0;
}
static int intersection_range_check(void)
{
int i, j, k;
unsigned long start, last;
struct interval_tree_node *node;
unsigned long *intxn1;
unsigned long *intxn2;
printk(KERN_ALERT "interval tree iteration\n");
intxn1 = bitmap_alloc(nnodes, GFP_KERNEL);
if (!intxn1) {
WARN_ON_ONCE("Failed to allocate intxn1\n");
return -ENOMEM;
}
intxn2 = bitmap_alloc(nnodes, GFP_KERNEL);
if (!intxn2) {
WARN_ON_ONCE("Failed to allocate intxn2\n");
bitmap_free(intxn1);
return -ENOMEM;
}
for (i = 0; i < search_loops; i++) {
/* Initialize interval tree for each round */
init();
for (j = 0; j < nnodes; j++)
interval_tree_insert(nodes + j, &root);
/* Let's try nsearches different ranges */
for (k = 0; k < nsearches; k++) {
/* Try whole range once */
if (!k) {
start = 0UL;
last = ULONG_MAX;
} else {
last = (prandom_u32_state(&rnd) >> 4) % max_endpoint;
start = (prandom_u32_state(&rnd) >> 4) % last;
}
/* Walk nodes to mark intersection nodes */
bitmap_zero(intxn1, nnodes);
for (j = 0; j < nnodes; j++) {
node = nodes + j;
if (start <= node->last && last >= node->start)
bitmap_set(intxn1, j, 1);
}
/* Iterate tree to clear intersection nodes */
bitmap_zero(intxn2, nnodes);
for (node = interval_tree_iter_first(&root, start, last); node;
node = interval_tree_iter_next(node, start, last))
bitmap_set(intxn2, node - nodes, 1);
WARN_ON_ONCE(!bitmap_equal(intxn1, intxn2, nnodes));
}
for (j = 0; j < nnodes; j++)
interval_tree_remove(nodes + j, &root);
}
bitmap_free(intxn1);
bitmap_free(intxn2);
return 0;
}
#ifdef CONFIG_INTERVAL_TREE_SPAN_ITER
/*
* Helper function to get span of current position from maple tree point of
* view.
*/
static void mas_cur_span(struct ma_state *mas, struct interval_tree_span_iter *state)
{
unsigned long cur_start;
unsigned long cur_last;
int is_hole;
if (mas->status == ma_overflow)
return;
/* walk to current position */
state->is_hole = mas_walk(mas) ? 0 : 1;
cur_start = mas->index < state->first_index ?
state->first_index : mas->index;
/* whether we have followers */
do {
cur_last = mas->last > state->last_index ?
state->last_index : mas->last;
is_hole = mas_next_range(mas, state->last_index) ? 0 : 1;
} while (mas->status != ma_overflow && is_hole == state->is_hole);
if (state->is_hole) {
state->start_hole = cur_start;
state->last_hole = cur_last;
} else {
state->start_used = cur_start;
state->last_used = cur_last;
}
/* advance position for next round */
if (mas->status != ma_overflow)
mas_set(mas, cur_last + 1);
}
static int span_iteration_check(void)
{
int i, j, k;
unsigned long start, last;
struct interval_tree_span_iter span, mas_span;
DEFINE_MTREE(tree);
MA_STATE(mas, &tree, 0, 0);
printk(KERN_ALERT "interval tree span iteration\n");
for (i = 0; i < search_loops; i++) {
/* Initialize interval tree for each round */
init();
for (j = 0; j < nnodes; j++)
interval_tree_insert(nodes + j, &root);
/* Put all the range into maple tree */
mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE);
mt_set_in_rcu(&tree);
for (j = 0; j < nnodes; j++)
WARN_ON_ONCE(mtree_store_range(&tree, nodes[j].start,
nodes[j].last, nodes + j, GFP_KERNEL));
/* Let's try nsearches different ranges */
for (k = 0; k < nsearches; k++) {
/* Try whole range once */
if (!k) {
start = 0UL;
last = ULONG_MAX;
} else {
last = (prandom_u32_state(&rnd) >> 4) % max_endpoint;
start = (prandom_u32_state(&rnd) >> 4) % last;
}
mas_span.first_index = start;
mas_span.last_index = last;
mas_span.is_hole = -1;
mas_set(&mas, start);
interval_tree_for_each_span(&span, &root, start, last) {
mas_cur_span(&mas, &mas_span);
WARN_ON_ONCE(span.is_hole != mas_span.is_hole);
if (span.is_hole) {
WARN_ON_ONCE(span.start_hole != mas_span.start_hole);
WARN_ON_ONCE(span.last_hole != mas_span.last_hole);
} else {
WARN_ON_ONCE(span.start_used != mas_span.start_used);
WARN_ON_ONCE(span.last_used != mas_span.last_used);
}
}
}
WARN_ON_ONCE(mas.status != ma_overflow);
/* Cleanup maple tree for each round */
mtree_destroy(&tree);
/* Cleanup interval tree for each round */
for (j = 0; j < nnodes; j++)
interval_tree_remove(nodes + j, &root);
}
return 0;
}
#else
static inline int span_iteration_check(void) {return 0; }
#endif
static int interval_tree_test_init(void)
{
nodes = kmalloc_array(nnodes, sizeof(struct interval_tree_node),
GFP_KERNEL);
if (!nodes)
return -ENOMEM;
queries = kmalloc_array(nsearches, sizeof(int), GFP_KERNEL);
if (!queries) {
kfree(nodes);
return -ENOMEM;
}
prandom_seed_state(&rnd, seed);
basic_check();
search_check();
intersection_range_check();
span_iteration_check();
kfree(queries);
kfree(nodes);

View File

@ -2,7 +2,7 @@
#include <linux/export.h>
#include <linux/min_heap.h>
void __min_heap_init(min_heap_char *heap, void *data, int size)
void __min_heap_init(min_heap_char *heap, void *data, size_t size)
{
__min_heap_init_inline(heap, data, size);
}
@ -20,7 +20,7 @@ bool __min_heap_full(min_heap_char *heap)
}
EXPORT_SYMBOL(__min_heap_full);
void __min_heap_sift_down(min_heap_char *heap, int pos, size_t elem_size,
void __min_heap_sift_down(min_heap_char *heap, size_t pos, size_t elem_size,
const struct min_heap_callbacks *func, void *args)
{
__min_heap_sift_down_inline(heap, pos, elem_size, func, args);

View File

@ -171,12 +171,24 @@ void plist_requeue(struct plist_node *node, struct plist_head *head)
plist_del(node, head);
/*
* After plist_del(), iter is the replacement of the node. If the node
* was on prio_list, take shortcut to find node_next instead of looping.
*/
if (!list_empty(&iter->prio_list)) {
iter = list_entry(iter->prio_list.next, struct plist_node,
prio_list);
node_next = &iter->node_list;
goto queue;
}
plist_for_each_continue(iter, head) {
if (node->prio != iter->prio) {
node_next = &iter->node_list;
break;
}
}
queue:
list_add_tail(&node->node_list, node_next);
plist_check_head(head);

View File

@ -14,6 +14,7 @@
__param(int, nnodes, 100, "Number of nodes in the rb-tree");
__param(int, perf_loops, 1000, "Number of iterations modifying the rb-tree");
__param(int, check_loops, 100, "Number of iterations modifying and verifying the rb-tree");
__param(ullong, seed, 3141592653589793238ULL, "Random seed");
struct test_node {
u32 key;
@ -239,19 +240,14 @@ static void check_augmented(int nr_nodes)
}
}
static int __init rbtree_test_init(void)
static int basic_check(void)
{
int i, j;
cycles_t time1, time2, time;
struct rb_node *node;
nodes = kmalloc_array(nnodes, sizeof(*nodes), GFP_KERNEL);
if (!nodes)
return -ENOMEM;
printk(KERN_ALERT "rbtree testing");
prandom_seed_state(&rnd, 3141592653589793238ULL);
init();
time1 = get_cycles();
@ -343,6 +339,14 @@ static int __init rbtree_test_init(void)
check(0);
}
return 0;
}
static int augmented_check(void)
{
int i, j;
cycles_t time1, time2, time;
printk(KERN_ALERT "augmented rbtree testing");
init();
@ -390,6 +394,20 @@ static int __init rbtree_test_init(void)
check_augmented(0);
}
return 0;
}
static int __init rbtree_test_init(void)
{
nodes = kmalloc_array(nnodes, sizeof(*nodes), GFP_KERNEL);
if (!nodes)
return -ENOMEM;
prandom_seed_state(&rnd, seed);
basic_check();
augmented_check();
kfree(nodes);
return -EAGAIN; /* Fail will directly unload the module */

View File

@ -151,9 +151,6 @@ static const config configuration_table[10] = {
* meaning.
*/
#define EQUAL 0
/* result of memcmp for equal strings */
/* ===========================================================================
* Update a hash value with the given input byte
* IN assertion: all calls to UPDATE_HASH are made with consecutive
@ -713,8 +710,7 @@ static void check_match(
)
{
/* check that the match is indeed a match */
if (memcmp((char *)s->window + match,
(char *)s->window + start, length) != EQUAL) {
if (memcmp((char *)s->window + match, (char *)s->window + start, length)) {
fprintf(stderr, " start %u, match %u, length %d\n",
start, match, length);
do {

View File

@ -300,6 +300,15 @@ config SAMPLE_CHECK_EXEC
demonstrate how they should be used with execveat(2) +
AT_EXECVE_CHECK.
config SAMPLE_HUNG_TASK
tristate "Hung task detector test code"
depends on DETECT_HUNG_TASK && DEBUG_FS
help
Build a module which provide a simple debugfs file. If user reads
the file, it will sleep long time (256 seconds) with holding a
mutex. Thus if there are 2 or more processes read this file, it
will be detected by the hung_task watchdog.
source "samples/rust/Kconfig"
source "samples/damon/Kconfig"

View File

@ -42,3 +42,4 @@ obj-$(CONFIG_SAMPLE_FPROBE) += fprobe/
obj-$(CONFIG_SAMPLES_RUST) += rust/
obj-$(CONFIG_SAMPLE_DAMON_WSSE) += damon/
obj-$(CONFIG_SAMPLE_DAMON_PRCL) += damon/
obj-$(CONFIG_SAMPLE_HUNG_TASK) += hung_task/

View File

@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SAMPLE_HUNG_TASK) += hung_task_mutex.o

View File

@ -0,0 +1,66 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* hung_task_mutex.c - Sample code which causes hung task by mutex
*
* Usage: load this module and read `<debugfs>/hung_task/mutex`
* by 2 or more processes.
*
* This is for testing kernel hung_task error message.
* Note that this will make your system freeze and maybe
* cause panic. So do not use this except for the test.
*/
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/mutex.h>
#define HUNG_TASK_DIR "hung_task"
#define HUNG_TASK_FILE "mutex"
#define SLEEP_SECOND 256
static const char dummy_string[] = "This is a dummy string.";
static DEFINE_MUTEX(dummy_mutex);
static struct dentry *hung_task_dir;
static ssize_t read_dummy(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
/* If the second task waits on the lock, it is uninterruptible sleep. */
guard(mutex)(&dummy_mutex);
/* When the first task sleep here, it is interruptible. */
msleep_interruptible(SLEEP_SECOND * 1000);
return simple_read_from_buffer(user_buf, count, ppos,
dummy_string, sizeof(dummy_string));
}
static const struct file_operations hung_task_fops = {
.read = read_dummy,
};
static int __init hung_task_sample_init(void)
{
hung_task_dir = debugfs_create_dir(HUNG_TASK_DIR, NULL);
if (IS_ERR(hung_task_dir))
return PTR_ERR(hung_task_dir);
debugfs_create_file(HUNG_TASK_FILE, 0400, hung_task_dir,
NULL, &hung_task_fops);
return 0;
}
static void __exit hung_task_sample_exit(void)
{
debugfs_remove_recursive(hung_task_dir);
}
module_init(hung_task_sample_init);
module_exit(hung_task_sample_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Masami Hiramatsu");
MODULE_DESCRIPTION("Simple sleep under mutex file for testing hung task");

View File

@ -113,7 +113,8 @@ Options:
--max-line-length=n set the maximum line length, (default $max_line_length)
if exceeded, warn on patches
requires --strict for use with --file
--min-conf-desc-length=n set the min description length, if shorter, warn
--min-conf-desc-length=n set the minimum description length for config symbols
in lines, if shorter, warn (default $min_conf_desc_length)
--tab-size=n set the number of spaces for tab (default $tabsize)
--root=PATH PATH to the kernel tree root
--no-summary suppress the per-file summary
@ -3645,7 +3646,7 @@ sub process {
$help_length < $min_conf_desc_length) {
my $stat_real = get_stat_real($linenr, $ln - 1);
WARN("CONFIG_DESCRIPTION",
"please write a help paragraph that fully describes the config symbol\n" . "$here\n$stat_real\n");
"please write a help paragraph that fully describes the config symbol with at least $min_conf_desc_length lines\n" . "$here\n$stat_real\n");
}
}

View File

@ -20,3 +20,13 @@ virtual patch
- msecs_to_jiffies(C * MSEC_PER_SEC)
+ secs_to_jiffies(C)
@depends on patch@ expression E; @@
- msecs_to_jiffies(E * 1000)
+ secs_to_jiffies(E)
@depends on patch@ expression E; @@
- msecs_to_jiffies(E * MSEC_PER_SEC)
+ secs_to_jiffies(E)

30
scripts/extract-fwblobs Executable file
View File

@ -0,0 +1,30 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
#
# -----------------------------------------------------------------------------
# Extracts the vmlinux built-in firmware blobs - requires a non-stripped image
# -----------------------------------------------------------------------------
if [ -z "$1" ]; then
echo "Must provide a non-stripped vmlinux as argument"
exit 1
fi
read -r RD_ADDR_HEX RD_OFF_HEX <<< "$( readelf -SW "$1" |\
grep -w rodata | awk '{print "0x"$5" 0x"$6}' )"
FW_SYMS="$(readelf -sW "$1" |\
awk -n '/fw_end/ { end=$2 ; print name " 0x" start " 0x" end; } { start=$2; name=$8; }')"
while IFS= read -r entry; do
read -r FW_NAME FW_ADDR_ST_HEX FW_ADDR_END_HEX <<< "$entry"
# Notice kernel prepends _fw_ and appends _bin to the FW name
# in rodata; hence we hereby filter that out.
FW_NAME=${FW_NAME:4:-4}
FW_OFFSET="$(printf "%d" $((FW_ADDR_ST_HEX - RD_ADDR_HEX + RD_OFF_HEX)))"
FW_SIZE="$(printf "%d" $((FW_ADDR_END_HEX - FW_ADDR_ST_HEX)))"
dd if="$1" of="./${FW_NAME}" bs="${FW_SIZE}" count=1 iflag=skip_bytes skip="${FW_OFFSET}"
done <<< "${FW_SYMS}"

View File

@ -46,7 +46,7 @@ def per_cpu(var_ptr, cpu):
# !CONFIG_SMP case
offset = 0
pointer = var_ptr.cast(utils.get_long_type()) + offset
return pointer.cast(var_ptr.type).dereference()
return pointer.cast(var_ptr.type)
cpu_mask = {}
@ -149,11 +149,29 @@ Note that VAR has to be quoted as string."""
super(PerCpu, self).__init__("lx_per_cpu")
def invoke(self, var, cpu=-1):
return per_cpu(var.address, cpu)
return per_cpu(var.address, cpu).dereference()
PerCpu()
class PerCpuPtr(gdb.Function):
"""Return per-cpu pointer.
$lx_per_cpu_ptr("VAR"[, CPU]): Return the per-cpu pointer called VAR for the
given CPU number. If CPU is omitted, the CPU of the current context is used.
Note that VAR has to be quoted as string."""
def __init__(self):
super(PerCpuPtr, self).__init__("lx_per_cpu_ptr")
def invoke(self, var, cpu=-1):
return per_cpu(var, cpu)
PerCpuPtr()
def get_current_task(cpu):
task_ptr_type = task_type.get_type().pointer()

View File

@ -14,7 +14,9 @@
import gdb
import os
import re
import struct
from itertools import count
from linux import modules, utils, constants
@ -53,6 +55,29 @@ if hasattr(gdb, 'Breakpoint'):
return False
def get_vmcore_s390():
with utils.qemu_phy_mem_mode():
vmcore_info = 0x0e0c
paddr_vmcoreinfo_note = gdb.parse_and_eval("*(unsigned long long *)" +
hex(vmcore_info))
inferior = gdb.selected_inferior()
elf_note = inferior.read_memory(paddr_vmcoreinfo_note, 12)
n_namesz, n_descsz, n_type = struct.unpack(">III", elf_note)
desc_paddr = paddr_vmcoreinfo_note + len(elf_note) + n_namesz + 1
return gdb.parse_and_eval("(char *)" + hex(desc_paddr)).string()
def get_kerneloffset():
if utils.is_target_arch('s390'):
try:
vmcore_str = get_vmcore_s390()
except gdb.error as e:
gdb.write("{}\n".format(e))
return None
return utils.parse_vmcore(vmcore_str).kerneloffset
return None
class LxSymbols(gdb.Command):
"""(Re-)load symbols of Linux kernel and currently loaded modules.
@ -95,10 +120,14 @@ lx-symbols command."""
except gdb.error:
return str(module_addr)
attrs = sect_attrs['attrs']
section_name_to_address = {
attrs[n]['battr']['attr']['name'].string(): attrs[n]['address']
for n in range(int(sect_attrs['nsections']))}
section_name_to_address = {}
for i in count():
# this is a NULL terminated array
if sect_attrs['grp']['bin_attrs'][i] == 0x0:
break
attr = sect_attrs['grp']['bin_attrs'][i].dereference()
section_name_to_address[attr['attr']['name'].string()] = attr['private']
textaddr = section_name_to_address.get(".text", module_addr)
args = []
@ -155,7 +184,12 @@ lx-symbols command."""
obj.filename.endswith('vmlinux.debug')):
orig_vmlinux = obj.filename
gdb.execute("symbol-file", to_string=True)
gdb.execute("symbol-file {0}".format(orig_vmlinux))
kerneloffset = get_kerneloffset()
if kerneloffset is None:
offset_arg = ""
else:
offset_arg = " -o " + hex(kerneloffset)
gdb.execute("symbol-file {0}{1}".format(orig_vmlinux, offset_arg))
self.loaded_modules = []
module_list = modules.module_list()

View File

@ -11,6 +11,11 @@
# This work is licensed under the terms of the GNU GPL version 2.
#
import contextlib
import dataclasses
import re
import typing
import gdb
@ -216,3 +221,33 @@ def gdb_eval_or_none(expresssion):
return gdb.parse_and_eval(expresssion)
except gdb.error:
return None
@contextlib.contextmanager
def qemu_phy_mem_mode():
connection = gdb.selected_inferior().connection
orig = connection.send_packet("qqemu.PhyMemMode")
if orig not in b"01":
raise gdb.error("Unexpected qemu.PhyMemMode")
orig = orig.decode()
if connection.send_packet("Qqemu.PhyMemMode:1") != b"OK":
raise gdb.error("Failed to set qemu.PhyMemMode")
try:
yield
finally:
if connection.send_packet("Qqemu.PhyMemMode:" + orig) != b"OK":
raise gdb.error("Failed to restore qemu.PhyMemMode")
@dataclasses.dataclass
class VmCore:
kerneloffset: typing.Optional[int]
def parse_vmcore(s):
match = re.search(r"KERNELOFFSET=([0-9a-f]+)", s)
if match is None:
kerneloffset = None
else:
kerneloffset = int(match.group(1), 16)
return VmCore(kerneloffset=kerneloffset)

View File

@ -50,6 +50,7 @@ my $output_multiline = 1;
my $output_separator = ", ";
my $output_roles = 0;
my $output_rolestats = 1;
my $output_substatus = undef;
my $output_section_maxlen = 50;
my $scm = 0;
my $tree = 1;
@ -269,6 +270,7 @@ if (!GetOptions(
'separator=s' => \$output_separator,
'subsystem!' => \$subsystem,
'status!' => \$status,
'substatus!' => \$output_substatus,
'scm!' => \$scm,
'tree!' => \$tree,
'web!' => \$web,
@ -314,6 +316,10 @@ $output_multiline = 0 if ($output_separator ne ", ");
$output_rolestats = 1 if ($interactive);
$output_roles = 1 if ($output_rolestats);
if (!defined $output_substatus) {
$output_substatus = $email && $output_roles && -t STDOUT;
}
if ($sections || $letters ne "") {
$sections = 1;
$email = 0;
@ -637,6 +643,7 @@ my @web = ();
my @bug = ();
my @subsystem = ();
my @status = ();
my @substatus = ();
my %deduplicate_name_hash = ();
my %deduplicate_address_hash = ();
@ -651,6 +658,11 @@ if ($scm) {
output(@scm);
}
if ($output_substatus) {
@substatus = uniq(@substatus);
output(@substatus);
}
if ($status) {
@status = uniq(@status);
output(@status);
@ -859,6 +871,7 @@ sub get_maintainers {
@bug = ();
@subsystem = ();
@status = ();
@substatus = ();
%deduplicate_name_hash = ();
%deduplicate_address_hash = ();
if ($email_git_all_signature_types) {
@ -1071,8 +1084,9 @@ MAINTAINER field selection options:
--moderated => include moderated lists(s) if any (default: true)
--s => include subscriber only list(s) if any (default: false)
--remove-duplicates => minimize duplicate email names/addresses
--roles => show roles (status:subsystem, git-signer, list, etc...)
--roles => show roles (role:subsystem, git-signer, list, etc...)
--rolestats => show roles and statistics (commits/total_commits, %)
--substatus => show subsystem status if not Maintained (default: match --roles when output is tty)"
--file-emails => add email addresses found in -f file (default: 0 (off))
--fixes => for patches, add signatures of commits with 'Fixes: <commit>' (default: 1 (on))
--scm => print SCM tree(s) if any
@ -1284,8 +1298,9 @@ sub get_maintainer_role {
my $start = find_starting_index($index);
my $end = find_ending_index($index);
my $role = "unknown";
my $role = "maintainer";
my $subsystem = get_subsystem_name($index);
my $status = "unknown";
for ($i = $start + 1; $i < $end; $i++) {
my $tv = $typevalue[$i];
@ -1293,23 +1308,13 @@ sub get_maintainer_role {
my $ptype = $1;
my $pvalue = $2;
if ($ptype eq "S") {
$role = $pvalue;
$status = $pvalue;
}
}
}
$role = lc($role);
if ($role eq "supported") {
$role = "supporter";
} elsif ($role eq "maintained") {
$role = "maintainer";
} elsif ($role eq "odd fixes") {
$role = "odd fixer";
} elsif ($role eq "orphan") {
$role = "orphan minder";
} elsif ($role eq "obsolete") {
$role = "obsolete minder";
} elsif ($role eq "buried alive in reporters") {
$status = lc($status);
if ($status eq "buried alive in reporters") {
$role = "chief penguin";
}
@ -1335,7 +1340,9 @@ sub add_categories {
my $start = find_starting_index($index);
my $end = find_ending_index($index);
push(@subsystem, $typevalue[$start]);
my $subsystem = $typevalue[$start];
push(@subsystem, $subsystem);
my $status = "Unknown";
for ($i = $start + 1; $i < $end; $i++) {
my $tv = $typevalue[$i];
@ -1386,8 +1393,8 @@ sub add_categories {
}
} elsif ($ptype eq "R") {
if ($email_reviewer) {
my $subsystem = get_subsystem_name($i);
push_email_addresses($pvalue, "reviewer:$subsystem" . $suffix);
my $subs = get_subsystem_name($i);
push_email_addresses($pvalue, "reviewer:$subs" . $suffix);
}
} elsif ($ptype eq "T") {
push(@scm, $pvalue . $suffix);
@ -1397,9 +1404,14 @@ sub add_categories {
push(@bug, $pvalue . $suffix);
} elsif ($ptype eq "S") {
push(@status, $pvalue . $suffix);
$status = $pvalue;
}
}
}
if ($subsystem ne "THE REST" and $status ne "Maintained") {
push(@substatus, $subsystem . " status: " . $status . $suffix)
}
}
sub email_inuse {
@ -1903,6 +1915,7 @@ EOT
$done = 1;
$output_rolestats = 0;
$output_roles = 0;
$output_substatus = 0;
last;
} elsif ($nr =~ /^\d+$/ && $nr > 0 && $nr <= $count) {
$selected{$nr - 1} = !$selected{$nr - 1};

View File

@ -2461,8 +2461,7 @@ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup)
* (for avoiding loud click noises for many (OSS) apps
* that open/close frequently)
*/
schedule_delayed_work(&ac97->power_work,
msecs_to_jiffies(power_save * 1000));
schedule_delayed_work(&ac97->power_work, secs_to_jiffies(power_save));
else {
cancel_delayed_work(&ac97->power_work);
update_power_regs(ac97);

13
tools/include/asm/timex.h Normal file
View File

@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __TOOLS_LINUX_ASM_TIMEX_H
#define __TOOLS_LINUX_ASM_TIMEX_H
#include <time.h>
#define cycles_t clock_t
static inline cycles_t get_cycles(void)
{
return clock();
}
#endif // __TOOLS_LINUX_ASM_TIMEX_H

View File

@ -19,6 +19,7 @@ bool __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int bits);
bool __bitmap_equal(const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int bits);
void __bitmap_set(unsigned long *map, unsigned int start, int len);
void __bitmap_clear(unsigned long *map, unsigned int start, int len);
bool __bitmap_intersects(const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int bits);
@ -79,6 +80,11 @@ static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
__bitmap_or(dst, src1, src2, nbits);
}
static inline unsigned long *bitmap_alloc(unsigned int nbits, gfp_t flags __maybe_unused)
{
return malloc(bitmap_size(nbits));
}
/**
* bitmap_zalloc - Allocate bitmap
* @nbits: Number of bits
@ -150,6 +156,21 @@ static inline bool bitmap_intersects(const unsigned long *src1,
return __bitmap_intersects(src1, src2, nbits);
}
static inline void bitmap_set(unsigned long *map, unsigned int start, unsigned int nbits)
{
if (__builtin_constant_p(nbits) && nbits == 1)
__set_bit(start, map);
else if (small_const_nbits(start + nbits))
*map |= GENMASK(start + nbits - 1, start);
else if (__builtin_constant_p(start & BITMAP_MEM_MASK) &&
IS_ALIGNED(start, BITMAP_MEM_ALIGNMENT) &&
__builtin_constant_p(nbits & BITMAP_MEM_MASK) &&
IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT))
memset((char *)map + start / 8, 0xff, nbits / 8);
else
__bitmap_set(map, start, nbits);
}
static inline void bitmap_clear(unsigned long *map, unsigned int start,
unsigned int nbits)
{

View File

@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _TOOLS_LINUX_CONTAINER_OF_H
#define _TOOLS_LINUX_CONTAINER_OF_H
#ifndef container_of
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
#endif
#endif /* _TOOLS_LINUX_CONTAINER_OF_H */

View File

@ -11,6 +11,7 @@
#include <linux/panic.h>
#include <endian.h>
#include <byteswap.h>
#include <linux/container_of.h>
#ifndef UINT_MAX
#define UINT_MAX (~0U)
@ -25,19 +26,6 @@
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#ifndef container_of
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })
#endif
#ifndef max
#define max(x, y) ({ \
typeof(x) _max1 = (x); \

View File

@ -72,4 +72,9 @@ static inline u64 mul_u64_u64_div64(u64 a, u64 b, u64 c)
}
#endif
static inline u64 div_u64(u64 dividend, u32 divisor)
{
return dividend / divisor;
}
#endif /* _LINUX_MATH64_H */

View File

@ -0,0 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _TOOLS_LINUX_MODULE_PARAMS_H
#define _TOOLS_LINUX_MODULE_PARAMS_H
#define MODULE_PARM_DESC(parm, desc)
#endif // _TOOLS_LINUX_MODULE_PARAMS_H

View File

@ -0,0 +1,51 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __TOOLS_LINUX_PRANDOM_H
#define __TOOLS_LINUX_PRANDOM_H
#include <linux/types.h>
struct rnd_state {
__u32 s1, s2, s3, s4;
};
/*
* Handle minimum values for seeds
*/
static inline u32 __seed(u32 x, u32 m)
{
return (x < m) ? x + m : x;
}
/**
* prandom_seed_state - set seed for prandom_u32_state().
* @state: pointer to state structure to receive the seed.
* @seed: arbitrary 64-bit value to use as a seed.
*/
static inline void prandom_seed_state(struct rnd_state *state, u64 seed)
{
u32 i = ((seed >> 32) ^ (seed << 10) ^ seed) & 0xffffffffUL;
state->s1 = __seed(i, 2U);
state->s2 = __seed(i, 8U);
state->s3 = __seed(i, 16U);
state->s4 = __seed(i, 128U);
}
/**
* prandom_u32_state - seeded pseudo-random number generator.
* @state: pointer to state structure holding seeded state.
*
* This is used for pseudo-randomness with no outside seeding.
* For more random results, use get_random_u32().
*/
static inline u32 prandom_u32_state(struct rnd_state *state)
{
#define TAUSWORTHE(s, a, b, c, d) (((s & c) << d) ^ (((s << a) ^ s) >> b))
state->s1 = TAUSWORTHE(state->s1, 6U, 13U, 4294967294U, 18U);
state->s2 = TAUSWORTHE(state->s2, 2U, 27U, 4294967288U, 2U);
state->s3 = TAUSWORTHE(state->s3, 13U, 21U, 4294967280U, 7U);
state->s4 = TAUSWORTHE(state->s4, 3U, 12U, 4294967168U, 13U);
return (state->s1 ^ state->s2 ^ state->s3 ^ state->s4);
}
#endif // __TOOLS_LINUX_PRANDOM_H

View File

@ -12,6 +12,7 @@
void *kmalloc(size_t size, gfp_t gfp);
void kfree(void *p);
void *kmalloc_array(size_t n, size_t size, gfp_t gfp);
bool slab_is_available(void);

View File

@ -42,6 +42,8 @@ typedef __s16 s16;
typedef __u8 u8;
typedef __s8 s8;
typedef unsigned long long ullong;
#ifdef __CHECKER__
#define __bitwise __attribute__((bitwise))
#else

View File

@ -101,6 +101,26 @@ bool __bitmap_intersects(const unsigned long *bitmap1,
return false;
}
void __bitmap_set(unsigned long *map, unsigned int start, int len)
{
unsigned long *p = map + BIT_WORD(start);
const unsigned int size = start + len;
int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
while (len - bits_to_set >= 0) {
*p |= mask_to_set;
len -= bits_to_set;
bits_to_set = BITS_PER_LONG;
mask_to_set = ~0UL;
p++;
}
if (len) {
mask_to_set &= BITMAP_LAST_WORD_MASK(size);
*p |= mask_to_set;
}
}
void __bitmap_clear(unsigned long *map, unsigned int start, int len)
{
unsigned long *p = map + BIT_WORD(start);

View File

@ -36,3 +36,19 @@ void kfree(void *p)
printf("Freeing %p to malloc\n", p);
free(p);
}
void *kmalloc_array(size_t n, size_t size, gfp_t gfp)
{
void *ret;
if (!(gfp & __GFP_DIRECT_RECLAIM))
return NULL;
ret = calloc(n, size);
uatomic_inc(&kmalloc_nr_allocated);
if (kmalloc_verbose)
printf("Allocating %p from calloc\n", ret);
if (gfp & __GFP_ZERO)
memset(ret, 0, n * size);
return ret;
}

View File

@ -0,0 +1,33 @@
# SPDX-License-Identifier: GPL-2.0
.PHONY: clean
TARGETS = rbtree_test interval_tree_test
OFILES = $(SHARED_OFILES) rbtree-shim.o interval_tree-shim.o maple-shim.o
DEPS = ../../../include/linux/rbtree.h \
../../../include/linux/rbtree_types.h \
../../../include/linux/rbtree_augmented.h \
../../../include/linux/interval_tree.h \
../../../include/linux/interval_tree_generic.h \
../../../lib/rbtree.c \
../../../lib/interval_tree.c
targets: $(TARGETS)
include ../shared/shared.mk
ifeq ($(DEBUG), 1)
CFLAGS += -g
endif
$(TARGETS): $(OFILES)
rbtree-shim.o: $(DEPS)
rbtree_test.o: ../../../lib/rbtree_test.c
interval_tree-shim.o: $(DEPS)
interval_tree-shim.o: CFLAGS += -DCONFIG_INTERVAL_TREE_SPAN_ITER
interval_tree_test.o: ../../../lib/interval_tree_test.c
interval_tree_test.o: CFLAGS += -DCONFIG_INTERVAL_TREE_SPAN_ITER
clean:
$(RM) $(TARGETS) *.o radix-tree.c idr.c generated/*

View File

@ -0,0 +1,58 @@
// SPDX-License-Identifier: GPL-2.0
/*
* interval_tree.c: Userspace Interval Tree test-suite
* Copyright (c) 2025 Wei Yang <richard.weiyang@gmail.com>
*/
#include <linux/math64.h>
#include <linux/kern_levels.h>
#include "shared.h"
#include "maple-shared.h"
#include "../../../lib/interval_tree_test.c"
int usage(void)
{
fprintf(stderr, "Userland interval tree test cases\n");
fprintf(stderr, " -n: Number of nodes in the interval tree\n");
fprintf(stderr, " -p: Number of iterations modifying the tree\n");
fprintf(stderr, " -q: Number of searches to the interval tree\n");
fprintf(stderr, " -s: Number of iterations searching the tree\n");
fprintf(stderr, " -a: Searches will iterate all nodes in the tree\n");
fprintf(stderr, " -m: Largest value for the interval's endpoint\n");
fprintf(stderr, " -r: Random seed\n");
exit(-1);
}
void interval_tree_tests(void)
{
interval_tree_test_init();
interval_tree_test_exit();
}
int main(int argc, char **argv)
{
int opt;
while ((opt = getopt(argc, argv, "n:p:q:s:am:r:")) != -1) {
if (opt == 'n')
nnodes = strtoul(optarg, NULL, 0);
else if (opt == 'p')
perf_loops = strtoul(optarg, NULL, 0);
else if (opt == 'q')
nsearches = strtoul(optarg, NULL, 0);
else if (opt == 's')
search_loops = strtoul(optarg, NULL, 0);
else if (opt == 'a')
search_all = true;
else if (opt == 'm')
max_endpoint = strtoul(optarg, NULL, 0);
else if (opt == 'r')
seed = strtoul(optarg, NULL, 0);
else
usage();
}
maple_tree_init();
interval_tree_tests();
return 0;
}

View File

@ -0,0 +1,48 @@
// SPDX-License-Identifier: GPL-2.0
/*
* rbtree_test.c: Userspace Red Black Tree test-suite
* Copyright (c) 2025 Wei Yang <richard.weiyang@gmail.com>
*/
#include <linux/init.h>
#include <linux/math64.h>
#include <linux/kern_levels.h>
#include "shared.h"
#include "../../../lib/rbtree_test.c"
int usage(void)
{
fprintf(stderr, "Userland rbtree test cases\n");
fprintf(stderr, " -n: Number of nodes in the rb-tree\n");
fprintf(stderr, " -p: Number of iterations modifying the rb-tree\n");
fprintf(stderr, " -c: Number of iterations modifying and verifying the rb-tree\n");
fprintf(stderr, " -r: Random seed\n");
exit(-1);
}
void rbtree_tests(void)
{
rbtree_test_init();
rbtree_test_exit();
}
int main(int argc, char **argv)
{
int opt;
while ((opt = getopt(argc, argv, "n:p:c:r:")) != -1) {
if (opt == 'n')
nnodes = strtoul(optarg, NULL, 0);
else if (opt == 'p')
perf_loops = strtoul(optarg, NULL, 0);
else if (opt == 'c')
check_loops = strtoul(optarg, NULL, 0);
else if (opt == 'r')
seed = strtoul(optarg, NULL, 0);
else
usage();
}
rbtree_tests();
return 0;
}

View File

@ -0,0 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
void rbtree_tests(void);
void interval_tree_tests(void);

Some files were not shown because too many files have changed in this diff Show More