当前位置: 首页 > news >正文

一次XFS死锁问题分析

kernel version: 5.1.0

现象

XFS 文件系统出现挂起(hung),业务进程大量处于 D 状态;多处堆栈显示卡在 xfs_igetxfs_fs_destroy_inode 路径上。

诊断过程

关键堆栈1(最早D住的进程,释放inode卡住)

  • 进程postgres
  • PID202276
  • 症状:在 xfs_fs_destroy_inode 路径上等待,向下追溯可见正在尝试读取/获取 AGF 缓冲(xfs buf),而该锁被其他事务持有。AGF保存了空闲块的信息。
#0  __schedule
#1  schedule_timeout
#2  down                      (信号量/互斥等待)
#3  down
#4  xfs_buf_lock              [xfs]
#5  xfs_buf_find              [xfs]
#6  xfs_buf_get_map           [xfs]
#7  xfs_trans_read_buf_map    [xfs]
#8  xfs_trans_read_buf_map    [xfs]   (封装层)
#9  xfs_read_agf / xfs_alloc_read_agf  [xfs]  ← 正在尝试拿 AGF buf
#10 xfs_agf_* / xfs_read_agf_*         [xfs]
#11 xfs_trans_read_buf                 [xfs]
#12 xfs_alloc_read_agf                 [xfs]
#13 xfs_btree_update / xfs_btree_del*  [xfs]
#14 xfs_inodegc_* / xfs_ifree_cluster  [xfs]
#15 xfs_inactive_ifree                 [xfs]
#16 xfs_destroy_inode                  [xfs]
#17 xfs_fs_destroy_inode               [xfs]   ← 释放 inode 主路径
#18 destroy_inode                      (VFS)
#19 evict                              (VFS)
#20 dentry_kill                        (VFS)
#21 dput                               (VFS)
#22 renameat2 / unlinkat               (syscall)
#23 __x64_sys_*                        (syscall)
#24 do_syscall_64
#25 entry_SYSCALL_64_after_hwframe

解析xfs_buf地址,顺着 xfs_buf → xfs_trans → xlog_ticket → task_struct.pid 反查,锁持有者落到下一条堆栈(关键堆栈2)。

关键堆栈2(锁的持有者,创建/iget 路径卡住)

  • 进程postgres
  • PID1894063
  • 症状:在 xfs_create / xfs_iget 路径;该事务已持有 AGF/AGI 相关日志项(从日志 item 链可见),同时在 iget 上等待 inode 资源,构成与 #1 的 ABBA 互等。
#0  __schedule
#1  schedule_timeout
#2  xfs_iget                     [xfs]     ← iget 等待(可能循环)
#3  xfs_ilock                    [xfs]
#4  xfs_iunlock                  [xfs]
#5  xfs_dir_ialloc               [xfs]
#6  xfs_ialloc                   [xfs]     (第1次/第2次分配)
#7  xfs_create                   [xfs]
#8  xfs_generic_create           [xfs]
#9  path_openat / do_open        (VFS)
#10 do_filp_open                 (VFS)
#11 do_sys_openat2
#12 do_sys_open
#13 __x64_sys_openat
#14 do_syscall_64
#15 entry_SYSCALL_64_after_hwframe

关联关系:堆栈2 持有 AGF → 堆栈1 需要 AGF;堆栈1 持有 inode/inode-bp → 堆栈2 需要 inode-bp;互相等待形成系统级挂起(xfs hung + iget 死循环)。

根因

两个进程:

  • 进程 1(销毁文件):正在删除文件、回收 inode;
  • 进程 2(创建文件):正在分配新的 inode。
    两个进程都要去改 XFS 的元数据结构,尤其是:
  • AGF(空闲块信息)
  • AGI(inode 信息)
  • inode cluster buffer(一组 inode 的缓存块)
    这几个结构之间是要上锁的。 如果 A 拿着 inode 的锁再去要 AGF 的锁, 而 B 拿着 AGF 的锁再去要 inode 的锁, 就会变成 “你等我,我等你” —— 这就是典型的死锁(deadlock)
    于是,整个 XFS 文件系统“挂死”(hung),看到的就是:
  • postgres 进程全在 D 状态;
  • xfs_iget 死循环;

修复

补丁xfs: use deferred frees for btree block freeing(commit b742d7b4f0e03...
核心思想:把“立刻释放”改为“延迟释放”。
技术上怎么实现的

  1. 把原来直接调用的
    xfs_free_extent() 改成了 xfs_free_extent_later()
    意思是: “我先把要释放的块记录到一个待办列表(deferred list)里, 等当前事务快提交时再一起处理。”
  2. 提交阶段,这些“待释放块”会被系统安全地处理:
    • 如果空间紧张,可以分多次提交;
    • 不会在持有其他锁时再去改 AGF;
    • 因此避免了死锁的条件。
  3. 同时引入了一个 xefi_agresv 参数,
    确保延迟释放的块仍然走正确的空闲空间管理逻辑(防止把 AG 专用块搞乱)。
http://www.hskmm.com/?act=detail&tid=35365

相关文章:

  • P11150 [THUWC 2018] 字胡串
  • 推荐系统与机器学习在会员服务中的应用
  • ManySpeech.MoonshineAsr 使用指南
  • 日志|JAVAWEB|maven
  • QT_基础
  • 2022 ICPC Hangzhou G and 2022 ICPC Jinan
  • C++在类定义内的函数包含static代表什么含义呢?
  • 2025/10/20~2025/?/? 做题笔记 - sb
  • 10-20 Extra-Problem 总结
  • ansible底层文件传输机制中默认模式遇到权限拒绝后启用管道模式可以得到解决
  • 10月20日记
  • Rust 编译加速的最佳实践
  • 20232304 2025-2026-1 《网络与系统攻防技术》实验三实验报告
  • 笔记本 光驱 的内部结构及用法: 应急强大的系统启动 (恢复) 光盘 (DVD+R/RW)
  • Android 源码解析系列1- Android init 进程启动流程
  • 分层图
  • 10.20总结
  • 学习相关
  • 题解:Luogu P10644 [NordicOI 2022] 能源网格 Power Grid
  • 题解:Luogu P10004 [集训队互测 2023] Permutation Counting 2
  • 题解:Luogu P2075 区间 LIS
  • 英语_阅读_2050 Space tourism_待读
  • goframe框架命令行工具gf在zsh下不能用
  • 题解:Luogu P4143 采集矿石
  • 从18w到1600w播放量,我的一点思考。
  • 扣一个细节问题
  • 10.20java作业
  • 题解:Luogu P14175 【MX-X23-T5】向死存魏
  • 题解:Luogu P14254 分割(divide)
  • 题解:Luogu P6898 [ICPC 2014 WF] Metal Processing Plant