JBD日志的定位、分析和恢复
在上一篇中,我们介绍了Ext3文件系统的日志可以看做一个文件,由JBD进行管理。自然而然引出如下这些问题:
1)如何定位ext3日志文件和查看日志文件的裸数据?
2)ext3日志文件数据在物理上是如何布局的?
3)JBD如何利用日志文件进行数据恢复?
带着这些问题,开始这次探索之旅。
JBD日志定位
首先找到ext3 日志文件的inode
- / # /dumpe2fs /dev/sda1
- dumpe2fs 1.42 (29-Nov-2011)
- Filesystem volume name: shouxian<none>
- Last mounted on: <not available>
- Filesystem UUID: 513c186a-108b-4840-ad98-aa8e8f62d4c8
- Filesystem magic number: 0xEF53
- Filesystem revision #: 1 (dynamic)
- Filesystem features: has_journal ext_attr resize_inode dir_index filetype sparse_super large_file
- Filesystem flags: signed_directory_hash
- Default mount options: user_xattr acl
- Filesystem state: clean
- Errors behavior: Continue
- Filesystem OS type: Linux
- Inode count: 513072
- Block count: 2048276
- Reserved block count: 102413
- Free blocks: 1978758
- Free inodes: 513061
- First block: 0
- Block size: 4096
- Fragment size: 4096
- Reserved GDT blocks: 500
- Blocks per group: 32768
- Fragments per group: 32768
- Inodes per group: 8144
- Inode blocks per group: 509
- Filesystem created: Sat Mar 21 11:39:13 2015
- Last mount time: n/a
- Last write time: Sat Mar 21 11:39:14 2015
- Mount count: 0
- Maximum mount count: -1
- Last checked: Sat Mar 21 11:39:13 2015
- Check interval: 0 (<none>)
- Reserved blocks uid: 0 (user root)
- Reserved blocks gid: 0 (group root)
- First inode: 11
- Inode size: 256
- Required extra isize: 28
- Desired extra isize: 28
- Journal inode: 8
- Default directory hash: half_md4
- Directory Hash Seed: 08091c3c-7a35-4f5b-8477-7af597c5eb50
- Journal backup: inode blocks
- Journal features: (none)
- Journal size: 128M
- Journal length: 32768
- Journal sequence: 0x00000001
- Journal start: 0
然后找到inode所在的数据块
- # /debugfs -R 'imap <8>' /dev/sda1
- debugfs 1.42 (29-Nov-2011)
- Inode 8 is part of block group 0
- located at block 504, offset 0x0700
根据块号、块大小和偏移,换算出inode所在数据块的物理偏移(以256B为单位)
- >>> (504*4096+0x700)/256.
- 8071.0
读出这个inode的数据
- # dd if=/dev/sda1 of=inode.8 bs=256 count=1 skip=8071
- 1+0 records in
- 1+0 records out
- 256 bytes (256B) copied, 0.000955 seconds, 261.8KB/s
- /usr/lib # hexdump inode.8
- 0000000 8081 0000 0000 0008 6258 0d55 6258 0d55
- 0000010 6258 0d55 0000 0000 0000 0100 0801 0400
- 0000020 0000 0000 0000 0000 ff01 0f00 0002 0f00
- 0000030 0102 0f00 0202 0f00 0302 0f00 0402 0f00
- 0000040 0502 0f00 0602 0f00 0702 0f00 0802 0f00
- 0000050 0902 0f00 0a02 0f00 0b02 0f00 0c06 0f00
- 0000060 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 0000080 1c00 0000 0000 0000 0000 0000 0000 0000
- 0000090 6258 0d55 0000 0000 0000 0000 0000 0000
- 00000a0 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 0000100
对照inode数据结构,找到其管理的数据块块号(蓝色标示),前12映射槽是直接映射,直接管理的数据块块号从0x0f01ff(983551)到0x0f020b,属于group 30。
- Group 30: (Blocks 983040-1015807)
- Block bitmap at 983040 (+0), Inode bitmap at 983041 (+1)
- Inode table at 983042-983550 (+2)
- 0 free blocks, 8144 free inodes, 0 directories
- Free blocks:
- Free inodes: 244321-252464
至此,终于可以dump出日志文件数据块内容。
- # dd if=/dev/sda1 of=inode.8.data bs=4096 count=12 skip=983551
- 1+0 records in
- 1+0 records out
- 4096 bytes (4.0KB) copied, 0.000942 seconds, 4.1MB/s
- 0000000 c03b 3998 0000 0004 0000 0000 0000 1000
- 0000010 0000 8000 0000 0001 0000 0002 0000 0001
- 0000020 0000 0000 0000 0000 0000 0000 0000 0000
- 0000030 513c 186a 108b 4840 ad98 aa8e 8f62 d4c8
- 0000040 0000 0001 0000 0000 0000 0000 0000 0000
- 0000050 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 0001000 c03b 3998 0000 0001 0000 0002 0000 01f8
- 0001010 0000 0008 0000 0000 0000 0000 0000 0000
- 0001020 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 0002000 0000 0000 0000 0000 6158 0d55 6158 0d55
- 0002010 6158 0d55 0000 0000 0000 0000 0000 0000
- 0002020 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 0002100 ed41 0000 0010 0000 d75d 0d55 6158 0d55
- 0002110 6158 0d55 0000 0000 0000 0300 0800 0000
- 0002120 0000 0000 0000 0000 f503 0000 0000 0000
- 0002130 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 0002180 1c00 0000 0000 0000 0000 0000 0000 0000
- 0002190 6158 0d55 0000 0000 0000 0000 0000 0000
- 00021a0 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 0002600 8081 0000 00c0 4000 6158 0d55 6158 0d55
- 0002610 6158 0d55 0000 0000 0000 0100 a88c 0000
- 0002620 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 0002650 0000 0000 0000 0000 0000 0000 fa03 0000
- 0002660 0000 0000 0000 0000 0000 0000 0100 0000
- 0002670 0000 0000 0000 0000 0000 0000 0000 0000
- 0002680 1c00 0000 0000 0000 0000 0000 0000 0000
- 0002690 6158 0d55 0000 0000 0000 0000 0000 0000
- 00026a0 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 0002700 8081 0000 0000 0008 6258 0d55 6258 0d55
- 0002710 6258 0d55 0000 0000 0000 0100 0801 0400
- 0002720 0000 0000 0000 0000 ff01 0f00 0002 0f00
- 0002730 0102 0f00 0202 0f00 0302 0f00 0402 0f00
- 0002740 0502 0f00 0602 0f00 0702 0f00 0802 0f00
- 0002750 0902 0f00 0a02 0f00 0b02 0f00 0c06 0f00
- 0002760 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 0002780 1c00 0000 0000 0000 0000 0000 0000 0000
- 0002790 6258 0d55 0000 0000 0000 0000 0000 0000
- 00027a0 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 0002a00 c041 0000 0040 0000 6158 0d55 6158 0d55
- 0002a10 6158 0d55 0000 0000 0000 0200 2000 0000
- 0002a20 0000 0000 0000 0000 f603 0000 f703 0000
- 0002a30 f803 0000 f903 0000 0000 0000 0000 0000
- 0002a40 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 0002a80 1c00 0000 0000 0000 0000 0000 0000 0000
- 0002a90 6158 0d55 0000 0000 0000 0000 0000 0000
- 0002aa0 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 0003000 c03b 3998 0000 0002 0000 0002 0000 0000
- 0003010 0000 0000 0000 0000 0000 0000 0000 0000
- *
- 以下略
JBD日志分析
0000000 -- 0001000 数据块:
日志超级块段,存储的是journal_superblock_t数据,从中可以看出块类型为JFS_SUPERBLOCK_V2(4),日志块大小: 0x1000; 日志块个数: 0x8000。进而可以计算出日志总大小为:0x1000 * 0x8000 = 128M。
- /*
- * Standard header for all descriptor blocks:
- */
- typedef struct journal_header_s
- {
- __be32 h_magic;
- __be32 h_blocktype;
- __be32 h_sequence;
- } journal_header_t;
- /*
- * The journal superblock. All fields are in big-endian byte order.
- */
- typedef struct journal_superblock_s
- {
- /* 0x0000 */
- journal_header_t s_header;
- /* 0x000C */
- /* Static information describing the journal */
- __be32 s_blocksize; /* journal device blocksize */
- __be32 s_maxlen; /* total blocks in journal file */
- __be32 s_first; /* first block of log information */
- /* 0x0018 */
- /* Dynamic information describing the current state of the log */
- __be32 s_sequence; /* first commit ID expected in log */
- __be32 s_start; /* blocknr of start of log */
- /* 0x0020 */
- /* Error value, as set by journal_abort(). */
- __be32 s_errno;
- /* 0x0024 */
- /* Remaining fields are only valid in a version-2 superblock */
- __be32 s_feature_compat; /* compatible feature set */
- __be32 s_feature_incompat; /* incompatible feature set */
- __be32 s_feature_ro_compat; /* readonly-compatible feature set */
- /* 0x0030 */
- __u8 s_uuid[16]; /* 128-bit uuid for journal */
- /* 0x0040 */
- __be32 s_nr_users; /* Nr of filesystems sharing log */
- __be32 s_dynsuper; /* Blocknr of dynamic superblock copy*/
- /* 0x0048 */
- __be32 s_max_transaction; /* Limit of journal blocks per trans.*/
- __be32 s_max_trans_data; /* Limit of data blocks per trans. */
- /* 0x0050 */
- __u32 s_padding[44];
- /* 0x0100 */
- __u8 s_users[16*48]; /* ids of all fs'es sharing the log */
- /* 0x0400 */
- } journal_superblock_t;
0001000 -- 0002000 数据块:
日志描述符块,开头存储的是journal_header_t,然后紧跟着journal_block_tag_t数据表。从中可以看出块类型为JFS_DESCRIPTOR_BLOCK(1), transaction id为2。只有一个tag,tag的block号为0x1f8, flag为JFS_FLAG_LAST_TAG(8)。此外,第一个tag后面会额外跟着一个16个字节的j_uuid,具有相同uuid的tag以JFS_FLAG_SAME_UUID(2)标示,最后一个tag flag以JFS_FLAG_LAST_TAG置位标示。
- /*
- * The block tag: used to describe a single buffer in the journal
- */
- typedef struct journal_block_tag_s
- {
- __be32 t_blocknr; /* The on-disk block number */
- __be32 t_flags; /* See below */
- } journal_block_tag_t;
0002000 -- 0003000 数据块:
元数据块,紧跟着DESCRIPTOR_BLOCK,一个tag对应一个块,块的个数由tag的个数决定。此示例中只有一个tag,所以只有一个数据块。这个块中的数据,在日志恢复或journal load时会写到存储设备文件系统的真实物理块(即tag的t_blocknr)上。
0003000 -- 0004000 数据块:
日志提交块。表示一个完整的transaction。从中可以看出块类型为JFS_COMMIT_BLOCK(2), transaction id为2,与前面的日志描述块匹配。
JBD日志恢复
如果文件系统崩溃或者unclean umount 重启造成文件系统损坏,当再次mount日志文件系统后,ext3文件系统会根据JBD日志文件进行日志恢复动作。
JBD的日志恢复分3个阶段:
第一个阶段PASS_SCAN:
完成日志一致性检查,查找日志尾部,获取start_transaction和end_transaction ID等信息;
第二个阶段PASS_REVOKE:
搜索revoke块(revoke块中存储需要丢弃的块号),统计nr_revokes个数,构造revoke块hash表;避免回放revoke块,破坏数据块内容,造成文件系统损坏;
第三个阶段PASS_REPLAY:
对日志中满足条件的数据块进行回放;拷贝日志中的数据块到文件系统真实位置:
1)块号不在revoke块hash表中;
2)此数据块所在的描述块commit ID大于revoke块的commit ID,即在revoke块后面;
然后设置日志的j_transaction_sequence为下个transaction ID,保证日志中已存在的日志记录都无效;
清空revoke块列表,同步存储设备,至此ext3日志完成恢复。
--EOF--
JBD日志的定位、分析和恢复的更多相关文章
- SpringCloud微服务实战——搭建企业级开发框架(三十八):搭建ELK日志采集与分析系统
一套好的日志分析系统可以详细记录系统的运行情况,方便我们定位分析系统性能瓶颈.查找定位系统问题.上一篇说明了日志的多种业务场景以及日志记录的实现方式,那么日志记录下来,相关人员就需要对日志数据进行 ...
- hadoop实战 -- 网站日志KPI指标分析
本项目分析apache服务器产生的日志,分析pv.独立ip数和跳出率等指标.其实这些指标在第三方系统中都可以检测到,在生产环境中通常用来分析用户交易等核心数据,此处只是用于演示说明日志数据的分析流程. ...
- MYSQL启用日志,查看日志,利用mysqlbinlog工具恢复MySQL数据库【转载】
转自 MYSQL启用日志,查看日志,利用mysqlbinlog工具恢复MySQL数据库 - _安静 - 博客园http://www.cnblogs.com/xionghui/archive/2012/ ...
- LCD 显示异常定位分析方法
第一种情况: 进入kernel或android 后,如果LCM图像示异常,可以通过如下步骤来判断问题出现在哪个层面. step1:通过DMMS截图,来判断上面刷到LCM的数据是否有问题. 若DMMS获 ...
- 【原创】大叔案例分享(4)定位分析--见证scala的强大
一 场景分析 定位分析广泛应用,比如室外基站定位,室内蓝牙beacon定位,室内wifi探针定位等,实现方式是三点定位 Trilateration 理想情况 这种理想情况要求3个基站‘同时’采集‘准确 ...
- vsftp日志xferlog格式分析
vsftp日志xferlog格式分析 [日期:2014-06-25] 来源:Linux社区 作者:Linux [字体:大 中 小] 1.开始vsftp记录日志.修改/etc/vsftpd/vsf ...
- odoo开发笔记 -- 后台日志输出及分析
odoo开发笔记 -- 后台日志输出及分析 附:日志分析软件
- 说说openjdk及G1回收器日志内容详细分析
谈谈openjdk: 在正式往下学习JVM之前,这里谈谈openjdk这个网站,这个在学习java并发时也用过它来分析过锁的底层实现,如:https://www.cnblogs.com/webor20 ...
- Linux下单机部署ELK日志收集、分析环境
一.ELK简介 ELK是elastic 公司旗下三款产品ElasticSearch .Logstash .Kibana的首字母组合,主要用于日志收集.分析与报表展示. ELK Stack包含:Elas ...
随机推荐
- sobel算子的一些细节
1. 形式 Gy 上下颠倒的 (*A表示卷积图像,忽略先): 看得出来,sobel算子感觉并不统一,特别是方向,我们知道matlab的图像格式是,x轴从左到右,y轴从上到下,原点在左上角. 所以,第二 ...
- yaf学习资料
yaf学习资料 文档 鸟哥的官方文档 Yaf框架结合PHPUnit的集成测试 php yaf框架扩展实践六--单元测试.计划任务.第三方库等 php yaf框架扩展实践一--配置篇 yaf实战例子 y ...
- javaweb学习总结(五)——Servlet开发(一)
一.Servlet简介 Servlet是sun公司提供的一门用于开发动态web资源的技术. Sun公司在其API中提供了一个servlet接口,用户若想用发一个动态web资源(即开发一个Java程序向 ...
- SQLite的时候判断语句是否纯在:出现RuntimeException
写SQLite的时候判断语句是否纯在: public boolean exist(long id) { String filter = FRIEND_KEY_ID + "=" + ...
- PhpStorm 8.x/9.x 快捷键设置/个性化设置,如何多项目共存?如何更换主题?
1."自定义"常用快捷键(设置成跟Eclipse差不多) 按照路径:File -> Settings -> Appearance & Behavior -> ...
- Github.com的Git和TortoiseGit图文教程
图文介绍Windows系统下使用 Github账户 + msysgit + TortoiseGit 进行文件管理的方法. 安装 安装mysysgit 下载地址:msysgit 安装过程: 0.启动 1 ...
- PHP数组函数: array_walk()
定义和用法 array_walk() 函数对数组中的每个元素应用回调函数.如果成功则返回 TRUE,否则返回 FALSE. 典型情况下 function 接受两个参数.array 参数的值作为第一个, ...
- 关于 JSONP跨域示例
1.脚本文件Jsonp,代码如下: $(function () { TestJsonP(); function TestJsonP() { var xhrurl = 'http://localhost ...
- jQuery源码笔记(二):定义了一些变量和函数 jQuery = function(){}
笔记(二)也分为三部分: 一. 介绍: 注释说明:v2.0.3版本.Sizzle选择器.MIT软件许可注释中的#的信息索引.查询地址(英文版)匿名函数自执行:window参数及undefined参数意 ...
- 【GWAS文献解读】疟原虫青蒿素抗药性的全基因组关联分析
英文名:Genetic architecture of artemisinin-resistant Plasmodium falciparum 中文名:疟原虫青蒿素抗药性的全基因组关联分析 期刊:Na ...