summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-04-16 20:11:56 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-04-16 20:11:56 -0700
commit440d6635b20037bc9ad46b20817d7b61cef0fc1b (patch)
tree1a5e8962ae974aff248dbf594ae39f237b6c637f /kernel
parent0b2f2b1fc0c61e602a6babf580b91f895b0ea80a (diff)
parent70b672833f4025341c11b22c7f83778a5cd611bc (diff)
downloadlinux-next-440d6635b20037bc9ad46b20817d7b61cef0fc1b.tar.gz
linux-next-440d6635b20037bc9ad46b20817d7b61cef0fc1b.zip
Merge tag 'mm-nonmm-stable-2026-04-15-04-20' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
Pull non-MM updates from Andrew Morton: - "pid: make sub-init creation retryable" (Oleg Nesterov) Make creation of init in a new namespace more robust by clearing away some historical cruft which is no longer needed. Also some documentation fixups - "selftests/fchmodat2: Error handling and general" (Mark Brown) Fix and a cleanup for the fchmodat2() syscall selftest - "lib: polynomial: Move to math/ and clean up" (Andy Shevchenko) - "hung_task: Provide runtime reset interface for hung task detector" (Aaron Tomlin) Give administrators the ability to zero out /proc/sys/kernel/hung_task_detect_count - "tools/getdelays: use the static UAPI headers from tools/include/uapi" (Thomas Weißschuh) Teach getdelays to use the in-kernel UAPI headers rather than the system-provided ones - "watchdog/hardlockup: Improvements to hardlockup" (Mayank Rungta) Several cleanups and fixups to the hardlockup detector code and its documentation - "lib/bch: fix undefined behavior from signed left-shifts" (Josh Law) A couple of small/theoretical fixes in the bch code - "ocfs2/dlm: fix two bugs in dlm_match_regions()" (Junrui Luo) - "cleanup the RAID5 XOR library" (Christoph Hellwig) A quite far-reaching cleanup to this code. I can't do better than to quote Christoph: "The XOR library used for the RAID5 parity is a bit of a mess right now. The main file sits in crypto/ despite not being cryptography and not using the crypto API, with the generic implementations sitting in include/asm-generic and the arch implementations sitting in an asm/ header in theory. The latter doesn't work for many cases, so architectures often build the code directly into the core kernel, or create another module for the architecture code. Change this to a single module in lib/ that also contains the architecture optimizations, similar to the library work Eric Biggers has done for the CRC and crypto libraries later. After that it changes to better calling conventions that allow for smarter architecture implementations (although none is contained here yet), and uses static_call to avoid indirection function call overhead" - "lib/list_sort: Clean up list_sort() scheduling workarounds" (Kuan-Wei Chiu) Clean up this library code by removing a hacky thing which was added for UBIFS, which UBIFS doesn't actually need - "Fix bugs in extract_iter_to_sg()" (Christian Ehrhardt) Fix a few bugs in the scatterlist code, add in-kernel tests for the now-fixed bugs and fix a leak in the test itself - "kdump: Enable LUKS-encrypted dump target support in ARM64 and PowerPC" (Coiby Xu) Enable support of the LUKS-encrypted device dump target on arm64 and powerpc - "ocfs2: consolidate extent list validation into block read callbacks" (Joseph Qi) Cleanup, simplify, and make more robust ocfs2's validation of extent list fields (Kernel test robot loves mounting corrupted fs images!) * tag 'mm-nonmm-stable-2026-04-15-04-20' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm: (127 commits) ocfs2: validate group add input before caching ocfs2: validate bg_bits during freefrag scan ocfs2: fix listxattr handling when the buffer is full doc: watchdog: fix typos etc update Sean's email address ocfs2: use get_random_u32() where appropriate ocfs2: split transactions in dio completion to avoid credit exhaustion ocfs2: remove redundant l_next_free_rec check in __ocfs2_find_path() ocfs2: validate extent block list fields during block read ocfs2: remove empty extent list check in ocfs2_dx_dir_lookup_rec() ocfs2: validate dx_root extent list fields during block read ocfs2: fix use-after-free in ocfs2_fault() when VM_FAULT_RETRY ocfs2: handle invalid dinode in ocfs2_group_extend .get_maintainer.ignore: add Askar ocfs2: validate bg_list extent bounds in discontig groups checkpatch: exclude forward declarations of const structs tools/accounting: handle truncated taskstats netlink messages taskstats: set version in TGID exit notifications ocfs2/heartbeat: fix slot mapping rollback leaks on error paths arm64,ppc64le/kdump: pass dm-crypt keys to kdump kernel ...
Diffstat (limited to 'kernel')
-rw-r--r--kernel/crash_core.c2
-rw-r--r--kernel/crash_dump_dm_crypt.c22
-rw-r--r--kernel/crash_reserve.c2
-rw-r--r--kernel/exit.c8
-rw-r--r--kernel/fork.c30
-rw-r--r--kernel/hung_task.c106
-rw-r--r--kernel/kexec_core.c1
-rw-r--r--kernel/panic.c47
-rw-r--r--kernel/pid.c18
-rw-r--r--kernel/signal.c12
-rw-r--r--kernel/taskstats.c1
-rw-r--r--kernel/vmcore_info.c2
-rw-r--r--kernel/watchdog.c148
-rw-r--r--kernel/watchdog_buddy.c9
14 files changed, 258 insertions, 150 deletions
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 2c1a3791e410..4f21fc3b108b 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -27,8 +27,6 @@
#include <asm/page.h>
#include <asm/sections.h>
-#include <crypto/sha1.h>
-
#include "kallsyms_internal.h"
#include "kexec_internal.h"
diff --git a/kernel/crash_dump_dm_crypt.c b/kernel/crash_dump_dm_crypt.c
index a20d4097744a..cb875ddb6ba6 100644
--- a/kernel/crash_dump_dm_crypt.c
+++ b/kernel/crash_dump_dm_crypt.c
@@ -6,6 +6,7 @@
#include <linux/cc_platform.h>
#include <linux/configfs.h>
#include <linux/module.h>
+#include <linux/sysfs.h>
#define KEY_NUM_MAX 128 /* maximum dm crypt keys */
#define KEY_SIZE_MAX 256 /* maximum dm crypt key size */
@@ -115,7 +116,7 @@ static int restore_dm_crypt_keys_to_thread_keyring(void)
addr = dm_crypt_keys_addr;
dm_crypt_keys_read((char *)&key_count, sizeof(key_count), &addr);
- if (key_count < 0 || key_count > KEY_NUM_MAX) {
+ if (key_count > KEY_NUM_MAX) {
kexec_dprintk("Failed to read the number of dm-crypt keys\n");
return -1;
}
@@ -139,7 +140,7 @@ static int restore_dm_crypt_keys_to_thread_keyring(void)
return 0;
}
-static int read_key_from_user_keying(struct dm_crypt_key *dm_key)
+static int read_key_from_user_keyring(struct dm_crypt_key *dm_key)
{
const struct user_key_payload *ukp;
struct key *key;
@@ -189,7 +190,7 @@ static inline struct config_key *to_config_key(struct config_item *item)
static ssize_t config_key_description_show(struct config_item *item, char *page)
{
- return sprintf(page, "%s\n", to_config_key(item)->description);
+ return sysfs_emit(page, "%s\n", to_config_key(item)->description);
}
static ssize_t config_key_description_store(struct config_item *item,
@@ -265,7 +266,7 @@ static struct config_item *config_keys_make_item(struct config_group *group,
static ssize_t config_keys_count_show(struct config_item *item, char *page)
{
- return sprintf(page, "%d\n", key_count);
+ return sysfs_emit(page, "%d\n", key_count);
}
CONFIGFS_ATTR_RO(config_keys_, count);
@@ -274,7 +275,7 @@ static bool is_dm_key_reused;
static ssize_t config_keys_reuse_show(struct config_item *item, char *page)
{
- return sprintf(page, "%d\n", is_dm_key_reused);
+ return sysfs_emit(page, "%d\n", is_dm_key_reused);
}
static ssize_t config_keys_reuse_store(struct config_item *item,
@@ -321,7 +322,7 @@ static bool restore;
static ssize_t config_keys_restore_show(struct config_item *item, char *page)
{
- return sprintf(page, "%d\n", restore);
+ return sysfs_emit(page, "%d\n", restore);
}
static ssize_t config_keys_restore_store(struct config_item *item,
@@ -387,7 +388,7 @@ static int build_keys_header(void)
strscpy(keys_header->keys[i].key_desc, key->description,
KEY_DESC_MAX_LEN);
- r = read_key_from_user_keying(&keys_header->keys[i]);
+ r = read_key_from_user_keyring(&keys_header->keys[i]);
if (r != 0) {
kexec_dprintk("Failed to read key %s\n",
keys_header->keys[i].key_desc);
@@ -414,14 +415,16 @@ int crash_load_dm_crypt_keys(struct kimage *image)
if (key_count <= 0) {
kexec_dprintk("No dm-crypt keys\n");
- return -ENOENT;
+ return 0;
}
if (!is_dm_key_reused) {
image->dm_crypt_keys_addr = 0;
r = build_keys_header();
- if (r)
+ if (r) {
+ pr_err("Failed to build dm-crypt keys header, ret=%d\n", r);
return r;
+ }
}
kbuf.buffer = keys_header;
@@ -432,6 +435,7 @@ int crash_load_dm_crypt_keys(struct kimage *image)
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
r = kexec_add_buffer(&kbuf);
if (r) {
+ pr_err("Failed to call kexec_add_buffer, ret=%d\n", r);
kvfree((void *)kbuf.buffer);
return r;
}
diff --git a/kernel/crash_reserve.c b/kernel/crash_reserve.c
index 62e60e0223cf..eee37a11380c 100644
--- a/kernel/crash_reserve.c
+++ b/kernel/crash_reserve.c
@@ -20,8 +20,6 @@
#include <asm/page.h>
#include <asm/sections.h>
-#include <crypto/sha1.h>
-
#include "kallsyms_internal.h"
#include "kexec_internal.h"
diff --git a/kernel/exit.c b/kernel/exit.c
index 31b714c3a791..25e9cb6de7e7 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -749,14 +749,12 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
tsk->exit_state = EXIT_ZOMBIE;
if (unlikely(tsk->ptrace)) {
- int sig = thread_group_leader(tsk) &&
- thread_group_empty(tsk) &&
- !ptrace_reparented(tsk) ?
- tsk->exit_signal : SIGCHLD;
+ int sig = thread_group_empty(tsk) && !ptrace_reparented(tsk)
+ ? tsk->exit_signal : SIGCHLD;
autoreap = do_notify_parent(tsk, sig);
} else if (thread_group_leader(tsk)) {
autoreap = thread_group_empty(tsk) &&
- do_notify_parent(tsk, tsk->exit_signal);
+ do_notify_parent(tsk, tsk->exit_signal);
} else {
autoreap = true;
/* untraced sub-thread */
diff --git a/kernel/fork.c b/kernel/fork.c
index fe3821160f9a..f1ad69c6dc2d 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -347,7 +347,7 @@ static int alloc_thread_stack_node(struct task_struct *tsk, int node)
stack = kasan_reset_tag(vm_area->addr);
/* Clear stale pointers from reused stack. */
- memset(stack, 0, THREAD_SIZE);
+ clear_pages(vm_area->addr, vm_area->nr_pages);
tsk->stack_vm_area = vm_area;
tsk->stack = stack;
@@ -1016,13 +1016,14 @@ free_tsk:
__cacheline_aligned_in_smp DEFINE_SPINLOCK(mmlist_lock);
-static unsigned long default_dump_filter = MMF_DUMP_FILTER_DEFAULT;
+static unsigned long coredump_filter = MMF_DUMP_FILTER_DEFAULT;
static int __init coredump_filter_setup(char *s)
{
- default_dump_filter =
- (simple_strtoul(s, NULL, 0) << MMF_DUMP_FILTER_SHIFT) &
- MMF_DUMP_FILTER_MASK;
+ if (kstrtoul(s, 0, &coredump_filter))
+ return 0;
+ coredump_filter <<= MMF_DUMP_FILTER_SHIFT;
+ coredump_filter &= MMF_DUMP_FILTER_MASK;
return 1;
}
@@ -1108,7 +1109,7 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
__mm_flags_overwrite_word(mm, mmf_init_legacy_flags(flags));
mm->def_flags = current->mm->def_flags & VM_INIT_DEF_MASK;
} else {
- __mm_flags_overwrite_word(mm, default_dump_filter);
+ __mm_flags_overwrite_word(mm, coredump_filter);
mm->def_flags = 0;
}
@@ -2435,7 +2436,11 @@ __latent_entropy struct task_struct *copy_process(
rseq_fork(p, clone_flags);
- /* Don't start children in a dying pid namespace */
+ /*
+ * If zap_pid_ns_processes() was called after alloc_pid(), the new
+ * child missed SIGKILL. If current is not in the same namespace,
+ * we can't rely on fatal_signal_pending() below.
+ */
if (unlikely(!(ns_of_pid(pid)->pid_allocated & PIDNS_ADDING))) {
retval = -ENOMEM;
goto bad_fork_core_free;
@@ -3241,11 +3246,10 @@ int ksys_unshare(unsigned long unshare_flags)
new_cred, new_fs);
if (err)
goto bad_unshare_cleanup_cred;
-
if (new_cred) {
err = set_cred_ucounts(new_cred);
if (err)
- goto bad_unshare_cleanup_cred;
+ goto bad_unshare_cleanup_nsproxy;
}
if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) {
@@ -3261,8 +3265,10 @@ int ksys_unshare(unsigned long unshare_flags)
shm_init_task(current);
}
- if (new_nsproxy)
+ if (new_nsproxy) {
switch_task_namespaces(current, new_nsproxy);
+ new_nsproxy = NULL;
+ }
task_lock(current);
@@ -3291,13 +3297,15 @@ int ksys_unshare(unsigned long unshare_flags)
perf_event_namespaces(current);
+bad_unshare_cleanup_nsproxy:
+ if (new_nsproxy)
+ put_nsproxy(new_nsproxy);
bad_unshare_cleanup_cred:
if (new_cred)
put_cred(new_cred);
bad_unshare_cleanup_fd:
if (new_fd)
put_files_struct(new_fd);
-
bad_unshare_cleanup_fs:
if (new_fs)
free_fs_struct(new_fs);
diff --git a/kernel/hung_task.c b/kernel/hung_task.c
index d2254c91450b..6fcc94ce4ca9 100644
--- a/kernel/hung_task.c
+++ b/kernel/hung_task.c
@@ -36,7 +36,7 @@ static int __read_mostly sysctl_hung_task_check_count = PID_MAX_LIMIT;
/*
* Total number of tasks detected as hung since boot:
*/
-static unsigned long __read_mostly sysctl_hung_task_detect_count;
+static atomic_long_t sysctl_hung_task_detect_count = ATOMIC_LONG_INIT(0);
/*
* Limit number of tasks checked in a batch.
@@ -223,37 +223,36 @@ static inline void debug_show_blocker(struct task_struct *task, unsigned long ti
}
#endif
-static void check_hung_task(struct task_struct *t, unsigned long timeout,
- unsigned long prev_detect_count)
+/**
+ * hung_task_info - Print diagnostic details for a hung task
+ * @t: Pointer to the detected hung task.
+ * @timeout: Timeout threshold for detecting hung tasks
+ * @this_round_count: Count of hung tasks detected in the current iteration
+ *
+ * Print structured information about the specified hung task, if warnings
+ * are enabled or if the panic batch threshold is exceeded.
+ */
+static void hung_task_info(struct task_struct *t, unsigned long timeout,
+ unsigned long this_round_count)
{
- unsigned long total_hung_task;
-
- if (!task_is_hung(t, timeout))
- return;
-
- /*
- * This counter tracks the total number of tasks detected as hung
- * since boot.
- */
- sysctl_hung_task_detect_count++;
-
- total_hung_task = sysctl_hung_task_detect_count - prev_detect_count;
trace_sched_process_hang(t);
- if (sysctl_hung_task_panic && total_hung_task >= sysctl_hung_task_panic) {
+ if (sysctl_hung_task_panic && this_round_count >= sysctl_hung_task_panic) {
console_verbose();
hung_task_call_panic = true;
}
/*
- * Ok, the task did not get scheduled for more than 2 minutes,
- * complain:
+ * The given task did not get scheduled for more than
+ * CONFIG_DEFAULT_HUNG_TASK_TIMEOUT. Therefore, complain
+ * accordingly
*/
if (sysctl_hung_task_warnings || hung_task_call_panic) {
if (sysctl_hung_task_warnings > 0)
sysctl_hung_task_warnings--;
- pr_err("INFO: task %s:%d blocked for more than %ld seconds.\n",
- t->comm, t->pid, (jiffies - t->last_switch_time) / HZ);
+ pr_err("INFO: task %s:%d blocked%s for more than %ld seconds.\n",
+ t->comm, t->pid, t->in_iowait ? " in I/O wait" : "",
+ (jiffies - t->last_switch_time) / HZ);
pr_err(" %s %s %.*s\n",
print_tainted(), init_utsname()->release,
(int)strcspn(init_utsname()->version, " "),
@@ -297,15 +296,14 @@ static bool rcu_lock_break(struct task_struct *g, struct task_struct *t)
/*
* Check whether a TASK_UNINTERRUPTIBLE does not get woken up for
- * a really long time (120 seconds). If that happens, print out
- * a warning.
+ * a really long time. If that happens, print out a warning.
*/
static void check_hung_uninterruptible_tasks(unsigned long timeout)
{
int max_count = sysctl_hung_task_check_count;
unsigned long last_break = jiffies;
struct task_struct *g, *t;
- unsigned long prev_detect_count = sysctl_hung_task_detect_count;
+ unsigned long this_round_count;
int need_warning = sysctl_hung_task_warnings;
unsigned long si_mask = hung_task_si_mask;
@@ -316,10 +314,9 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
if (test_taint(TAINT_DIE) || did_panic)
return;
-
+ this_round_count = 0;
rcu_read_lock();
for_each_process_thread(g, t) {
-
if (!max_count--)
goto unlock;
if (time_after(jiffies, last_break + HUNG_TASK_LOCK_BREAK)) {
@@ -328,12 +325,22 @@ static void check_hung_uninterruptible_tasks(unsigned long timeout)
last_break = jiffies;
}
- check_hung_task(t, timeout, prev_detect_count);
+ if (task_is_hung(t, timeout)) {
+ /*
+ * Increment the global counter so that userspace could
+ * start migrating tasks ASAP. But count the current
+ * round separately because userspace could reset
+ * the global counter at any time.
+ */
+ atomic_long_inc(&sysctl_hung_task_detect_count);
+ this_round_count++;
+ hung_task_info(t, timeout, this_round_count);
+ }
}
unlock:
rcu_read_unlock();
- if (!(sysctl_hung_task_detect_count - prev_detect_count))
+ if (!this_round_count)
return;
if (need_warning || hung_task_call_panic) {
@@ -358,6 +365,46 @@ static long hung_timeout_jiffies(unsigned long last_checked,
}
#ifdef CONFIG_SYSCTL
+
+/**
+ * proc_dohung_task_detect_count - proc handler for hung_task_detect_count
+ * @table: Pointer to the struct ctl_table definition for this proc entry
+ * @dir: Flag indicating the operation
+ * @buffer: User space buffer for data transfer
+ * @lenp: Pointer to the length of the data being transferred
+ * @ppos: Pointer to the current file offset
+ *
+ * This handler is used for reading the current hung task detection count
+ * and for resetting it to zero when a write operation is performed using a
+ * zero value only.
+ * Return: 0 on success, or a negative error code on failure.
+ */
+static int proc_dohung_task_detect_count(const struct ctl_table *table, int dir,
+ void *buffer, size_t *lenp, loff_t *ppos)
+{
+ unsigned long detect_count;
+ struct ctl_table proxy_table;
+ int err;
+
+ proxy_table = *table;
+ proxy_table.data = &detect_count;
+
+ if (SYSCTL_KERN_TO_USER(dir))
+ detect_count = atomic_long_read(&sysctl_hung_task_detect_count);
+
+ err = proc_doulongvec_minmax(&proxy_table, dir, buffer, lenp, ppos);
+ if (err < 0)
+ return err;
+
+ if (SYSCTL_USER_TO_KERN(dir)) {
+ if (detect_count)
+ return -EINVAL;
+ atomic_long_set(&sysctl_hung_task_detect_count, 0);
+ }
+
+ return 0;
+}
+
/*
* Process updating of timeout sysctl
*/
@@ -438,10 +485,9 @@ static const struct ctl_table hung_task_sysctls[] = {
},
{
.procname = "hung_task_detect_count",
- .data = &sysctl_hung_task_detect_count,
.maxlen = sizeof(unsigned long),
- .mode = 0444,
- .proc_handler = proc_doulongvec_minmax,
+ .mode = 0644,
+ .proc_handler = proc_dohung_task_detect_count,
},
{
.procname = "hung_task_sys_info",
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 2fea396d29b9..a43d2da0fe3e 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -47,7 +47,6 @@
#include <asm/page.h>
#include <asm/sections.h>
-#include <crypto/hash.h>
#include "kexec_internal.h"
atomic_t __kexec_lock = ATOMIC_INIT(0);
diff --git a/kernel/panic.c b/kernel/panic.c
index c78600212b6c..20feada5319d 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -801,6 +801,8 @@ EXPORT_SYMBOL(panic);
* Documentation/admin-guide/tainted-kernels.rst, including its
* small shell script that prints the TAINT_FLAGS_COUNT bits of
* /proc/sys/kernel/tainted.
+ *
+ * Also, update INIT_TAINT_BUF_MAX below.
*/
const struct taint_flag taint_flags[TAINT_FLAGS_COUNT] = {
TAINT_FLAG(PROPRIETARY_MODULE, 'P', 'G'),
@@ -854,15 +856,54 @@ static void print_tainted_seq(struct seq_buf *s, bool verbose)
}
}
+/* The initial buffer can accommodate all taint flags in verbose
+ * mode, with some headroom. Once the allocator is available, the
+ * exact size is allocated dynamically; the initial buffer remains
+ * as a fallback if allocation fails.
+ *
+ * The verbose taint string currently requires up to 327 characters.
+ */
+#define INIT_TAINT_BUF_MAX 350
+
+static char init_taint_buf[INIT_TAINT_BUF_MAX] __initdata;
+static char *taint_buf __refdata = init_taint_buf;
+static size_t taint_buf_size = INIT_TAINT_BUF_MAX;
+
+static __init int alloc_taint_buf(void)
+{
+ int i;
+ char *buf;
+ size_t size = 0;
+
+ size += sizeof("Tainted: ") - 1;
+ for (i = 0; i < TAINT_FLAGS_COUNT; i++) {
+ size += 2; /* For ", " */
+ size += 4; /* For "[%c]=" */
+ size += strlen(taint_flags[i].desc);
+ }
+
+ size += 1; /* For NULL terminator */
+
+ buf = kmalloc(size, GFP_KERNEL);
+
+ if (!buf) {
+ panic("Failed to allocate taint string buffer");
+ }
+
+ taint_buf = buf;
+ taint_buf_size = size;
+
+ return 0;
+}
+postcore_initcall(alloc_taint_buf);
+
static const char *_print_tainted(bool verbose)
{
- /* FIXME: what should the size be? */
- static char buf[sizeof(taint_flags)];
struct seq_buf s;
BUILD_BUG_ON(ARRAY_SIZE(taint_flags) != TAINT_FLAGS_COUNT);
- seq_buf_init(&s, buf, sizeof(buf));
+ seq_buf_init(&s, taint_buf, taint_buf_size);
print_tainted_seq(&s, verbose);
diff --git a/kernel/pid.c b/kernel/pid.c
index 677c84e319dd..fd5c2d4aa349 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -131,9 +131,8 @@ void free_pid(struct pid *pid)
wake_up_process(READ_ONCE(ns->child_reaper));
break;
case PIDNS_ADDING:
- /* Handle a fork failure of the first process */
- WARN_ON(ns->child_reaper);
- ns->pid_allocated = 0;
+ /* Only possible if the 1st fork fails */
+ WARN_ON(READ_ONCE(ns->child_reaper));
break;
}
@@ -230,6 +229,10 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t *arg_set_tid,
retried_preload = false;
idr_preload(GFP_KERNEL);
spin_lock(&pidmap_lock);
+ /* For the case when the previous attempt to create init failed */
+ if (ns->pid_allocated == PIDNS_ADDING)
+ idr_set_cursor(&ns->idr, 0);
+
for (tmp = ns, i = ns->level; i >= 0;) {
int tid = set_tid[ns->level - i];
@@ -314,6 +317,11 @@ struct pid *alloc_pid(struct pid_namespace *ns, pid_t *arg_set_tid,
*
* This can't be done earlier because we need to preserve other
* error conditions.
+ *
+ * We need this even if copy_process() does the same check. If two
+ * or more tasks from parent namespace try to inject a child into a
+ * dead namespace, one of free_pid() calls from the copy_process()
+ * error path may try to wakeup the possibly freed ns->child_reaper.
*/
retval = -ENOMEM;
if (unlikely(!(ns->pid_allocated & PIDNS_ADDING)))
@@ -341,10 +349,6 @@ out_free:
idr_remove(&upid->ns->idr, upid->nr);
}
- /* On failure to allocate the first pid, reset the state */
- if (ns->pid_allocated == PIDNS_ADDING)
- idr_set_cursor(&ns->idr, 0);
-
spin_unlock(&pidmap_lock);
idr_preload_end();
diff --git a/kernel/signal.c b/kernel/signal.c
index 21d881b95ffb..2d102e025883 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1000,9 +1000,7 @@ static void complete_signal(int sig, struct task_struct *p, enum pid_type type)
* Found a killable thread. If the signal will be fatal,
* then start taking the whole group down immediately.
*/
- if (sig_fatal(p, sig) &&
- (signal->core_state || !(signal->flags & SIGNAL_GROUP_EXIT)) &&
- !sigismember(&t->real_blocked, sig) &&
+ if (sig_fatal(p, sig) && !sigismember(&t->real_blocked, sig) &&
(sig == SIGKILL || !p->ptrace)) {
/*
* This signal will be fatal to the whole group.
@@ -2173,13 +2171,13 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
bool autoreap = false;
u64 utime, stime;
- WARN_ON_ONCE(sig == -1);
+ if (WARN_ON_ONCE(!valid_signal(sig)))
+ return false;
/* do_notify_parent_cldstop should have been called instead. */
WARN_ON_ONCE(task_is_stopped_or_traced(tsk));
- WARN_ON_ONCE(!tsk->ptrace &&
- (tsk->group_leader != tsk || !thread_group_empty(tsk)));
+ WARN_ON_ONCE(!tsk->ptrace && !thread_group_empty(tsk));
/* ptraced, or group-leader without sub-threads */
do_notify_pidfd(tsk);
@@ -2259,7 +2257,7 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
* Send with __send_signal as si_pid and si_uid are in the
* parent's namespaces.
*/
- if (valid_signal(sig) && sig)
+ if (sig)
__send_signal_locked(sig, &info, tsk->parent, PIDTYPE_TGID, false);
__wake_up_parent(tsk, tsk->parent);
spin_unlock_irqrestore(&psig->siglock, flags);
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 0cd680ccc7e5..73bd6a6a7893 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -649,6 +649,7 @@ void taskstats_exit(struct task_struct *tsk, int group_dead)
goto err;
memcpy(stats, tsk->signal->stats, sizeof(*stats));
+ stats->version = TASKSTATS_VERSION;
send:
send_cpu_listeners(rep_skb, listeners);
diff --git a/kernel/vmcore_info.c b/kernel/vmcore_info.c
index 94e4ef75b1b2..8614430ca212 100644
--- a/kernel/vmcore_info.c
+++ b/kernel/vmcore_info.c
@@ -18,8 +18,6 @@
#include <asm/page.h>
#include <asm/sections.h>
-#include <crypto/sha1.h>
-
#include "kallsyms_internal.h"
#include "kexec_internal.h"
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 7d675781bc91..87dd5e0f6968 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -61,6 +61,13 @@ int __read_mostly sysctl_hardlockup_all_cpu_backtrace;
# endif /* CONFIG_SMP */
/*
+ * Number of consecutive missed interrupts before declaring a lockup.
+ * Default to 1 (immediate) for NMI/Perf. Buddy will overwrite this to 3.
+ */
+int __read_mostly watchdog_hardlockup_miss_thresh = 1;
+EXPORT_SYMBOL_GPL(watchdog_hardlockup_miss_thresh);
+
+/*
* Should we panic when a soft-lockup or hard-lockup occurs:
*/
unsigned int __read_mostly hardlockup_panic =
@@ -137,6 +144,7 @@ __setup("nmi_watchdog=", hardlockup_panic_setup);
static DEFINE_PER_CPU(atomic_t, hrtimer_interrupts);
static DEFINE_PER_CPU(int, hrtimer_interrupts_saved);
+static DEFINE_PER_CPU(int, hrtimer_interrupts_missed);
static DEFINE_PER_CPU(bool, watchdog_hardlockup_warned);
static DEFINE_PER_CPU(bool, watchdog_hardlockup_touched);
static unsigned long hard_lockup_nmi_warn;
@@ -159,21 +167,33 @@ void watchdog_hardlockup_touch_cpu(unsigned int cpu)
per_cpu(watchdog_hardlockup_touched, cpu) = true;
}
-static bool is_hardlockup(unsigned int cpu)
+static void watchdog_hardlockup_update_reset(unsigned int cpu)
{
int hrint = atomic_read(&per_cpu(hrtimer_interrupts, cpu));
- if (per_cpu(hrtimer_interrupts_saved, cpu) == hrint)
- return true;
-
/*
* NOTE: we don't need any fancy atomic_t or READ_ONCE/WRITE_ONCE
* for hrtimer_interrupts_saved. hrtimer_interrupts_saved is
* written/read by a single CPU.
*/
per_cpu(hrtimer_interrupts_saved, cpu) = hrint;
+ per_cpu(hrtimer_interrupts_missed, cpu) = 0;
+}
+
+static bool is_hardlockup(unsigned int cpu)
+{
+ int hrint = atomic_read(&per_cpu(hrtimer_interrupts, cpu));
- return false;
+ if (per_cpu(hrtimer_interrupts_saved, cpu) != hrint) {
+ watchdog_hardlockup_update_reset(cpu);
+ return false;
+ }
+
+ per_cpu(hrtimer_interrupts_missed, cpu)++;
+ if (per_cpu(hrtimer_interrupts_missed, cpu) % watchdog_hardlockup_miss_thresh)
+ return false;
+
+ return true;
}
static void watchdog_hardlockup_kick(void)
@@ -187,8 +207,11 @@ static void watchdog_hardlockup_kick(void)
void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs)
{
int hardlockup_all_cpu_backtrace;
+ unsigned int this_cpu;
+ unsigned long flags;
if (per_cpu(watchdog_hardlockup_touched, cpu)) {
+ watchdog_hardlockup_update_reset(cpu);
per_cpu(watchdog_hardlockup_touched, cpu) = false;
return;
}
@@ -201,74 +224,73 @@ void watchdog_hardlockup_check(unsigned int cpu, struct pt_regs *regs)
* fired multiple times before we overflow'd. If it hasn't
* then this is a good indication the cpu is stuck
*/
- if (is_hardlockup(cpu)) {
- unsigned int this_cpu = smp_processor_id();
- unsigned long flags;
+ if (!is_hardlockup(cpu)) {
+ per_cpu(watchdog_hardlockup_warned, cpu) = false;
+ return;
+ }
#ifdef CONFIG_SYSFS
- ++hardlockup_count;
+ ++hardlockup_count;
#endif
- /*
- * A poorly behaving BPF scheduler can trigger hard lockup by
- * e.g. putting numerous affinitized tasks in a single queue and
- * directing all CPUs at it. The following call can return true
- * only once when sched_ext is enabled and will immediately
- * abort the BPF scheduler and print out a warning message.
- */
- if (scx_hardlockup(cpu))
- return;
+ /*
+ * A poorly behaving BPF scheduler can trigger hard lockup by
+ * e.g. putting numerous affinitized tasks in a single queue and
+ * directing all CPUs at it. The following call can return true
+ * only once when sched_ext is enabled and will immediately
+ * abort the BPF scheduler and print out a warning message.
+ */
+ if (scx_hardlockup(cpu))
+ return;
- /* Only print hardlockups once. */
- if (per_cpu(watchdog_hardlockup_warned, cpu))
- return;
+ /* Only print hardlockups once. */
+ if (per_cpu(watchdog_hardlockup_warned, cpu))
+ return;
- /*
- * Prevent multiple hard-lockup reports if one cpu is already
- * engaged in dumping all cpu back traces.
- */
- if (hardlockup_all_cpu_backtrace) {
- if (test_and_set_bit_lock(0, &hard_lockup_nmi_warn))
- return;
- }
+ /*
+ * Prevent multiple hard-lockup reports if one cpu is already
+ * engaged in dumping all cpu back traces.
+ */
+ if (hardlockup_all_cpu_backtrace) {
+ if (test_and_set_bit_lock(0, &hard_lockup_nmi_warn))
+ return;
+ }
- /*
- * NOTE: we call printk_cpu_sync_get_irqsave() after printing
- * the lockup message. While it would be nice to serialize
- * that printout, we really want to make sure that if some
- * other CPU somehow locked up while holding the lock associated
- * with printk_cpu_sync_get_irqsave() that we can still at least
- * get the message about the lockup out.
- */
- pr_emerg("CPU%u: Watchdog detected hard LOCKUP on cpu %u\n", this_cpu, cpu);
- printk_cpu_sync_get_irqsave(flags);
+ /*
+ * NOTE: we call printk_cpu_sync_get_irqsave() after printing
+ * the lockup message. While it would be nice to serialize
+ * that printout, we really want to make sure that if some
+ * other CPU somehow locked up while holding the lock associated
+ * with printk_cpu_sync_get_irqsave() that we can still at least
+ * get the message about the lockup out.
+ */
+ this_cpu = smp_processor_id();
+ pr_emerg("CPU%u: Watchdog detected hard LOCKUP on cpu %u\n", this_cpu, cpu);
+ printk_cpu_sync_get_irqsave(flags);
- print_modules();
- print_irqtrace_events(current);
- if (cpu == this_cpu) {
- if (regs)
- show_regs(regs);
- else
- dump_stack();
- printk_cpu_sync_put_irqrestore(flags);
- } else {
- printk_cpu_sync_put_irqrestore(flags);
- trigger_single_cpu_backtrace(cpu);
- }
+ print_modules();
+ print_irqtrace_events(current);
+ if (cpu == this_cpu) {
+ if (regs)
+ show_regs(regs);
+ else
+ dump_stack();
+ printk_cpu_sync_put_irqrestore(flags);
+ } else {
+ printk_cpu_sync_put_irqrestore(flags);
+ trigger_single_cpu_backtrace(cpu);
+ }
- if (hardlockup_all_cpu_backtrace) {
- trigger_allbutcpu_cpu_backtrace(cpu);
- if (!hardlockup_panic)
- clear_bit_unlock(0, &hard_lockup_nmi_warn);
- }
+ if (hardlockup_all_cpu_backtrace) {
+ trigger_allbutcpu_cpu_backtrace(cpu);
+ if (!hardlockup_panic)
+ clear_bit_unlock(0, &hard_lockup_nmi_warn);
+ }
- sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT);
- if (hardlockup_panic)
- nmi_panic(regs, "Hard LOCKUP");
+ sys_info(hardlockup_si_mask & ~SYS_INFO_ALL_BT);
+ if (hardlockup_panic)
+ nmi_panic(regs, "Hard LOCKUP");
- per_cpu(watchdog_hardlockup_warned, cpu) = true;
- } else {
- per_cpu(watchdog_hardlockup_warned, cpu) = false;
- }
+ per_cpu(watchdog_hardlockup_warned, cpu) = true;
}
#else /* CONFIG_HARDLOCKUP_DETECTOR_COUNTS_HRTIMER */
diff --git a/kernel/watchdog_buddy.c b/kernel/watchdog_buddy.c
index ee754d767c21..3a1e57080c1c 100644
--- a/kernel/watchdog_buddy.c
+++ b/kernel/watchdog_buddy.c
@@ -21,6 +21,7 @@ static unsigned int watchdog_next_cpu(unsigned int cpu)
int __init watchdog_hardlockup_probe(void)
{
+ watchdog_hardlockup_miss_thresh = 3;
return 0;
}
@@ -86,14 +87,6 @@ void watchdog_buddy_check_hardlockup(int hrtimer_interrupts)
{
unsigned int next_cpu;
- /*
- * Test for hardlockups every 3 samples. The sample period is
- * watchdog_thresh * 2 / 5, so 3 samples gets us back to slightly over
- * watchdog_thresh (over by 20%).
- */
- if (hrtimer_interrupts % 3 != 0)
- return;
-
/* check for a hardlockup on the next CPU */
next_cpu = watchdog_next_cpu(smp_processor_id());
if (next_cpu >= nr_cpu_ids)