惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The GitHub Blog
The GitHub Blog
Engineering at Meta
Engineering at Meta
博客园 - 聂微东
博客园 - Franky
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
雷峰网
雷峰网
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
L
LangChain Blog
WordPress大学
WordPress大学
H
Help Net Security
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Y
Y Combinator Blog
Blog — PlanetScale
Blog — PlanetScale
MyScale Blog
MyScale Blog
IT之家
IT之家
酷 壳 – CoolShell
酷 壳 – CoolShell
罗磊的独立博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
有赞技术团队
有赞技术团队
Apple Machine Learning Research
Apple Machine Learning Research
云风的 BLOG
云风的 BLOG
博客园 - 【当耐特】
P
Proofpoint News Feed
D
DataBreaches.Net

一派胡言

吉隆坡游记 | 一派胡言 春节观鸟记:罗定篇 | 一派胡言 春节观鸟记:广州篇 | 一派胡言 观鸟改变了我 | 一派胡言 个人春秋2025 | 一派胡言 观鸟记:20251214, 20251220, 20251221, 20251225 | 一派胡言 那是傻瓜的血脉使然啊 | 一派胡言 观鸟记:Sungei Buloh 20251101 | 一派胡言 观鸟记: Tampines Eco Green 20251011 | 一派胡言 涅磐 | 一派胡言 东京也无非是这样 | 一派胡言 回忆我的中学母校 | 一派胡言 2025年Q1 漫画月旦 | 一派胡言 个人春秋2024 | 一派胡言 ebpf 札记(5): bpftrace cgroup_path 无法用作 map key | 一派胡言 回顾21世纪 | 一派胡言 聊斋笔记若干 | 一派胡言 阅微草堂中的纪晓岚 | 一派胡言 Ipoh 游记 | 一派胡言 个人春秋2023 | 一派胡言 ebpf 札记(4): 用 ebpf 侦测函数内部的状态 | 一派胡言 ebpf 札记(2): samples/bpf/cpustat(WIP) | 一派胡言 ebpf 札记(1): bpf_types.h | 一派胡言 The Linux Kernel Module Programming Guide 读书笔记 | 一派胡言 彼岸人生 | 一派胡言 同光之间的罗定——《晚清官场镜像》读书笔记 | 一派胡言 个人春秋2022 | 一派胡言 再看 Ghost in the Shell | 一派胡言 不要偷懒 | 一派胡言 个人阅读史2020 | 一派胡言
ebpf 札记(3): 一个跟踪 kernel I/O request 生命周期的脚本 ...
2023-10-04 · via 一派胡言

上周睡眠一直有问题,没有继续看 samples 里面的代码。写点别的来充数。

现在在追踪 kernel I/O request ,一个 request 被创建出来之后,会在多个函数中传递,直到被释放。 这个过程中它被那些内核函数调用?这是一个复杂的问题。幸好很多处理 request 的函数都是以 struct request* 作为入参, 这给我们一个跟踪 request 的思路。

同样的思路我还用来跟踪 nginx 里面的运行过程。

#!/usr/bin/env bpftrace

BEGIN {
  @count = 0;
}

kretprobe:blk_mq_alloc_request
{
  if (@req == 0) {
    @req = retval;
    printf("%llu, %d,  %s\n", (struct request *)@req, pid, probe);
    printf("comm: %s, kstack: \n%s\n", comm, kstack);
  }
  if (retval == @req) {
    printf("duplicated req: %d, %llu\n", pid, @req);
  }
}

kprobe:blk_*
{
  if (@req != 0) {
    if (arg1 == @req || arg0 == @req) {
      $rid = arg0;
      if (arg1 == @req) {
	$rid = arg1
      }
      printf("%llu, %s\n", (struct request *)$rid, probe);
      printf("%llu, %s\n%s\n", @req, probe, kstack);
    }
  }
}

kprobe:blk_mq_free_request
/ @req > 0 /
{
  if (@req == arg0) {
    @count += 1;
    if (@count > 3) {
      exit();
    }
    @req = 0;
  }
}

现在 bpftrace 的 kprobe section 不支持更复杂的匹配方式,倒是挺遗憾的。我想 「匹配所有 blk_ 开头的 kprobe 但是 blk_mq_free_request 除外」,但是没有找到方法实现。

我还糊了一个 python 脚本解释拿到的栈:

(root): entry_SYSCALL_64_after_hwframe
|
\-entry_SYSCALL_64_after_hwframe
 |
 \-do_syscall_64
  |
  \-__x64_sys_ioctl
   |
   \-sg_ioctl
    |
    \-sg_ioctl_common
     |
     \-sg_new_write.isra.0
      |
      \-sg_common_write.isra.0
       |
       \-kretprobe_trampoline(blk_mq_alloc_request)
       |
       \-blk_rq_map_user_iov
       |
       \-blk_account_io_start
       |
       \-blk_mq_sched_insert_request
        |
        \-blk_mq_run_hw_queue
         |
         \-__blk_mq_delay_run_hw_queue
          |
          \-__blk_mq_run_hw_queue
           |
           \-blk_mq_sched_dispatch_requests
            |
            \-__blk_mq_sched_dispatch_requests
             |
             \-blk_mq_get_driver_tag
             |
             \-blk_mq_dispatch_rq_list
              |
              \-blk_mq_start_request
              |
              \-scsi_queue_rq
               |
               \-blk_add_timer
      |
      \-blk_rq_map_user
       |
       \-blk_rq_append_bio
      |
      \-blk_execute_rq_nowait
       |
       \-blk_mq_request_bypass_insert

(root): secondary_startup_64_no_verify
|
\-secondary_startup_64_no_verify
 |
 \-start_secondary
  |
  \-cpu_startup_entry
   |
   \-do_idle
    |
    \-flush_smp_call_function_from_idle
     |
     \-do_softirq
      |
      \-__softirqentry_text_start
       |
       \-blk_done_softirq
        |
        \-blk_complete_reqs
         |
         \-scsi_complete
          |
          \-scsi_finish_command
           |
           \-scsi_io_completion
            |
            \-scsi_end_request
             |
             \-blk_stat_add
             |
             \-blk_account_io_done
             |
             \-__blk_mq_end_request
              |
              \-blk_put_request
              |
              \-sg_rq_end_io
               |
               \-blk_mq_free_request

TODO:

  1. 为什么 blk_mq_alloc_request 会重入?