Alibaba Cloud Linux 3在内核版本5.10.84-10
(x86架构)和5.10.134-16
(ARM架构)开始支持KFENCE功能。本文为您介绍KFENCE的功能和使用方法等。
功能介绍
KFENCE(Kernel Electric-Fence)是Linux内核内置的、可在线上环境开启的工具,用于捕获内核及内核模块的内存污染问题,在上游Linux内核社区的5.12
版本中引入。KFENCE的目标是通过在内存边界附近插入特殊的标记(fence),来检测对已释放或未分配内存的访问。当发生内存污染问题时,KFENCE会检测到并触发错误报告,并提供有关问题的详细信息。关于KFENCE的更多信息,请参见KFENCE文档和龙蜥社区。
阿里云在Alibaba Cloud Linux 3中对KFENCE功能进行了增强,能够灵活动态开关KFENCE和全量捕获内存污染问题,从而兼顾线上探测和线下调试。
如果您是一名内核或内核模块的开发者,可以用此工具来检查您开发的内核或内核模块是否存在内存污染问题。如果您是一名普通用户但遇到了内核崩溃的问题,也可以打开KFENCE帮助我们或第三方驱动模块的开发者收集更多信息。
开启KFENCE
在以下业务场景中经常会用到开启KFENCE功能,具体说明如下:
线上探测场景
场景1:使用KFENCE探测内存是否存在污染
该场景占用2 MiB内存,基本不会影响性能。
运行以下命令,开启KFENCE(添加boot commandline参数的方式)。
sudo grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="kfence.sample_interval=100"
该场景下,系统在下次重启时,配置会自动生效。
场景2:使用KFENCE捕获内存污染问题
该场景将消耗以GiB为单位的大量内存,小规格机器慎用。
新建一个内存分配脚本,并添加如下内容(以脚本名称kfence.sh,监控的目标slab类型是
kmalloc-64
为例)。#!/bin/bash # usage: ./kfence.sh kmalloc-64 SLAB_PREFIX=/sys/kernel/slab MODULE_PREFIX=/sys/module/kfence/parameters if [ $# -eq 0 ]; then echo "err: please input slabs" exit 1 fi #check whether slab exists for i in $@; do slab_path=$SLAB_PREFIX/$i if [ ! -d $slab_path ]; then echo "err: slab $i not exist!" exit 1 fi done #calculate num_objects sumobj=0 for i in $@; do objects=($(cat $SLAB_PREFIX/$i/objects)) maxobj=1 for ((j=1; j<${#objects[@]}; j++)); do nodeobj=$(echo ${objects[$j]} | awk -F= '{print $2}') [ $maxobj -lt $nodeobj ] && maxobj=$nodeobj done ((sumobj += maxobj)) done echo "recommend num_objects per node: $sumobj" #check kfence stats if [ $(cat $MODULE_PREFIX/sample_interval) -ne 0 ]; then echo "kfence is running, disable it and wait..." echo 0 > $MODULE_PREFIX/sample_interval sleep 1 fi #disable all slabs catching for file in $SLAB_PREFIX/* do echo 0 > $file/kfence_enable done #disable order0 page catching echo 0 > $MODULE_PREFIX/order0_page #enable setting slabs catching for i in $@; do echo 1 > $SLAB_PREFIX/$i/kfence_enable done #setting num_objects and node mode echo $sumobj > $MODULE_PREFIX/num_objects echo node > $MODULE_PREFIX/pool_mode #start kfence echo -1 > $MODULE_PREFIX/sample_interval if [ $? -ne 0 ]; then echo "err: kfence enable fail!" exit 1 fi echo "kfence enabled!"
该脚本将探测目标slab的活跃对象数量,并根据该数量估算出合适的KFENCE池子大小,然后启用KFENCE以捕获所有目标slab的分配。
说明slab是内存管理中常用的概念和技术,用于优化内存的分配和释放操作,提高系统的性能和效率。KFENCE支持监控slab以及order 0单页。更多信息,请参见基本概念。
运行以下命令,执行脚本,开始探测。
sudo bash ./kfence.sh kmalloc-64
线下调试场景
通过添加参数开启KFENCE(x86架构)
运行以下命令,开启KFENCE。
sudo grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="kfence.num_objects=1000000" sudo grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="kfence.sample_interval=-1" sudo grubby --update-kernel=/boot/vmlinuz-$(uname -r) --args="kfence.fault=panic"
num_objects
:决定了KFENCE池子的大小,其占用内存为(num_objects+1)* 8 KiB,一般建议该值配置为最大可用内存的10%。例如设置num_objects
为1,000,000时,占用内存为(1,000,000+1)* 8 KiB,计算结果向上取整为8 GiB。sample_interval
:取值包含以下三种情况。0:表示关闭KFENCE功能。
正数:采样间隔(ms),例如设置为100时,表示每隔100 ms分配的内存将进入KFENCE的监控范围内。
负数:全量模式,所有符合(slab类型筛选)条件的内存均将进入KFENCE的监控范围内。
fault
:自内核版本5.10.134-16
开始新增的参数,默认是report
。当设置为panic
时,会在捕获问题的现场宕机,以保留第一现场的内核转储文件。
重启系统使配置生效。
具体操作,请参见重启实例。
通过配置脚本开启KFENCE(x86/ARM架构)
通过该方式开启KFENCE时,无法捕获内核启动过程中可能出现的内存污染问题。
开启KFENCE后,如果需要修改
num_objects
或sample_interval
配置,需先关闭KFENCE再进行修改。
运行以下命令,开启KFENCE。
sudo sh -c 'echo 1000000 > /sys/module/kfence/parameters/num_objects'
sudo sh -c 'echo -1 > /sys/module/kfence/parameters/sample_interval'
sudo sh -c 'echo panic > /sys/module/kfence/parameters/fault'
num_objects
:决定了KFENCE池子的大小,其占用内存为(num_objects+1)* 8 KiB,一般建议该值配置为最大可用内存的10%。例如设置num_objects
为1,000,000时,占用内存为(1,000,000+1)* 8 KiB,计算结果向上取整为8 GiB。sample_interval
:取值包含以下三种情况。0:表示关闭KFENCE功能。
正数:采样间隔(ms),例如设置为100时,表示每隔100 ms分配的内存将进入KFENCE的监控范围内。
负数:全量模式,所有符合(slab类型筛选)条件的内存均将进入KFENCE的监控范围内。
fault
:自内核版本5.10.134-16
开始新增的参数,默认是report
。当设置为panic
时,会在捕获问题的现场宕机,以保留第一现场的内核转储文件。说明如果您的内核是
5.10.134-16
之前的版本,执行该条命令会报错,您直接忽略即可,不影响开启KFENCE。
查看结果
KFENCE捕获到内存污染问题后,您可以查看捕获到的问题个数以及详细的错误信息。
如下图所示,运行
sudo cat /sys/kernel/debug/kfence/stats
命令,查看到的total bugs
计数会增加。系统会将信息打印在dmesg中,您可以运行
dmesg | grep -i kfence
命令查看与KFENCE相关的错误日志信息。如下图所示,查询到1条错误信息。
关闭KFENCE
运行以下命令,关闭KFENCE。
sudo bash -c 'echo 0 > /sys/module/kfence/parameters/sample_interval'
关闭KFENCE功能后,KFENCE不再捕获任何内存分配。当池子内监控的所有内存均释放后,KFENCE将以1 GiB单位为粒度向内核伙伴系统返还内存。
对于通过添加boot commandline开启KFENCE的场景,您可以运行以下命令移除这些参数,下次系统重启将不再自动打开KFENCE。
sudo grubby --update-kernel=/boot/vmlinuz-$(uname -r) --remove-args="kfence.sample_interval"
FAQ
基本概念
KFENCE功能中涉及的基本概念说明如下。
名词 | 说明 |
内存污染 | 指在程序运行过程中,内存区域被错误地修改或破坏,导致程序行为异常或崩溃的问题。内存污染可能是由于编程错误、软件漏洞、恶意软件或硬件故障等原因引起的。 |
slab | slab是Linux内核中一种高效的内存分配机制。它通过预先分配一定数量的内存对象,组织成一个内存缓存池,用于快速分配和释放内存。slab可以避免频繁的内存分配和释放操作,提高内存分配的效率。 |
order 0单页 | order 0单页也是Linux内核中一种内存分配机制,内存被分割成固定大小的页框(page frame),一般为4 KiB。order 0的单页指的就是一个普通的4 KiB大小的内存页框,它是内存分配的基本单位。当应用程序或内核需要分配一小块内存时,通常会以order 0的方式进行分配。 |