xfs: add kmem_alloc_by_vmalloc and kmem_alloc_large_dump_stack sysctl

Upstream: no

Add dump stack logic when kmem_alloc failed.

kmem_alloc_by_vmalloc: when kmem_alloc size larger than
PAGE_SIZE * kmem_alloc_by_vmalloc, use vmalloc instead kmalloc.
kmem_alloc_large_dump_stack: dump info and stack when kmem_alloc size
larger than PAGE_SIZE*kmem_alloc_by_vmalloc.

Signed-off-by: Kaixu Xia <kaixuxia@tencent.com>
Signed-off-by: katrinzhou <katrinzhou@tencent.com>
Signed-off-by: Kairui Song <kasong@tencent.com>
This commit is contained in:
Kairui Song 2023-11-16 18:27:48 +08:00
parent 4330e77496
commit 9ffe8eb4df
7 changed files with 62 additions and 4 deletions

View File

@ -41,6 +41,7 @@ void arch_trigger_cpumask_backtrace(const cpumask_t *mask, int exclude_cpu)
nmi_trigger_cpumask_backtrace(mask, exclude_cpu,
nmi_raise_cpu_backtrace);
}
EXPORT_SYMBOL_GPL(arch_trigger_cpumask_backtrace);
static int nmi_cpu_backtrace_handler(unsigned int cmd, struct pt_regs *regs)
{

View File

@ -4,8 +4,10 @@
* All Rights Reserved.
*/
#include "xfs.h"
#include <linux/nmi.h>
#include "xfs_message.h"
#include "xfs_trace.h"
#include "xfs_linux.h"
void *
kmem_alloc(size_t size, xfs_km_flags_t flags)
@ -16,15 +18,33 @@ kmem_alloc(size_t size, xfs_km_flags_t flags)
trace_kmem_alloc(size, flags, _RET_IP_);
if (xfs_kmem_alloc_by_vmalloc &&
size > (PAGE_SIZE * xfs_kmem_alloc_by_vmalloc) &&
xfs_kmem_alloc_large_dump_stack) {
xfs_warn(NULL, "%s size: %ld large than %ld\n",
__func__, size, PAGE_SIZE * xfs_kmem_alloc_by_vmalloc);
dump_stack();
}
do {
ptr = kmalloc(size, lflags);
if (xfs_kmem_alloc_by_vmalloc && (size > PAGE_SIZE * xfs_kmem_alloc_by_vmalloc))
ptr = __vmalloc(size, lflags);
else
ptr = kmalloc(size, lflags);
if (ptr || (flags & KM_MAYFAIL))
return ptr;
if (!(++retries % 100))
if (!(++retries % 100)) {
xfs_err(NULL,
"%s(%u) possible memory allocation deadlock size %u in %s (mode:0x%x)",
"%s(%u) possible memory allocation deadlock size %u in %s (mode:0x%x), flags: 0x%x",
current->comm, current->pid,
(unsigned int)size, __func__, lflags);
(unsigned int)size, __func__, lflags, flags);
if (xfs_kmem_fail_dump_stack == 1)
dump_stack();
else if (xfs_kmem_fail_dump_stack == 2)
trigger_all_cpu_backtrace();
else if (xfs_kmem_fail_dump_stack == 3)
__show_mem(0, NULL, gfp_zone(lflags));
}
memalloc_retry_wait(lflags);
} while (1);
}

View File

@ -30,6 +30,9 @@ xfs_param_t xfs_params = {
.inherit_nodfrg = { 0, 1, 1 },
.fstrm_timer = { 1, 30*100, 3600*100},
.blockgc_timer = { 1, 300, 3600*24},
.kmem_fail_dump_stack = { 0, 0, 3 },
.kmem_alloc_by_vmalloc = { 0, 1, 4 },
.kmem_alloc_large_dump_stack = { 0, 0, 1 },
};
struct xfs_globals xfs_globals = {

View File

@ -103,6 +103,9 @@ typedef __u32 xfs_nlink_t;
#define xfs_inherit_nodefrag xfs_params.inherit_nodfrg.val
#define xfs_fstrm_centisecs xfs_params.fstrm_timer.val
#define xfs_blockgc_secs xfs_params.blockgc_timer.val
#define xfs_kmem_fail_dump_stack xfs_params.kmem_fail_dump_stack.val
#define xfs_kmem_alloc_by_vmalloc xfs_params.kmem_alloc_by_vmalloc.val
#define xfs_kmem_alloc_large_dump_stack xfs_params.kmem_alloc_large_dump_stack.val
#define current_cpu() (raw_smp_processor_id())
#define current_set_flags_nested(sp, f) \

View File

@ -206,6 +206,33 @@ static struct ctl_table xfs_table[] = {
.extra2 = &xfs_params.stats_clear.max
},
#endif /* CONFIG_PROC_FS */
{
.procname = "kmem_fail_dump_stack",
.data = &xfs_params.kmem_fail_dump_stack.val,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &xfs_params.kmem_fail_dump_stack.min,
.extra2 = &xfs_params.kmem_fail_dump_stack.max,
},
{
.procname = "kmem_alloc_by_vmalloc",
.data = &xfs_params.kmem_alloc_by_vmalloc.val,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &xfs_params.kmem_alloc_by_vmalloc.min,
.extra2 = &xfs_params.kmem_alloc_by_vmalloc.max,
},
{
.procname = "kmem_alloc_large_dump_stack",
.data = &xfs_params.kmem_alloc_large_dump_stack.val,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec_minmax,
.extra1 = &xfs_params.kmem_alloc_large_dump_stack.min,
.extra2 = &xfs_params.kmem_alloc_large_dump_stack.max,
},
{}
};

View File

@ -36,6 +36,9 @@ typedef struct xfs_param {
xfs_sysctl_val_t inherit_nodfrg;/* Inherit the "nodefrag" inode flag. */
xfs_sysctl_val_t fstrm_timer; /* Filestream dir-AG assoc'n timeout. */
xfs_sysctl_val_t blockgc_timer; /* Interval between blockgc scans */
xfs_sysctl_val_t kmem_fail_dump_stack;
xfs_sysctl_val_t kmem_alloc_by_vmalloc;
xfs_sysctl_val_t kmem_alloc_large_dump_stack;
} xfs_param_t;
/*

View File

@ -427,3 +427,4 @@ void __show_mem(unsigned int filter, nodemask_t *nodemask, int max_zone_idx)
printk("%lu pages hwpoisoned\n", atomic_long_read(&num_poisoned_pages));
#endif
}
EXPORT_SYMBOL(__show_mem);