block_dump观察Linux IO写入的具体文件

本文介绍了一种在Linux环境下用于调试程序IO状况的工具——Block Dump。它可以在全局视角之外提供具体文件的IO信息,包括进程号、inode号、文件名及磁盘设备名等。文章详细解释了其使用方法及工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.oenhan.com/block-dump-linux-io

很多情况下开发者调测程序需要在Linux下获取具体的IO的状况,目前常用的IO观察工具用vmstat和iostat,具体功能上说当然是iostat更胜一筹,在IO统计上时间点上更具体精细。但二者都是在全局上看到IO,宏观上的数据对于判断IO到哪个文件上毫无帮助,这个时候block_dump的作用就显现出来了。

一、使用方法:

需要先停掉syslog功能,因为具体IO数据要通过printk输出,如果syslog存在,则会往message产生大量IO,干扰正常结果

1
2
suse:~ # service syslog stop
Shutting down syslog services done

然后启动block_dump

1
suse:~ # echo 1 > /proc/sys/vm/block_dump

先说效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
suse:~ # dmesg | tail
dmesg(3414): dirtied inode 9594 (LC_MONETARY) on sda1
dmesg(3414): dirtied inode 9238 (LC_COLLATE) on sda1
dmesg(3414): dirtied inode 9241 (LC_TIME) on sda1
dmesg(3414): dirtied inode 9606 (LC_NUMERIC) on sda1
dmesg(3414): dirtied inode 9350 (LC_CTYPE) on sda1
kjournald(506): WRITE block 3683672 on sda1
kjournald(506): WRITE block 3683680 on sda1
kjournald(506): WRITE block 3683688 on sda1
kjournald(506): WRITE block 3683696 on sda1
kjournald(506): WRITE block 3683704 on sda1
kjournald(506): WRITE block 3683712 on sda1
kjournald(506): WRITE block 3683720 on sda1
kjournald(506): WRITE block 3683728 on sda1
kjournald(506): WRITE block 3683736 on sda1
kjournald(506): WRITE block 3683744 on sda1

通过dmesg信息可以看到IO正在写那些文件,有进程号,inode号,文件名和磁盘设备名;但每个文件写了多少呢,仅仅通过dirtied inode就看不出来了,还需要分析WRITE block,后面的数字并不是真正的块号,而是内核IO层获取的扇区号,除以8即为块号,然后根据debugfs工具的icheck和ncheck选项,就可以获取该文件系统块属于哪个具体文件,具体请google之。

二、基本原理:

block_dump的原理其实很简单,内核在IO层根据标志block_dump在IO提交给磁盘的关口卡主过关的每一个BIO,将它们的数据打出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void submit_bio( int rw, struct bio *bio)
{
      int count = bio_sectors(bio);
 
      bio->bi_rw |= rw;
 
/*
  * If it's a regular read/write or a barrier with data attached,
  * go through the normal accounting stuff before submission.
  */
      if (bio_has_data(bio) && !(rw & REQ_DISCARD)) {
          if (rw & WRITE) {
          count_vm_events(PGPGOUT, count);
      } else {
          task_io_account_read(bio->bi_size);
          count_vm_events(PGPGIN, count);
      }
 
      if (unlikely(block_dump)) {
          char b[BDEVNAME_SIZE];
          printk(KERN_DEBUG "%s(%d): %s block %Lu on %s (%u sectors)n" ,
               current->comm, task_pid_nr(current),
               (rw & WRITE) ? "WRITE" : "READ" ,
               (unsigned long long )bio->bi_sector,
               bdevname(bio->bi_bdev, b),
               count);
         }
     }
 
     generic_make_request(bio);
}

具体WRITE block块号和文件系统块号之间的对应关系在submit_bh函数中决定

1
bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);

inode的block_dump实现是通过block_dump___mark_inode_dirty搞定的,这次把关口架在inode脏数据写回的路上,把每个过关的inode信息打出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void __mark_inode_dirty( struct inode *inode, int flags)
{
 
if (unlikely(block_dump))
block_dump___mark_inode_dirty(inode);
 
}
 
static noinline void block_dump___mark_inode_dirty( struct inode *inode)
{
if (inode->i_ino || strcmp (inode->i_sb->s_id, "bdev" )) {
struct dentry *dentry;
const char *name = "?" ;
 
dentry = d_find_alias(inode);
if (dentry) {
spin_lock(&dentry->d_lock);
name = ( const char *) dentry->d_name.name;
}
printk(KERN_DEBUG
"%s(%d): dirtied inode %lu (%s) on %sn" ,
current->comm, task_pid_nr(current), inode->i_ino,
name, inode->i_sb->s_id);
if (dentry) {
spin_unlock(&dentry->d_lock);
dput(dentry);
}
  }

三、总结

1.内核由很多合适的关口来截获获取的IO信息,不改动内核,也可以用jprobe抢劫很多东西。

2.debugfs在大量的block–>file转换过程总太慢,自己用ext2fs写一个,效率应该能提高很多。


<think>好的,我现在需要帮助用户解决关于fio测试中遇到的“verify: bad magic header”错误以及hdr_fail数据的意义。首先,我需要回忆一下fio工具的基本知识,特别是数据验证相关的功能。 用户提到他们在使用fio进行测试时遇到了校验失败的问题,即使使用本地文件系统也是如此。错误信息包括“bad magic header 0 wanted acca”和“crc64 verification failed”,同时提到了hdr_fail的数据。根据引用[2],用户之前在使用fio3.7时也遇到了verify校验失败的问题,猜测是参数冲突。这可能与数据验证的配置有关。 首先,我应该解释“verify”在fio中的作用。fio的verify功能用于在IO操作后检查数据是否正确,通过写入特定的模式(比如magic头)并在读取时验证。如果magic头不匹配,就会报“bad magic header”错误。这里用户看到的“0 wanted acca”可能意味着预期的magic头是“acca”,但实际读取到的是0,说明写入的数据没有被正确记录或者读取时发生了问题。 接下来,关于hdr_fail,这应该是指验证失败时的元数据记录,比如错误的位置、预期值和实际值等。这些数据帮助用户定位哪些IO操作出现了问题,进而分析是硬件故障、配置错误还是其他原因。 然后,我需要考虑可能的原因。根据用户提供的参数,他们使用了ioengine=sync,rw=read,bs=512k。可能的问题点包括: 1. 在写入阶段没有正确生成验证数据,导致读取时无法匹配。例如,如果测试只进行了读操作而没有事先写入验证数据,那么读取的块可能包含随机数据,无法通过验证。 2. 块大小(bs=512k)与验证机制不兼容,可能某些配置下大块处理有问题。 3. 参数冲突,如引用[2]提到的,可能某些选项组合导致验证过程出错,比如同时启用了多个验证方式或者参数设置不正确。 4. 文件系统或磁盘本身的错误,比如缓存问题、坏道等,但用户已经排除了本地文件系统的问题,所以可能性较低。 解决方法方面,首先应确保在读取之前有正确的写入阶段,并且启用了验证。例如,先运行一次写测试并启用verify,然后再进行读测试。此外,检查参数是否正确,比如使用正确的ioengine,避免冲突的选项。如果使用crc64验证,可能需要确认是否支持该算法,或者尝试更换其他验证方式如md5。 最后,关于hdr_fail数据的意义,需要解释这些数据如何帮助用户定位问题,比如记录每个失败IO的偏移量、长度、预期和实际值,从而分析是特定区域的问题还是全局性的配置错误。 总结起来,我需要分步骤解释错误原因、可能的问题来源,并提供相应的解决建议,同时说明hdr_fail数据的作用,帮助用户全面理解和解决问题。</think>### Fio测试中verify错误与hdr_fail数据的解析 #### 1. **`verify: bad magic header`错误原因** 此错误表明fio在校验数据时发现**数据块的头部标识(magic header)不符合预期**。具体表现如`bad magic header 0 wanted acca`表示: - **实际读取的头部标识**是`0x0000` - **期望的头部标识**是`0xacca` **常见原因**: - **未正确初始化验证数据**:若测试仅执行读操作(如`rw=read`)而未预先写入包含校验头的数据块,读取时会因无有效标识而失败[^3]。 - **参数冲突**:当同时启用多线程、特定IO引擎(如`ioengine=sync`)或混合读写模式时,可能导致数据覆盖或校验逻辑混乱[^2]。 - **块大小不兼容**:使用`bs=512k`等大块时,若文件系统对齐或硬件缓存机制与校验算法冲突,可能破坏头部标识[^1]。 #### 2. **`hdr_fail`数据的意义** `hdr_fail`是fio在校验失败时记录的元数据,包含以下关键信息: - **失败位置**:发生错误的逻辑块地址(LBA)或文件偏移量 - **预期值与实际值**:如magic header、CRC校验码等 - **错误类型**:如头部不匹配(`bad magic`)、数据CRC校验失败(`crc64 verification failed`) 通过分析`hdr_fail`数据,可定位是**局部性错误**(如磁盘坏道)还是**全局性错误**(如参数配置问题)。 --- #### 3. **解决方案** ##### 步骤1:确保数据初始化正确 - **先写入校验数据**:执行读测试前,先运行一次**带验证的写测试**: ```bash fio --rw=write --verify=crc64 --bs=512k --ioengine=sync --filename=testfile ``` - **验证模式匹配**:写和读阶段需使用**相同的验证算法**(如`--verify=crc64`)。 ##### 步骤2:检查参数兼容性 - **避免读写模式冲突**:若需混合读写(如`rw=randrw`),需明确指定`rwmixread`比例,并确保写入阶段已生成校验数据。 - **简化配置**:暂时移除`gtod_reduce`、`iodepth`等高级参数,排除干扰。 ##### 步骤3:排查硬件/文件系统问题 - **直接IO绕过缓存**:添加`--direct=1`跳过系统缓存,直接访问磁盘。 - **更换存储介质**:将测试文件保存到不同磁盘或内存盘(如`--filename=/dev/shm/testfile`)。 --- #### 4. **操作示例** ```bash # 1. 写入带校验头的数据 fio --name=init --rw=write --bs=512k --ioengine=sync --filename=testfile --verify=crc64 --verify_dump=1 # 2. 执行带校验的读测试 fio --name=readtest --rw=read --bs=512k --ioengine=sync --filename=testfile --verify=crc64 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值