当前位置: 首页 > news >正文

ftrace使用实战

诉求:遇到一个问题 echo blocked > /sys/class/block/sdb/device/state 报非法参数,想要知道根因,但是对这块内核代码不熟悉,不知道从哪里下手,那就先用ftrace看看内核调用栈,如下所示。

root@rlk:/home/rlk/rlk# echo blocked > /sys/class/block/sdb/device/state
bash: echo: write error: Invalid argument

cd /sys/kernel/debug/tracing

  • 设定跟踪的进程pid
    set_ftrace_pid

  • 查看可以设定的tracer

root@rlk:/home/rlk/rlk# cat /sys/kernel/debug/tracing/available_tracers
hwlat blk mmiotrace function_graph wakeup_dl wakeup_rt wakeup function nop
  • 设定tracer类型
root@rlk:/sys/kernel/debug/tracing# echo function_graph > current_tracer
  • 开启tracer
root@rlk:/sys/kernel/debug/tracing# echo 1 > tracing_on

写文件/sys/class/block/sdb/device/state是一个很快的过程,没有办法精准的知道什么时候把trace打开,所以只能采集相对来说比较泛的数据,为了减少一些无用的数据,可以通过写两个脚本来实现,先抓取echo running > /sys/class/block/sdb/device/state的调用栈。

write.sh

#!/bin/bash
sleep 0.3
echo running > /sys/class/block/sdb/device/state

查找进程pid命令花费的时间为0.109s

root@rlk:/home/rlk/rlk# time ps aux | grep write.sh | grep -v grep | awk '{print $2}'
5442real    0m0.109s
user    0m0.019s
sys     0m0.121s
#!/bin/bash
./write.sh &
pid=`ps aux | grep write.sh | grep -v grep | awk '{print $2}'`
echo $pidecho $pid > /sys/kernel/debug/tracing/set_ftrace_pid
echo 1 > /sys/kernel/debug/tracing/tracing_on

echo 其实就是一个打开文件,然后写文件的过程,用户态写文件会调用vfs_write,在trace日志中抓出如下调用信息。

 1)               |  do_syscall_64() {1)               |    __x64_sys_write() {1)               |      ksys_write() {1)               |        __fdget_pos() {1)   0.100 us    |          __fget_light();1)   0.291 us    |        }1)               |        vfs_write() {1)               |          rw_verify_area() {1)               |            security_file_permission() {1)               |              apparmor_file_permission() {1)               |                common_file_perm() {1)   0.100 us    |                  aa_file_perm();1)   0.290 us    |                }1)   0.481 us    |              }1)   0.682 us    |            }1)   0.872 us    |          }1)               |          __sb_start_write() {1)               |            _cond_resched() {1)   0.090 us    |              rcu_all_qs();1)   0.271 us    |            }1)   0.461 us    |          }1)               |          __vfs_write() {1)               |            kernfs_fop_write() {1)               |              __kmalloc() {1)   0.090 us    |                kmalloc_slab();1)               |                _cond_resched() {1)   0.091 us    |                  rcu_all_qs();1)   0.291 us    |                }1)   0.090 us    |                should_failslab();1)   0.330 us    |                memcg_kmem_put_cache();1)   1.513 us    |              }1)               |              __check_object_size() {1)   0.100 us    |                check_stack_object();1)   0.090 us    |                __virt_addr_valid();1)   0.491 us    |                __check_heap_object();1)   1.202 us    |              }1)               |              mutex_lock() {1)               |                _cond_resched() {1)   0.090 us    |                  rcu_all_qs();1)   0.261 us    |                }1)   0.451 us    |              }1)   0.090 us    |              kernfs_get_active();1)               |              sysfs_kf_write() {	//调用sfsfs写接口1)               |                dev_attr_store() {1)               |                  store_state_field() {1)               |                    mutex_lock() {1)               |                      _cond_resched() {1)   0.100 us    |                        rcu_all_qs();1)   0.271 us    |                      }1)   0.461 us    |                    }1)   0.200 us    |                    scsi_device_set_state(); //在这里设置了device的状态1)               |                    blk_mq_run_hw_queues() {1)               |                      blk_mq_run_hw_queue() {1)   0.390 us    |                        dd_has_work();1)   2.084 us    |                      }1)   2.775 us    |                    }1)   0.090 us    |                    mutex_unlock();1)   4.628 us    |                  }1)   5.210 us    |                }1)   6.191 us    |              }1)   0.101 us    |              kernfs_put_active();1)   0.090 us    |              mutex_unlock();1)   0.091 us    |              kfree();1) + 10.841 us   |            }1) + 11.071 us   |          }1)   0.091 us    |              kfree();1) + 10.841 us   |            }1) + 11.071 us   |          }1)   0.090 us    |          __fsnotify_parent();1)   0.090 us    |          fsnotify();1)   0.080 us    |          __sb_end_write();1) + 13.415 us   |        }1) + 14.006 us   |      }1) + 14.187 us   |    }1)   0.090 us    |    fpregs_assert_state_consistent();1) + 14.627 us   |  }

drivers/scsi/scsi_sysfs.c定义了 /sys/class/block/sdx/device/state操作函数,所有块设备相关(ll /sys/class/block/sdx/device/)DEVICE_ATTR都可以在这个文件中找到,测试的内核版本为5.4.0-26-generic


// 
static const struct {enum scsi_host_state	value;char			*name;
} shost_states[] = {{ SHOST_CREATED, "created" },{ SHOST_RUNNING, "running" },{ SHOST_CANCEL, "cancel" },{ SHOST_DEL, "deleted" },{ SHOST_RECOVERY, "recovery" },{ SHOST_CANCEL_RECOVERY, "cancel/recovery" },{ SHOST_DEL_RECOVERY, "deleted/recovery", },
};
const char *scsi_host_state_name(enum scsi_host_state state)
{int i;char *name = NULL;for (i = 0; i < ARRAY_SIZE(shost_states); i++) {if (shost_states[i].value == state) {name = shost_states[i].name;break;}}return name;
}static ssize_t
store_state_field(struct device *dev, struct device_attribute *attr,const char *buf, size_t count)
{int i, ret;struct scsi_device *sdev = to_scsi_device(dev);enum scsi_device_state state = 0;for (i = 0; i < ARRAY_SIZE(sdev_states); i++) {const int len = strlen(sdev_states[i].name);if (strncmp(sdev_states[i].name, buf, len) == 0 &&buf[len] == '\n') {state = sdev_states[i].value;break;}}switch (state) {case SDEV_RUNNING:case SDEV_OFFLINE:break;default:return -EINVAL;}mutex_lock(&sdev->state_mutex);ret = scsi_device_set_state(sdev, state);/** If the device state changes to SDEV_RUNNING, we need to run* the queue to avoid I/O hang.*/if (ret == 0 && state == SDEV_RUNNING)blk_mq_run_hw_queues(sdev->request_queue, true);mutex_unlock(&sdev->state_mutex);return ret == 0 ? count : -EINVAL;
}static ssize_t
show_state_field(struct device *dev, struct device_attribute *attr, char *buf)
{struct scsi_device *sdev = to_scsi_device(dev);const char *name = scsi_device_state_name(sdev->sdev_state);if (!name)return -EINVAL;return snprintf(buf, 20, "%s\n", name);
}static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_state_field, store_state_field);

以上问题可以在上面的代码找到答案,当前仅支持设置SDEV_RUNNING,SDEV_OFFLINE两种状态。

DEVICE_ATTR 是一个宏定义,用于在 Linux 设备驱动程序中定义设备属性。它定义了一个名为 dev_attr_ 的静态结构体变量,其中 是属性的名称。该结构体包含了属性的名称、读取和写入函数的指针,以及一些其他属性。

使用 DEVICE_ATTR 宏可以方便地定义设备属性,而无需手动编写结构体和函数。例如,以下代码定义了一个名为 my_attribute 的设备属性:

static ssize_t my_attribute_show(struct device *dev, struct device_attribute *attr, char *buf)
{// 读取属性值并将其写入缓冲区return sprintf(buf, "Hello, world!\n");
}static ssize_t my_attribute_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{// 将缓冲区中的值写入属性return count;
}DEVICE_ATTR(my_attribute, 0644, my_attribute_show, my_attribute_store);

在上面的代码中,my_attribute_show 和 my_attribute_store 分别是读取和写入函数的指针。0644 是属性的访问权限,表示该属性可以被所有者读取和写入,其他用户只能读取。最后一行使用 DEVICE_ATTR 宏定义了 my_attribute 属性。

Linux 内核的 IO 调用栈通常包括以下几个层次:

用户空间调用:应用程序通过系统调用(如 read、write、open 等)向内核发起 IO 请求。

VFS 层:VFS(Virtual File System)是 Linux 内核中的一个抽象层,它负责管理文件系统的挂载、卸载、文件名解析等操作。当应用程序发起 IO 请求时,VFS 层会根据文件系统类型和文件描述符等信息,将请求转发给相应的文件系统。

文件系统层:文件系统层负责具体的 IO 操作,包括读写磁盘、缓存管理、文件系统元数据更新等。不同的文件系统有不同的实现方式,但它们都需要遵循 VFS 层的接口规范。

块设备层:块设备层负责将 IO 请求转换为磁盘操作。它通过与硬件驱动程序的交互,将数据从内核缓冲区写入磁盘或从磁盘读取数据到内核缓冲区。

硬件驱动程序:硬件驱动程序负责与硬件设备进行通信,将 IO 请求转换为硬件操作。它通过与设备控制器的交互,将数据从内存写入磁盘或从磁盘读取数据到内存。

总的来说,Linux 内核的 IO 调用栈是一个由多个层次组成的复杂系统,每个层次都有自己的职责和实现方式。在 IO 请求的处理过程中,数据需要在不同的层次之间传递和转换,因此 IO 性能的优化需要考虑整个调用栈的影响。

相关文章:

ftrace使用实战

诉求&#xff1a;遇到一个问题 echo blocked > /sys/class/block/sdb/device/state 报非法参数&#xff0c;想要知道根因&#xff0c;但是对这块内核代码不熟悉&#xff0c;不知道从哪里下手&#xff0c;那就先用ftrace看看内核调用栈&#xff0c;如下所示。 rootrlk:/home…...

【C#进阶】C# 不安全代码

序号系列文章20【C#进阶】C# 泛型21【C#进阶】C# 匿名方法22【C#进阶】C# 多线程文章目录前言1、什么是不安全代码&#xff1f;2、如何编译不安全代码&#xff1f;3、指针类型4、指针执行的运算符和语句5、固定大小的缓冲区6、函数指针7、不安全代码的总结结语前言 &#x1f4d…...

Docker安装部署ElasticSearch

1.部署单点ElasticSearch 1.1.创建网络 因为我们还需要部署kibana容器&#xff0c;因此需要让ElasticSearch和kibana容器互联。这里先创建一个网络&#xff1a; docker network create es-net1.2.拉取镜像 考虑到ElasticSearch的兼容性&#xff0c;这里ElasticSearch、kiba…...

【新2023Q2模拟题JAVA】华为OD机试 - 快递业务站

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:快递业务站 题目 快递业务范…...

OpenCV入门(二十四)快速学会OpenCV 23 傅里叶变换

OpenCV入门&#xff08;二十四&#xff09;快速学会OpenCV 23 傅里叶变换1.傅里叶变换理论概述2.Numpy实现傅里叶变换2.1 傅里叶变换2.2 傅里叶逆变换2.3 高通滤波3.OpenCV实现傅里叶变换3.1 实现傅里叶变换3.2 实现傅里叶逆变换3.3 低通滤波作者&#xff1a;Xiou 1.傅里叶变换…...

线段树合并

前置知识&#xff1a;权值线段树&#xff0c;动态开点。 引入 我们先来看一道题&#xff1a; 永无乡包含 nnn 座岛&#xff0c;给出每座岛的重要度的排名&#xff0c;名次用 111 到 nnn 来表示。一开始有 mmm 条边连接&#xff0c;接下来有 qqq 次操作。操作分两种&#xff…...

研发效能 | DevOps如何改变游戏公司工作方式?

如果你是游戏开发者&#xff0c;那么在过去几年里&#xff0c;你可能会觉得有人给了你一把双刃剑。 整个行业不断蓬勃发展&#xff0c;但玩家的预期值也越来越高。玩家们总是希望游戏体验能够更快、更真实、更具创造性。此外&#xff0c;他们还希望能够定期推出新的游戏和更新…...

Mongo聚合和Springboot整合Mongo聚合

聚合(aggregate)是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。 语法格式:db.集合名称.aggregate({管道:{表达式}}) 常用管道如下: $group: 将集合中的⽂…...

第06章_索引的数据结构

第06章_索引的数据结构 &#x1f3e0;个人主页&#xff1a;shark-Gao &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是shark-Gao&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f389;目前状况&#xff1a;23届毕业生&#xff0c;目…...

不确定的市场,确定的增长,海尔智家2022全球再逆增

文|螳螂观察 作者| 余一 上市公司2022年年报逐渐进入密集披露期&#xff0c;在当前的年报季窗口&#xff0c;各家公司的业绩情况被高度关注。 3月30日晚&#xff0c;海尔智家发布了2022年财报。财报显示&#xff0c;2022年海尔智家实现收入2435.14亿元&#xff0c;同比增长7…...

测试老鸟手把手教你python接口自动化测试项目实战演示

目录 前言 一、项目准备 二、项目流程 三、完整代码 四、总结 前言 在进行接口自动化测试项目实战之前&#xff0c;我们需要先了解什么是接口自动化测试。接口自动化测试是通过自动化脚本模拟用户请求和服务器响应的过程&#xff0c;以检测接口是否符合预期&#xff0c;确…...

一起来学5G终端射频标准(Coherent UL-MIMO测试要求)

01 — Coherent UL-MIMO测试要求 首先什么是Coherent&#xff1f;它的英文释义是&#xff1a;&#xff08;of ideas, thoughts, argument, theory, or policy) logical and consistent&#xff0c;翻译过来就是&#xff1a;&#xff08;看法、思想、论证、理论或政策等&…...

计算广告(五)

Nobid Nobid&#xff08;在某手有时也叫MCB&#xff0c;在Facebook叫Lowest Cost&#xff09;是指广告主不用&#xff08;也不能&#xff09;对转化成本进行出价&#xff0c;而是出一个预算&#xff08;大多数是日预算&#xff09;&#xff0c;然后投放平台的目标是在时间范围…...

排序输入的高效霍夫曼编码 | 贪心算法 3

前面我们讲到了 贪心算法的哈夫曼编码规则&#xff0c;原理图如下&#xff1a; 如果我们知道给定的数组已排序&#xff08;按频率的非递减顺序&#xff09;&#xff0c;我们可以在 O(n) 时间内生成霍夫曼代码。以下是用于排序输入的 O(n) 算法。1.创建两个空队列。2.为每个唯一…...

奇异值分解(SVD)和图像压缩

在本文中&#xff0c;我将尝试解释 SVD 背后的数学及其几何意义&#xff0c;还有它在数据科学中的最常见的用法&#xff0c;图像压缩。 奇异值分解是一种常见的线性代数技术&#xff0c;可以将任意形状的矩阵分解成三个部分的乘积&#xff1a;U、S、V。原矩阵A可以表示为&#…...

Java如何从yml文件获取对象

目录一、背景二、application.yml三、ChinaPersonFactory.java四、使用示例一、背景 在 SpringBoot 中&#xff0c;我们可以使用 Value 注解从属性文件&#xff08;例如 application.yml 或 application.properties&#xff09;中获取配置信息&#xff0c;但是只能获取简单的字…...

vue使用tinymce实现富文本编辑器

安装两个插件tinymce和 tinymce/tinymce-vue npm install tinymce5.10.3 tinymce/tinymce-vue5.0.0 -S 注意&#xff1a; tinymce/tinymce-vue 是对tinymce进行vue的包装&#xff0c;主要作用当作vue组件使用-S保存到package.json文件 2. 把node_modules/tinymce下的目录&a…...

yolov4实战训练数据

1、克隆项目文件 项目Github地址&#xff1a;https://github.com/AlexeyAB/darknet 打开终端&#xff0c;克隆项目 git clone https://github.com/AlexeyAB/darknet.git无法克隆的话&#xff0c;把https修改为git git clone git://github.com/AlexeyAB/darknet.git修改Makef…...

第十四章 DOM的Diff算法与key

React使用Diff算法来比较虚拟DOM树和真实DOM树之间的差异&#xff0c;并仅更新必要的部分&#xff0c;以提高性能。key的作用是在Diff算法中帮助React确定哪些节点已更改&#xff0c;哪些节点已添加或删除。 我们以案例来说明。 使用索引值和唯一ID作为key的效果 1、使用索引…...

MySQL调优

MySQL调优常见的回答如何回答效果更好业务层的优化如果只能用mysql该如何优化代码层的优化SQL层面优化总结常见的回答 SQL层面的优化——创建索引&#xff0c;创建联合索引&#xff0c;减少回表。再有就是少使用函数查询。 回表指的是数据库根据索引&#xff08;非主键&#…...

【STM32】幻尔16路舵机控制板串口协议解析与实战编程

1. 幻尔16路舵机控制板基础认知 第一次拿到幻尔16路舵机控制板时&#xff0c;我盯着密密麻麻的接口有点发懵。这块巴掌大的绿色电路板&#xff0c;居然能同时控制16个舵机&#xff1f;经过半年多的项目实战&#xff0c;我可以负责任地说&#xff1a;这绝对是多舵机项目的开发神…...

vue3 diff算法中的-双端 Diff + 最长递增子序列 讲解

一句话总结 Vue3 Diff 双端比较&#xff08;快速复用&#xff09; 最长递增子序列&#xff08;最小移动 DOM&#xff09; 目的&#xff1a;在乱序节点中&#xff0c;只移动最少 DOM&#xff0c;实现最高效更新。1. 先搞懂&#xff1a;Vue3 对比 Vue2 差在哪&#xff1f; Vue2…...

向量化计算落地难?揭秘阿里/腾讯内部正在用的7个Java Vector API高危避坑场景

第一章&#xff1a;Java Vector API向量化计算落地的现实困境Java Vector API&#xff08;JEP 338、414、426、448&#xff09;虽在JDK 16起逐步成熟&#xff0c;但实际工程化部署仍面临多重结构性约束。其核心矛盾在于&#xff1a;API设计高度抽象&#xff0c;而底层硬件适配、…...

嵌入式STM32开发者的Gitee协作指南:如何用.gitignore管好你的Hex和工程文件

嵌入式STM32开发者的Gitee协作指南&#xff1a;如何用.gitignore管好你的Hex和工程文件 在嵌入式开发领域&#xff0c;STM32系列微控制器的项目开发往往伴随着大量中间文件的生成——从Keil MDK编译产生的.hex、.axf&#xff0c;到STM32CubeIDE自动创建的Debug文件夹&#xff0…...

抖音批量下载终极指南:免费无水印,一键搞定视频、音乐、合集

抖音批量下载终极指南&#xff1a;免费无水印&#xff0c;一键搞定视频、音乐、合集 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and brows…...

2026届必备的五大AI辅助论文助手实际效果

Ai论文网站排名&#xff08;开题报告、文献综述、降aigc率、降重综合对比&#xff09; TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 基于大语言模型与自然语言处理技术的 AI 写作软件&#xff0c;是内容生产领域新兴工具&…...

3层防护构建个人AI助手: Maid跨平台应用的隐私与体验革新

3层防护构建个人AI助手&#xff1a; Maid跨平台应用的隐私与体验革新 【免费下载链接】maid Maid is a free and open source application for interfacing with llama.cpp models locally, and with Anthropic, DeepSeek, Ollama, Mistral and OpenAI models remotely. 项目…...

OmenSuperHub终极指南:简单三步掌控暗影精灵硬件性能

OmenSuperHub终极指南&#xff1a;简单三步掌控暗影精灵硬件性能 【免费下载链接】OmenSuperHub 项目地址: https://gitcode.com/gh_mirrors/om/OmenSuperHub 你是否厌倦了官方Omen Gaming Hub的臃肿体积和烦人广告&#xff1f;是否希望获得纯净的硬件控制体验&#xf…...

利用快马平台十分钟快速构建开源项目网站原型:以openclaw101为例

作为一个经常参与开源项目的开发者&#xff0c;我深知快速验证想法的重要性。最近在尝试为开源项目openclaw101搭建网站时&#xff0c;发现InsCode(快马)平台能完美解决从零搭建的繁琐过程。下面分享如何用十分钟完成一个具备完整功能的项目网站原型。 明确需求与功能规划 首先…...

手把手教你用VSCode给Ai-WB2-12F烧录固件(含串口调试技巧)

手把手教你用VSCode给Ai-WB2-12F烧录固件&#xff08;含串口调试技巧&#xff09; 在物联网开发中&#xff0c;固件烧录是最基础也是最重要的环节之一。对于Ai-WB2-12F这款热门Wi-Fi/BLE双模模组&#xff0c;掌握高效的烧录方法能显著提升开发效率。本文将详细介绍如何利用VSC…...