一个内核slub内存泄漏问题分析

操作系统版本:centos7.3

内核版本:3.10.0-693

利用slabtop命令,发现有大量的kmalloc-64占用,且一直未释放,初步怀疑是内存泄漏,但不知道谁泄漏的。

通过打开kmemleak,发现有install进程大量__kmalloc且size大小刚好也为64k

(线上机器会定期调用/usr/bin/install命令,至于为何调用,那是业务的需求了。。。。。。写个死循环疯狂调用install确实能复现,该命令实际是调用了setxattr函数,你可以写个c函数疯狂调用之复现)

函数栈如下:

unreferenced object 0xffff8801c5a40000 (size 64):
comm "install", pid 15131, jiffies 4300179882 (age 217981.193s)
hex dump (first 32 bytes):
01 00 00 00 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b ....kkkkkkkkkkkk
03 00 00 00 01 00 06 00 6b 6b 6b 6b 04 00 00 00 ........kkkk....
backtrace:
[] kmemleak_alloc+0x4e/0xb0
[] __kmalloc+0xdd/0x1b0
[] posix_acl_alloc+0x1c/0x30
[] posix_acl_from_xattr+0x82/0x190
[] ext4_xattr_set_acl+0x92/0x2d0 [ext4]
[] generic_setxattr+0x68/0x80
[] __vfs_setxattr_noperm+0x65/0x1b0
[] vfs_setxattr+0xb5/0xc0
[] setxattr+0x12e/0x1c0
[] SyS_fsetxattr+0xce/0x110
[] system_call_fastpath+0x1c/0x21
[] 0xffffffffffffffff

但是还是不明白为何会泄漏,没办法,只能上gdb大法。。。

用gdb跟踪内核,成功发现泄露点位于函数:ext4_xattr_set_acl
该函数中其中一行: error = posix_acl_update_mode(inode, &mode, &acl);
继续跟进 posix_acl_update_mode函数,其中有一行:*acl = NULL,该操作会将ext4_xattr_set_acl中的acl置空;ext4_xattr_set_acl中最后部分有一行: posix_acl_release(acl); 该函数由于判断acl为NULL,导致无法执行到kfree,最终引起不断创建的acl大量堆积,内存泄露。

附上本人的patch修复:

— a/fs/ext4/acl.c 2018-04-29 01:23:50.000000000 +0800
+++ b/fs/ext4/acl.c 2019-09-17 17:48:03.094206145 +0800
@@ -404,6 +404,7 @@ ext4_xattr_set_acl(struct dentry *dentry
struct inode *inode = dentry->d_inode;
handle_t *handle;
struct posix_acl *acl;
+ struct posix_acl *p = NULL;
int error, retries = 0;
int update_mode = 0;
umode_t mode = inode->i_mode;
@@ -426,6 +427,7 @@ ext4_xattr_set_acl(struct dentry *dentry
}
} else
acl = NULL;
+ p = acl;

retry:
handle = ext4_journal_start(inode, EXT4_HT_XATTR,
@@ -452,7 +454,7 @@ out_stop:
goto retry;

release_and_out:

  • posix_acl_release(acl);
    + posix_acl_release(p);
    return error;
    }

打上补丁,问题成功解决。

 

你可能感兴趣的:(Linux内核)