热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

BLOCK_DUMP观察LINUXIO写入的具体文件

很多情况下开发者调测程序需要在Linux下获取具体的IO的状况,目前常用的IO观察工具用vmstat和iostat,具体功能上说当然是iostat更胜一

很多情况下开发者调测程序需要在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);

这段代码输入形如:

1

[10489963.254731] kworker/u65:0(119773): WRITE block 3017556368 on sdm (136 sectors)

[10489963.254731] kworker/u65:0current->comm,即struct task_struct的comm字段,注释上说”executable name excluding path”;
119773task_pid_nr(current),即线程id;
WRITE表明当前block io是写操作;
3017556368bio->bi_iter.bi_sector,这个值是struct biostruct bvec_iter bi_iter中的bi_sector,表示当前block io的第一个sector号;
sdmbdevname(bio->bi_bdev, b),设备名;
136是count,当前block io的sector数;

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

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写一个,效率应该能提高很多。

block_dump观察Linux IO写入的具体文件来自于OenHan

 


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • vue使用
    关键词: ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • PHP中的单例模式与静态变量的区别及使用方法
    本文介绍了PHP中的单例模式与静态变量的区别及使用方法。在PHP中,静态变量的存活周期仅仅是每次PHP的会话周期,与Java、C++不同。静态变量在PHP中的作用域仅限于当前文件内,在函数或类中可以传递变量。本文还通过示例代码解释了静态变量在函数和类中的使用方法,并说明了静态变量的生命周期与结构体的生命周期相关联。同时,本文还介绍了静态变量在类中的使用方法,并通过示例代码展示了如何在类中使用静态变量。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
author-avatar
mobiledu2502873093
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有