from:http://blog.donghao.org/2013/03/20/%E4%BF%AE%E5%A4%8Dext4%E6%97%A5%E5%BF%97%EF%BC%88jbd2%EF%BC%89bug/

生产上报来了内核bug:mysql在做reset master时内核整个panic了。

DBA同学非常热心的帮忙找到了重新步骤:就是一个地雷一样的文件,只要open它,再fdatasync,kernel就panic。
从panic的代码位置看,就是 jbd2_journal_commit_transaction() 里的
J_ASSERT(journal->j_running_transaction != NULL);
判断失败触发panic

但是,为什么jbd2在没有running_transaction的时候也会提交事务?那就只能把所有唤醒kjournald2内核线程(里面调用了jbd2_journal_commit_transaction)的地方——即wake_up(&journal->j_wait_commit)处都加上trace,由于重现步骤是现成的,很快就定位到了原因:open一个文件再直接fdatasync的时候,会调用ext4_sync_file ,里面调用jbd2_log_start_commit开始提交jbd2的日志,jbd2_log_start_commit里会加锁然后调用__jbd2_log_start_commit,代码如下:

int __jbd2_log_start_commit(journal_t *journal, tid_t target)
{       /* * Are we already doing a recent enough commit?                            */if (!tid_geq(journal->j_commit_request, target)) {/** We want a new commit: OK, mark the request and wakup the        * commit thread.  We do _not_ do the commit ourselves.            */journal->j_commit_request = target;jbd_debug(1, "JBD: requesting commit %d/%d\n",                     journal->j_commit_request,journal->j_commit_sequence);wake_up(&journal->j_wait_commit);return 1;}       return 0;
}

从trace的结果看,journal->j_commit_request的值为2177452108,而target的值为0,看上去j_commit_request显然比target小,应该不会走到if判断里面去,但是实际上是走了的,因为tid_geq的实现是:

static inline int tid_geq(tid_t x, tid_t y)
{int difference = (x - y);return (difference >= 0);
}

unsigned int型2177452108减去0然后转为int型,猜猜结果是多少?等于 -2117515188 !看上去好像tid_geq的实现又罗嗦又奇怪,于是翻了一下注释,才发现,jbd2给每个transaction一个tid,这个tid是不断增长的,而它又是个unsigned int型,所以容易溢出,于是弄出来这么一个tid_geq,把0看成是比2177452108更“晚”的tid,当commit_request为2177452108而target为0时,意思是:编号2177452108的tid已经提交了,0比2177452108更“晚”,所以有必要把0号transaction给commit一下,于是唤醒kjournald2(那句wake_up)。而这一唤醒,就发现没有running_transaction,于是悲剧了。
从trace看,大部分传入__jbd2_log_start_commit的target值都不是0,看来这个0来得蹊跷,翻了一下upstream的代码,找到了Ted在去年3月份提的一个patch:

commit 688f869ce3bdc892daa993534dc6df18c95df931
Author: Theodore Ts'o
Date:   Wed Mar 16 17:16:31 2011 -0400ext4: Initialize fsync transaction ids in ext4_new_inode()When allocating a new inode, we need to make sure i_sync_tid andi_datasync_tid are initialized.  Otherwise, one or both of these twovalues could be left initialized to zero, which could potentiallyresult in BUG_ON in jbd2_journal_commit_transaction.(This could happen by having journal->commit_request getting set tozero, which could wake up the kjournald process even though there isno running transaction, which then causes a BUG_ON via theJ_ASSERT(j_ruinning_transaction != NULL) statement.Signed-off-by: "Theodore Ts'o"
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 2fd3b0e..a679a48 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -1054,6 +1054,11 @@ got:}}
+       if (ext4_handle_valid(handle)) {
+               ei->i_sync_tid = handle->h_transaction->t_tid;
+               ei->i_datasync_tid = handle->h_transaction->t_tid;
+       }
+err = ext4_mark_inode_dirty(handle, inode);if (err) {ext4_std_error(sb, err);

啊哈,就是它了,由于i_sync_tid和i_datasync_tid都没有正确赋值,所以带上了默认的0值,一路传给ext4_sync_file,而后面的__jbd2_log_start_commit又误认为0是一个要提交的新事务(其实此时还没有把当前事务挂到running_transaction上去),所以错误了。打上这个patch,再走重现步骤kernel也不panic了。

既然这么容易重现为什么其它机器上没有遇到?原因就是这个commit_request必须是一个很大的值,大到转为int型时会变为负数。我试了一下在ext4上不停的创建空文件并fdatasync之,10分钟左右commit_request才变为一百万,如果要让它到二十亿,至少还需要十四天,而线上的io压力毕竟没有人工压力测试那么大,所以几个月后commit_request才到二十亿,才触发了这个bug。
redhat最新的2.6.32-220内核是有这个问题的,大家多小心。

感谢@元云和@希羽两位同学帮忙提供了重现步骤,内核修bug,最难的就是重现,两位却直接把步骤提供出来了,真是太体贴太客气了!

======

本来想用ksplice来不重启升级内核,这样DBA就可以不重启机器修复这个bug,但是研究了一下ksplice,发现它要求加gcc参数 -ffunction-sections -fdata-sections 来编译内核,而这两个参数又和 -pg 参数冲突,而我们的kernel trace需要用到 -pg ,所以....目前无解,还没有办法用ksplice来帮助我们在线升级内核。

转载请注明转自: 斯巴达第二季 , 本文固定链接: 修复ext4日志(jbd2)bug

转载于:https://www.cnblogs.com/94cool/p/5661008.html

修复ext4日志(jbd2)bug( Ext4 文件系统有以下 Bug)相关推荐

  1. 修复被破坏了的linux文件系统分区表

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 原贴:h ...

  2. 测试使用linux日志定位BUG,Web测试中定位bug方法

    在web测试过程中,经常会遇到页面中内容或数据显示错误,甚至不显示,第一反应就是BUG,进一步了解这个BUG的问题出在那里,是测试人员需要掌握的,可以简单的使用浏览器自带开发者工具.数据库工具配合去排 ...

  3. 易优cms修复后台编辑器下拉滚动条时跳动的BUG

    eyoucms修复后台编辑器下拉滚动条时跳动的BUG 已做好更新包,发现有此BUG的朋友可以下载回去直接覆盖对应源码或直接在后台执行版本更新即可  修复编辑器跳动的BUG.zip (269.31 KB ...

  4. 魔坊APP项目-18-种植园,基于支付宝提供的沙箱测试环境开发支付接口、服务端, 处理支付结果的同步通知和异步通知、修复页面底部菜单无法被点击的BUG

    种植园 一.基于支付宝提供的沙箱测试环境开发支付接口 沙箱环境: https://openhome.alipay.com/platform/appDaily.htm?tab=info 开发文档: ht ...

  5. 解Bug之路-Druid的Bug

    2019独角兽企业重金招聘Python工程师标准>>> 解Bug之路-Druid的Bug 笔者很热衷于解决Bug,同时比较擅长(网络/协议)部分,所以经常被唤去解决一些网络IO方面的 ...

  6. 软件测试(基础)· 软件测试的生命周期 · 如何描述一个 Bug · Bug 的级别 · Bug 的生命周期 · 争执 · Bug 评审

    一.软件测试的生命周期 软件测试的生命周期 & 软件开发的生命周期 二.如何描述一个 Bug 三.如何定义 Bug 的级别 四.Bug 的生命周期 五.发生争执了怎么办? Bug 评审 一.软 ...

  7. 测试:bug的生命周期、bug的等级、如何描述一个bug

    一.Bug 的生命周期 new - open - fixing - verify - close 发现bug–>提交bug–>指派bug–>研发确认bug–>研发去修复bug– ...

  8. 软件测试中Bug的生命周期以及Bug的严重等级

    Bug的生命周期中有很多个状态,下面我就为大家比较细致的罗列出一个Bug从它被创建到关闭的过程: 1.首先当测试人员接到一个项目或产品准备测试的时候,测试人员会根据测试用例一步步的来执行用例进行简单的 ...

  9. 测试中BUG定义、测试BUG的等级划分、Bug流程以及Bug解决优先级

    一个优秀的软件测试师不仅仅能够发现软件中的bug,还能分析出bug产生的原因. 总结了一些软件测试入门必须要了解和学习的BUG基础知识,主要包括BUG定义.测试BUG的等级划分.Bug流程以及Bug解 ...

最新文章

  1. Date, TimeZone, MongoDB, java中date的时区问题
  2. 如何使用jquery判断一个元素是否含有一个指定的类(class)
  3. Hydra 8.4/8.5新增功能
  4. 使用 Java 开发 OpenCV 应用
  5. SAP Spartacus翻译 i18n - internationalization 的工作原理
  6. php 如何守护进程_PHP 如何实现守护进程
  7. 小菜编程成长记(一 面试受挫——代码无错就是好?)
  8. jquery获取父级元素、子级元素、兄弟元素
  9. 点扩散函数point spread function (PSF)
  10. 东北大学——应用数理统计——笔记
  11. android 播放assets下视频,安卓播放assets文件里视频文件相关问题分析
  12. 【Nginx之轨迹】Nginx + Lua 实现 waf Web 应用防火墙(解决 nignx 加载失败问题:LuaJIT version which is not OpenResty‘s)
  13. python大数据工程师招聘_大数据工程师是做什么的为什么招聘网上薪资都好高啊?...
  14. pytorch实现 vision_transformer
  15. java 实现电子签名_Java实现数字签名
  16. 公众号网课搜题接口系统调用搭建
  17. ytb网站报错 “您没有联网,请检查网络连接”
  18. 数字滤波器设计(高通低通)
  19. CSV文件处理——填充空值
  20. 数据科学家:21世纪最脏的工作

热门文章

  1. go的实现接口的一个小demo
  2. laravel重定向自定义显示提示消息
  3. 垃圾回收算法与实现系列-学习GC之前的准备工作
  4. 使用openvswitch网桥连接不同的network namespace
  5. Docker由浅入深
  6. GROUP BY你都不会!ROLLUP,CUBE,GROUPPING详解
  7. 算法科普:有趣的霍夫曼编码
  8. dubbo的Extension源码分析
  9. java8 Optional源码
  10. 《R语言机器学习:实用案例分析》——1.2节R的数据结构