在日常开发工作中最容易发生的错误十有八九都是出在线性空间的操作方面。(这里指的线性空间可以认为等同于虚拟地址或虚拟内存,但其他场合并不一 定适用)
主要的问题体现在:
1. 访问了未初始化的线性空间。 这类问题还是相对比较容易发现,因为内核立即会告警并打印堆栈。
2. 释放了错误的线性空间,或者对某个线性空间进行了双重释放。这种情况如果测试充分也能被发现,但即使被发现也很难判定就是因为误释放线性空间而发生错误。 因为内核无法判断你要释放的线性空间是不是就是你要释放的,所以也不会有任何告警。如果测试过程中未被发现那么它将是埋在产品中的一颗定时炸弹, 也许连续run 几个小时内核就会挂掉,也许run 几天几十天才会挂掉。
3. 已分配的线性空间没有释放,其实就是常说的内存泄露,如果某个类型的内存对象很小,或者被分配的几率很低,这通常不是什么非常大的问题,尤其是在拥有海量 内存的系统上。如果情况不是这样,那么写代码的时候就要小心了,因为后续补救起来是件非常耗时和麻烦的工作。
使用slub(slab) API 并配合debug(posion 内存毒药)功能能够大幅降低上述问题的发生。
准备内核:
1. 如果分配器使用的是slab, kernel configuration:
CONFIG_SLAB=y
CONFIG_SLAB_DEBUG=y
CONFIG_DEBUG_SLAB_LEAK=y
CONFIG_DEBUG_SLABINFO=y
CONFIG_DEBUG_INFO=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
2. 如果分配器使用的是slub 那么就简单了,无需重新编译内核,slub默认就内嵌了debug的相关代码,只不过这项功能默认是禁用的。
最好仍然增加如下kernel configuration:
CONFIG_DEBUG_SLABINFO=y
CONFIG_DEBUG_INFO=y
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
启用方法:
个人仅使用过slub debug,下文均以slub分配器来说明:
1. 如果需要启用全局的slub debug 需要在内核启动参数中加入 slub_debug
2. 有时候在全局启用了debug后 内核消息输出会增加很多,对于debug 特定的slub(slab) 对象而言看起来很不方便,并大幅降低分配器的效率。 这种情况下可以选择特定的对象来调试,而且可以在内核运行时打开/关闭 调试对象,不需要重启。步骤如下:
#cat /proc/slabinfo
slabinfo – version: 2.1
# name
fat_inode_cache 23 253 688 23 4 : tunables 0 0 0 : slabdata 11 11 0
fat_cache 102 204 40 102 1 : tunables 0 0 0 : slabdata 2 2 0
fuse_request 26 52 608 26 4 : tunables 0 0 0 : slabdata 2 2 0
fuse_inode 1 23 704 23 4 : tunables 0 0 0 : slabdata 1 1 0
kcopyd_job 0 0 3240 10 8 : tunables 0 0 0 : slabdata 0 0 0
dm_uevent 0 0 2608 12 8 : tunables 0 0 0 : slabdata 0 0 0
dm_rq_target_io 0 0 408 20 2 : tunables 0 0 0 : slabdata 0 0 0
ip6_dst_cache 7 25 320 25 2 : tunables 0 0 0 : slabdata 1 1 0
UDPLITEv6 0 0 1024 16 4 : tunables 0 0 0 : slabdata 0 0 0
UDPv6 16 32 1024 16 4 : tunables 0 0 0 : slabdata 2 2 0
tw_sock_TCPv6 0 16 256 16 1 : tunables 0 0 0 : slabdata 1 1 0
TCPv6 19 34 1856 17 8 : tunables 0 0 0 : slabdata 2 2 0
flow_cache 0 0 104 39 1 : tunables 0 0 0 : slabdata 0 0 0
cfq_queue 225 238 232 17 1 : tunables 0 0 0 : slabdata 14 14 0
bsg_cmd 0 0 312 26 2 : tunables 0 0 0 : slabdata 0 0 0
journal_handle 340 340 24 170 1 : tunables 0 0 0 : slabdata 2 2 0
journal_head 72 288 112 36 1 : tunables 0 0 0 : slabdata 8 8 0
revoke_record 256 256 32 128 1 : tunables 0 0 0 : slabdata 2 2 0
ext4_inode_cache 21466 21618 904 18 4 : tunables 0 0 0 : slabdata 1201 1201 0
ext4_free_data 146 146 56 73 1 : tunables 0 0 0 : slabdata 2 2 0
ext4_allocation_context 870 870 136 30 1 : tunables 0 0 0 : slabdata 29 29 0
ext4_io_end 58 319 1128 29 8 : tunables 0 0 0 : slabdata 11 11 0
ext4_io_page 516 1792 16 256 1 : tunables 0 0 0 : slabdata 7 7 0
ext3_inode_cache 0 0 792 20 4 : tunables 0 0 0 : slabdata 0 0 0
ext3_xattr 0 0 88 46 1 : tunables 0 0 0 : slabdata 0 0 0
arp_cache 36 36 448 18 2 : tunables 0 0 0 : slabdata 2 2 0
RAW 461 475 832 19 4 : tunables 0 0 0 : slabdata 25 25 0
UDP 38 38 832 19 4 : tunables 0 0 0 : slabdata 2 2 0
tw_sock_TCP 21 42 192 21 1 : tunables 0 0 0 : slabdata 2 2 0
TCP 42 209 1664 19 8 : tunables 0 0 0 : slabdata 11 11 0
blkdev_queue 20 36 1816 18 8 : tunables 0 0 0 : slabdata 2 2 0
blkdev_requests 52 220 368 22 2 : tunables 0 0 0 : slabdata 10 10 0
sock_inode_cache 554 675 640 25 4 : tunables 0 0 0 : slabdata 27 27 0
net_namespace 1 12 2560 12 8 : tunables 0 0 0 : slabdata 1 1 0
shmem_inode_cache 11296 11448 656 24 4 : tunables 0 0 0 : slabdata 477 477 0
shared_policy_node 21143 22440 48 85 1 : tunables 0 0 0 : slabdata 264 264 0
numa_policy 203 210 136 30 1 : tunables 0 0 0 : slabdata 7 7 0
radix_tree_node 7248 8456 568 28 4 : tunables 0 0 0 : slabdata 302 302 0
idr_layer_cache 872 900 544 30 4 : tunables 0 0 0 : slabdata 30 30 0
dma-kmalloc-8192 0 0 8192 4 8 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-4096 0 0 4096 8 8 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-2048 0 0 2048 16 8 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-1024 0 0 1024 16 4 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-512 0 16 512 16 2 : tunables 0 0 0 : slabdata 1 1 0
dma-kmalloc-256 0 0 256 16 1 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-128 0 0 128 32 1 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-64 0 0 64 64 1 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-32 0 0 32 128 1 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-16 0 0 16 256 1 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-8 0 0 8 512 1 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-192 0 0 192 21 1 : tunables 0 0 0 : slabdata 0 0 0
dma-kmalloc-96 0 0 96 42 1 : tunables 0 0 0 : slabdata 0 0 0
kmalloc-8192 41 44 8192 4 8 : tunables 0 0 0 : slabdata 11 11 0
kmalloc-4096 109 120 4096 8 8 : tunables 0 0 0 : slabdata 15 15 0
kmalloc-2048 597 672 2048 16 8 : tunables 0 0 0 : slabdata 42 42 0
kmalloc-1024 787 864 1024 16 4 : tunables 0 0 0 : slabdata 54 54 0
kmalloc-512 10975 11088 512 16 2 : tunables 0 0 0 : slabdata 693 693 0
kmalloc-256 1439 1488 256 16 1 : tunables 0 0 0 : slabdata 93 93 0
kmalloc-128 1886 3232 128 32 1 : tunables 0 0 0 : slabdata 101 101 0
kmalloc-64 21988 23040 64 64 1 : tunables 0 0 0 : slabdata 360 360 0
kmalloc-32 20129 20992 32 128 1 : tunables 0 0 0 : slabdata 164 164 0
kmalloc-16 3341 3584 16 256 1 : tunables 0 0 0 : slabdata 14 14 0
kmalloc-8 22202 23040 8 512 1 : tunables 0 0 0 : slabdata 45 45 0
kmalloc-192 17809 17955 192 21 1 : tunables 0 0 0 : slabdata 855 855 0
kmalloc-96 6222 6342 96 42 1 : tunables 0 0 0 : slabdata 151 151 0
kmem_cache 32 32 256 16 1 : tunables 0 0 0 : slabdata 2 2 0
kmem_cache_node 153 192 64 64 1 : tunables 0 0 0 : slabdata 3 3 0
然后记下需要调试的对象名称(第一列)
echo 1 > /sys/kernel/slab/<对象名称>/poison
最后cat /sys/kernel/slab/<对象名称>/poison
如果显示为1 则说明针对此对象的debug poison 已经打开
注意:实际情况下并不是所有<对象名称>都可以在运行时开启/关闭debug poison 比如kmalloc-x
测试:
示例代码:
#include
#include
#include
#include
MODULE_LICENSE(“GPL”);
struct slab_obj{
int aa;
int bb;
int cc;
};
typedef struct slab_obj* slab_obj_t;
slab_obj_t memblk=NULL;
struct kmem_cache *myslabobj;
static void mm_create(void){
myslabobj=kmem_cache_create(“my_slab_obj”,sizeof(struct slab_obj),0,SLAB_HWCACHE_ALIGN,NULL);
memblk=kmem_cache_alloc(myslabobj,GFP_KERNEL);
memblk->aa=0xabcd;
memblk->bb=0×1234;
memblk->cc=0×6879;
}
static void mm_destroy(void){
kfree(memblk);
kmem_cache_destroy(myslabobj);
}
static int __init mmbug_init(void){
mm_create();
return 0;
}
static void __exit mmbug_exit(void){
mm_destroy();
}
module_init(mmbug_init);
module_exit(mmbug_exit);
这段代码是没有内存方面的问题的,针对自定义的“slab_obj” 创建了slub cache “my_slab_obj” 。由于是非内核数据结构,所以my_slab_obj不会在/proc/slabinfo 中新开一行,而是根据sizeof(struct slab_ojb) 的大小合并到kmalloc-8 。又因为kmalloc-8 不能在运行时开启debug poison ,所以只能启动时加内核参数slub_debug来开启。
1. 检测内存泄露:
在mm_destroy() 函数中把kfree(memblk); 注释掉 。 这样在模块卸载时调用到kmem_cache_destroy(myslabobj) 就会触发slub debug ,告警:
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943251] =============================================================================
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943254] BUG my_slab_obj: Objects remaining on kmem_cache_close()
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943256] —————————————————————————–
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943256]
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943258] INFO: Slab 0xffffea000039f200 objects=24 used=1 fp=0xffff88000e7c9e30 flags=0×20000000004080
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943261] Pid: 4842, comm: rmmod Not tainted 3.1.0-1.5-yamu-kmem #2
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943263] Call Trace:
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943269] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943272] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943275] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943279] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943283] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943286] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943289] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943291] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943296] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943300] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943304] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943311] [<00007f0966db7b27>] 0x7f0966db7b26
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943314] INFO: Object 0xffff88000e7c8000 @offset=0
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943317] INFO: Allocated in 0xffffffffa0005033 age=1316 cpu=1 pid=4841
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943319] set_track+0x5d/0x1a0
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943321] alloc_debug_processing+0x8d/0xfb
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943322] __slab_alloc.isra.60+0x20c/0x25b
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943324] kmem_cache_alloc+0×141/0×150
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943326] 0xffffffffa0005033
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943328] do_one_initcall+0x3b/0×180
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943329] sys_init_module+0×113/0×380
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943331] system_call_fastpath+0×16/0x1b
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943333] 0x7f491185cc8a
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943346] SLUB my_slab_obj: kmem_cache_destroy called for cache that still has objects.
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943348] Pid: 4842, comm: rmmod Not tainted 3.1.0-1.5-yamu-kmem #2
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943350] Call Trace:
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943352] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943355] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943357] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943360] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943362] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943366] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943368] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943371] [
Jan 16 14:14:55 linux-9ffj kernel: [ 7880.943374] [<00007f0966db7b27>] 0x7f0966db7b26
2. 检测错误释放线性空间(这里表现为重复释放):
在原来的kfree(memblk) 后面再加一个kfree(memblk) 进行重复释放,卸载模块时告警:
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831862] =============================================================================
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831866] BUG my_slab_obj: Object already free
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831867] —————————————————————————–
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831868]
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831875] INFO: Allocated in 0xffffffffa0005033 age=4621 cpu=1 pid=5196
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831879] set_track+0x5d/0x1a0
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831882] alloc_debug_processing+0x8d/0xfb
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831884] __slab_alloc.isra.60+0x20c/0x25b
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831886] kmem_cache_alloc+0×141/0×150
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831887] 0xffffffffa0005033
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831890] do_one_initcall+0x3b/0×180
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831893] sys_init_module+0×113/0×380
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831895] system_call_fastpath+0×16/0x1b
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831897] 0x7f569ec49c8a
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831899] INFO: Freed in mmbug_exit+0×10/0×1000 [mmbug] age=0 cpu=0 pid=5198
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831901] set_track+0x5d/0x1a0
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831903] free_debug_processing+0×137/0x1a7
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831904] __slab_free+0x2c/0x30b
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831906] kfree+0×140/0×170
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831907] mmbug_exit+0×10/0×1000 [mmbug]
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831909] sys_delete_module+0×191/0×380
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831911] system_call_fastpath+0×16/0x1b
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831912] 0x7f41cf78bb27
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831913] INFO: Slab 0xffffea0001483e00 objects=24 used=0 fp=0xffff8800520f8000 flags=0×20000000004081
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831915] INFO: Object 0xffff8800520f8000 @offset=0 fp=0xffff8800520f9e30
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831916]
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831917] Object 0xffff8800520f8000: 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkk�
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831925] Redzone 0xffff8800520f800c: bb bb bb bb ����
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831932] Padding 0xffff8800520f8148: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831940] Pid: 5198, comm: rmmod Not tainted 3.1.0-1.5-yamu-kmem #2
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831941] Call Trace:
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831945] [
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831948] [
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831951] [
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831954] [
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831957] [
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831960] [
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831962] [
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831965] [
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831968] [
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831971] [
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831974] [
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831977] [<00007f41cf78bb27>] 0x7f41cf78bb26
Jan 16 14:20:15 linux-9ffj kernel: [ 8200.831979] FIX my_slab_obj: Object at 0xffff8800520f8000 not freed
注意最后一行的 “FIX” 他的意思是第二次释放无效,这样其实避免了内核panic的可能性。
3. 访问已释放的线性空间
对于写操作:
增加kfree后面的代码如下
memblk->aa=0xabcd;
memblk->bb=0×1234;
memblk->cc=0×8789;
卸载模块时告警:
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313558] =============================================================================
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313562] BUG my_slab_obj: Poison overwritten
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313563] —————————————————————————–
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313564]
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313565] INFO: 0xffff88000aace000-0xffff88000aace00a. First byte 0xcd instead of 0x6b
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313572] INFO: Allocated in 0xffffffffa0005033 age=1607 cpu=1 pid=5369
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313577] set_track+0x5d/0x1a0
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313579] alloc_debug_processing+0x8d/0xfb
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313581] __slab_alloc.isra.60+0x20c/0x25b
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313583] kmem_cache_alloc+0×141/0×150
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313584] 0xffffffffa0005033
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313587] do_one_initcall+0x3b/0×180
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313590] sys_init_module+0×113/0×380
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313592] system_call_fastpath+0×16/0x1b
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313594] 0x7f3ce0bbbc8a
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313596] INFO: Freed in mmbug_exit+0×10/0×1000 [mmbug] age=0 cpu=1 pid=5370
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313598] set_track+0x5d/0x1a0
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313600] free_debug_processing+0×137/0x1a7
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313601] __slab_free+0x2c/0x30b
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313603] kfree+0×140/0×170
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313604] mmbug_exit+0×10/0×1000 [mmbug]
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313606] sys_delete_module+0×191/0×380
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313608] system_call_fastpath+0×16/0x1b
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313609] 0x7f8e151a2b27
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313611] INFO: Slab 0xffffea00002ab380 objects=24 used=0 fp=0xffff88000aace000 flags=0×20000000004080
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313612] INFO: Object 0xffff88000aace000 @offset=0 fp=0xffff88000aacfe30
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313613]
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313614] Object 0xffff88000aace000: cd ab 00 00 34 12 00 00 89 87 00 00 ͫ..4…….
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313622] Redzone 0xffff88000aace00c: bb bb bb bb ����
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313629] Padding 0xffff88000aace148: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313637] Pid: 5370, comm: rmmod Not tainted 3.1.0-1.5-yamu-kmem #2
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313639] Call Trace:
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313643] [
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313646] [
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313648] [
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313652] [
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313655] [
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313658] [
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313661] [
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313664] [
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313667] [
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313670] [
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313673] [
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313676] [
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313679] [
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313682] [<00007f8e151a2b27>] 0x7f8e151a2b26
Jan 16 14:26:02 linux-9ffj kernel: [ 8548.313684] FIX my_slab_obj: Restoring 0xffff88000aace000-0xffff88000aace00a=0x6b
同样最后的 “FIX” 指示第二次访问无效,内核不会panic。
对于读操作 不会出现告警,但如果用printk 打印这段地址,会输出多个字节的0x6b。看到这个就说明正在访问已经释放过的线性空间。
原理:
slub 实现poison debug 其实是简单的,正如刚才的debug 信息中所示slub(slab)会在恰当的时候放置单字节poison 0x6b 来占据实际分配的空间 ,并以单字节0xa5 结束。后续填充一定数量的单字节0xbb 作为Redzone (具体用意不明),最后还有单纯的填充字节0x5a 。 当发生重复释放,错误访问等情况时这些放置的“毒药”就会起作用,slab 也会采取措施纠正错误的操作。
有关内存毒药的字节定义可以查看 /lib/modules/$(uname -r)/build/include/linux/poison.h
其他说明:
尽管示例代码演示的是直接使用slab API 分配线性空间 ,但使用kmalloc来分配线性空间也可以配合slub(slab) debug ,因为kmalloc 实际分配的slab 对象是kmalloc-64 。不过因为无法使用kmem_cache_destroy这样的函数来释放slab cache 所以无法检测出内存泄露这样的问题。
如果操作线性空间分配与释放的层次不属于slub(slab) 而是位于伙伴系统(分页管理) 则需要开启page poison debug 。