nfsv3的文件占用缓存太多,使用echo 3 > /proc/sys/vm/drop_caches命令依然无法释放缓存。
占用缓存最多的inode地址为0xffff8dc8f6cb4380,找出超级块地址:
crash> struct inode.i_sb 0xffff8dc8f6cb4380
i_sb = 0xffff8df33b6a5800,在挂载信息中找不到这个超级块地址:
crash> mount | grep ffff8df33b6a5800根据以下在虚拟机中验证可知,在导出vmcore之前,环境已经执行过umount -l。
查看第一个page,可以看到private标记没有清除:
crash> kmem ffffc7b0a71abc40
PAGE PHYSICAL MAPPING INDEX CNT FLAGS
ffffc7b0a71abc40 19c6af1000 ffff8db67005d210 3773 2 17ffffc000102a error,uptodate,lru,private文件的大小为613G:
crash> struct inode.i_size 0xffff8dc8f6cb4380
i_size = 658510457197,占用缓存最多的inode地址为0xffff9d9eeca42da0,找出超级块地址:
crash> struct inode.i_sb 0xffff9d9eeca42da0
i_sb = 0xffff9dae81c1d000,在挂载信息中找不到这个超级块地址:
crash> mount | grep ffff9dae81c1d000根据以下在虚拟机中验证可知,在导出vmcore之前,环境已经执行过umount -l。
查看第一个page,可以看到private标记没有清除:
crash> kmem fffffae836418f40
PAGE PHYSICAL MAPPING INDEX CNT FLAGS
fffffae836418f40 ad9063d000 ffff9d9eeca42f10 54e470e 2 197ffffc000102a error,uptodate,lru,private文件的大小为613G:
crash> struct inode.i_size 0xffff9d9eeca42da0
i_size = 658367030190,合入补丁0001-reproduce-4.19-nfsv3-cannot-drop-cache.patch。
mount -t nfs -o vers=3 192.168.53.211:/tmp/s_test /mnt测试步骤:
echo something > something
echo something_else > something_else
echo something_else_again > something_else_again
# 为什么不直接用 echo something > /mnt/file 呢,因为用ps无法查看到echo进程
cat something > /mnt/file &
cat something_else > /mnt/file &
cat something_else_again > /mnt/file &我们看到page的flags中的private没有清除:
crash> kmem ffffea000434e4c0
PAGE PHYSICAL MAPPING INDEX CNT FLAGS
ffffea000434e4c0 10d393000 ffff8881037967f0 0 3 17ffffc000102b locked,error,uptodate,lru,private执行完echo 3 > /proc/sys/vm/drop_caches后,还是一样。
挂载:
mount -t nfs -o vers=3 192.168.53.209:/tmp/s_test /mnt编译运行:
dd if=/dev/random of=/mnt/file bs=1M count=1024 # 文件大小1G
echo 3 > /proc/sys/vm/drop_caches
gcc test.c
./a.out & # 读100M数据
cd /mnt # 进入挂载点参考《内核调试方法》在虚拟机中导出vmcore。
查看地址空间中有25728个page,每个page有4K大小,总共100M:
crash> struct address_space.nrpages 0xffff88810437dd38
nrpages = 25728, # 执行完 echo 3 > /proc/sys/vm/drop_caches 后 nrpages 为 0执行umount -l后重新再mount(挂载参数一样,路径可以不同),mount命令输出中包含inode所在的super
block,files命令也可以找到打开这个文件的进程:
crash> mount | grep ffff88812ae61800
ffff8881002ce880 ffff88812ae61800 nfs 192.168.53.209:/tmp/s_test /mnt
crash> foreach files -R mnt
PID: 923 TASK: ffff8881045bcd40 CPU: 14 COMMAND: "a.out"
ROOT: / CWD: /root
FD FILE DENTRY INODE TYPE PATH
3 ffff88800ee72a80 ffff888004e1c000 ffff88810437dbc8 REG /mnt/file执行umount -l后重新再mount(挂载参数不同),mount命令输出中不包含inode所在的super
block,files命令也找不到打开文件的进程:
crash> mount | grep ffff88812ae61800 # 找不到
crash> foreach files -R mnt # 没有找到麒麟服务器v10没有vmtouch,可以在这里下载vmtouch rpm包。
mount_point=/mnt
export size_threshold_mb=100
find ${mount_point} -type f -print0 | xargs -0 -n1 -P16 sh -c '
for file do
out=$(vmtouch -v "$file")
pages=$(echo "$out" | awk "/Resident Pages:/ {print \$3}" | cut -d/ -f1)
mb=$((pages*4096/1024/1024))
if [ "$mb" -gt ${size_threshold_mb} ]; then
echo "$file Cached_MB=${mb}"
fi
done
' sh其他相关的分析请查看以两个链接:
page设置private的地方:
nfs_inode_add_request
SetPagePrivate(req->wb_page);page清除private的地方:
nfs_write_error_remove_page
// 在这里打印出inode地址
req->wb_context->dentry->d_inode
// 出问题的代码合入补丁 22876f540bdf NFS: Don't call generic_error_remove_page() while holding locks
// 以下函数不会调用
generic_error_remove_page
truncate_inode_page
truncate_cleanup_page
do_invalidatepage
nfs_invalidate_page
nfs_wb_page_cancel
nfs_inode_remove_request
// 由于没调用generic_error_remove_page()
// 所以不会执行到这里,也不会清除private标记
ClearPagePrivate(head->wb_page);调用nfs_write_error_remove_page()的地方:
// done
nfs_async_write_error
// todo
nfs_page_async_flush // 这个在软锁问题那里分析过,也有可能有些流程会不触发软锁调用nfs_async_write_error()的地方:
// done
nfs_async_write_reschedule_io
// done
.error_cleanup调用nfs_async_write_reschedule_io()的地方:
// done,pnfs不涉及
ff_layout_reset_write
.reschedule_io调用.error_cleanup的地方:
// todo
nfs_pageio_cleanup_request
// todo
nfs_pageio_error_cleanup
// todo
nfs_pageio_resend回退补丁14bebe3c90b3 NFS: Don’t interrupt file writeout due to fatal errors。