Linux内核之debugfs_create_dir与debugfs_create_file实例与调用栈流程(三十二)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

1.前言

本篇目的:Linux内核之debugfs_create_dir与debugfs_create_file实例与调用栈流程

2.Linux内核之debugfs_create_dir与debugfs_create_file函数介绍

  • Linux内核提供了丰富的调试和监控功能,其中debugfs是内核调试的一个非常有用的接口。debugfs是一个虚拟文件系统,专门用于内核调试信息。开发者可以通过它来创建、读取、写入和删除文件,以此来获取和设置内核的调试信息。
  • debugfs_create_dirdebugfs_create_filedebugfs提供的两个关键函数,用于在内核中创建目录和文件。

debugfs_create_dir

  • debugfs_create_dir函数用于在debugfs文件系统中创建一个新目录。这个函数在内核中的定义大致如下:
int debugfs_create_dir(const char *name, struct dentry *parent);
  • const char *name: 要创建的目录的名称。
  • struct dentry *parent: 父目录的 dentry 结构。
    返回值是一个整数,表示操作的结果。如果成功,返回0;如果有错误,返回一个负值。
    创建目录的流程大致是:
  1. 调用debugfs_create_dir函数。
  2. 函数内部会使用kmalloc分配内存,创建一个dir_operations结构体,并设置该结构体中的必要函数指针,比如lookupfor_each_child等。
  3. 调用debugfs_create_file函数来创建这个目录下的文件。
  4. 将这个目录的dentry结构添加到父目录的dentry链表中。
  5. 将这个目录的inode结构设置为可写,并将其添加到debugfs的目录树中。

debugfs_create_file

debugfs_create_file函数用于在debugfs文件系统中创建一个新文件。这个函数在内核中的定义大致如下:

int debugfs_create_file(const char *name, umode_t mode, struct dentry *parent,
                        void *data, const struct file_operations *fops);
  • const char *name: 要创建的文件的名称。
  • umode_t mode: 文件的权限模式。
  • struct dentry *parent: 父目录的 dentry 结构。
  • void *data: 传递给文件操作的私有数据。
  • const struct file_operations *fops: 文件操作结构体,包含了文件操作的函数指针。
    返回值同debugfs_create_dir
    创建文件的流程大致是:
  1. 调用debugfs_create_file函数。
  2. 函数内部会使用kmalloc分配内存,创建一个file_operations结构体,并设置该结构体中的必要函数指针,比如readwriteopenrelease等。
  3. 调用者需要提供这个文件的file_operations结构体和私有数据。
  4. 函数将这个文件的dentry结构添加到父目录的dentry链表中。
  5. 函数创建这个文件的inode结构,并将其添加到debugfs的目录树中。
  • 通过这两个函数,开发者可以在内核中方便地创建用于调试和监控的目录和文件。这些目录和文件可以用来存储内核的调试信息,或者作为内核模块之间的通信媒介。这对于内核开发和故障排查都是非常有益的。

3.代码实例

<1>.debugfs_create_dir创建目录驱动例子

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>

#define MY_DEBUGFS_DIR "my_debugfs"
static int my_debugfs_create_dir_handler(struct dentry *parent, const char *name)
{
    int ret;
    struct dentry *debugfs_dir;

    debugfs_dir = debugfs_create_dir(name, parent);
    if IS_ERR(debugfs_dir)) {
        ret = PTR_ERR(debugfs_dir);
        printk(KERN_ERR "Failed to create debugfs directory: %d\n", ret);
        return ret;
    }

    return 0;
}

int __init my_debugfs_init(void)
{
    struct dentry *debugfs_root;

    debugfs_root = debugfs_create_dir("my_module", NULL);
    if IS_ERR(debugfs_root)) {
        printk(KERN_ERR "Failed to create debugfs root directory\n");
        return PTR_ERR(debugfs_root);
    }

    // 创建 debugfs 目录
    my_debugfs_create_dir_handler(debugfs_root, MY_DEBUGFS_DIR);
    return 0;
}

void __exit my_debugfs_exit(void)
{
}
MODULE_LICENSE("GPL");

<2>.debugfs_create_file创建文件驱动例子

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>

#define MY_DEBUGFS_FILE "my_file"
static int my_debugfs_read_handler(struct file *file, char __user *buffer, size_t length, loff_t *offset)
{
    // 实现读取逻辑
    return length;
}

static int my_debugfs_write_handler(struct file *file, const char __user *buffer, size_t length, loff_t *offset)
{
    // 实现写入逻辑
    return length;
}

static const struct file_operations my_debugfs_fops = {
    .read = my_debugfs_read_handler,
    .write = my_debugfs_write_handler,
};

int __init my_debugfs_init(void)
{
    struct dentry *debugfs_root;

    debugfs_root = debugfs_create_dir("my_module", NULL);
    if IS_ERR(debugfs_root)) {
        printk(KERN_ERR "Failed to create debugfs root directory\n");
        return PTR_ERR(debugfs_root);
    }

    // 创建 debugfs 文件
    debugfs_create_file(MY_DEBUGFS_FILE, 0644, debugfs_root, NULL, &my_debugfs_fops);
    return 0;
}

void __exit my_debugfs_exit(void)
{
}

MODULE_LICENSE("GPL");

4.debugfs_create_dir函数调用栈流程

<1>.debugfs_create_dir调用流程

private/msm-google/fs/debugfs/inode.c

struct dentry *debugfs_create_dir(const char *name, struct dentry *parent)
{
	struct dentry *dentry = start_creating(name, parent);
	struct inode *inode;

	if (IS_ERR(dentry))
		return NULL;

	inode = debugfs_get_inode(dentry->d_sb);
	if (unlikely(!inode))
		return failed_creating(dentry);

	inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
	inode->i_op = &simple_dir_inode_operations;
	inode->i_fop = &simple_dir_operations;

	/* directory inodes start off with i_nlink == 2 (for "." entry) */
	inc_nlink(inode);
	d_instantiate(dentry, inode);
	inc_nlink(d_inode(dentry->d_parent));
	fsnotify_mkdir(d_inode(dentry->d_parent), dentry);
	return end_creating(dentry);
}

simple_dir_inode_operations设置权限
simple_dir_operations回调函数设置目录

<2>.simple_dir_operations回调函数实现

const struct file_operations simple_dir_operations = {
	.open		= dcache_dir_open,
	.release	= dcache_dir_close,
	.llseek		= dcache_dir_lseek,
	.read		= generic_read_dir,
	.iterate_shared	= dcache_readdir,
	.fsync		= noop_fsync,
};

<3>.dcache_dir_open实现


int dcache_dir_open(struct inode *inode, struct file *file)
{
	file->private_data = d_alloc_cursor(file->f_path.dentry);

	return file->private_data ? 0 : -ENOMEM;
}

<4>.dcache_readdir实现

int dcache_readdir(struct file *file, struct dir_context *ctx)
{
	struct dentry *dentry = file->f_path.dentry;
	struct dentry *cursor = file->private_data;
	struct list_head *anchor = &dentry->d_subdirs;
	struct dentry *next = NULL;
	struct list_head *p;

	if (!dir_emit_dots(file, ctx))
		return 0;

	if (ctx->pos == 2)
		p = anchor;
	else
		p = &cursor->d_child;

	while ((p = scan_positives(cursor, p, 1, &next)) != anchor) {
		if (!dir_emit(ctx, next->d_name.name, next->d_name.len,
			      d_inode(next)->i_ino, dt_type(d_inode(next))))
			break;
		ctx->pos++;
	}
	spin_lock(&dentry->d_lock);
	list_move_tail(&cursor->d_child, p);
	spin_unlock(&dentry->d_lock);
	dput(next);

	return 0;
}

5.debugfs_create_file函数调用栈流程

<1>.debugfs_create_file调用流程

private/msm-google/fs/debugfs/inode.c

static struct dentry *__debugfs_create_file(const char *name, umode_t mode,
				struct dentry *parent, void *data,
				const struct file_operations *proxy_fops,
				const struct file_operations *real_fops)
{
	struct dentry *dentry;
	struct inode *inode;

	if (!(mode & S_IFMT))
		mode |= S_IFREG;
	BUG_ON(!S_ISREG(mode));
	dentry = start_creating(name, parent);

	if (IS_ERR(dentry))
		return NULL;

	inode = debugfs_get_inode(dentry->d_sb);
	if (unlikely(!inode))
		return failed_creating(dentry);

	inode->i_mode = mode;
	inode->i_private = data;

	inode->i_fop = proxy_fops;
	dentry->d_fsdata = (void *)((unsigned long)real_fops |
				DEBUGFS_FSDATA_IS_REAL_FOPS_BIT);

	d_instantiate(dentry, inode);
	fsnotify_create(d_inode(dentry->d_parent), dentry);
	return end_creating(dentry);
}

simple_pin_fs:挂载文件系统

<2>.simple_pin_fs:挂载文件系统

int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *count)
{
	struct vfsmount *mnt = NULL;
	spin_lock(&pin_fs_lock);
	if (unlikely(!*mount)) {
		spin_unlock(&pin_fs_lock);
		mnt = vfs_kern_mount(type, SB_KERNMOUNT, type->name, NULL);
		if (IS_ERR(mnt))
			return PTR_ERR(mnt);
		spin_lock(&pin_fs_lock);
		if (!*mount)
			*mount = mnt;
	}
	mntget(*mount);
	++*count;
	spin_unlock(&pin_fs_lock);
	mntput(mnt);
	return 0;
}

调用vfs_kern_mount挂载文件系统

<3>.vfs_kern_mount

struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
	struct mount *mnt;
	struct dentry *root;

	if (!type)
		return ERR_PTR(-ENODEV);

	mnt = alloc_vfsmnt(name);
	if (!mnt)
		return ERR_PTR(-ENOMEM);

	if (type->alloc_mnt_data) {
		mnt->mnt.data = type->alloc_mnt_data();
		if (!mnt->mnt.data) {
			mnt_free_id(mnt);
			free_vfsmnt(mnt);
			return ERR_PTR(-ENOMEM);
		}
	}
	if (flags & SB_KERNMOUNT)
		mnt->mnt.mnt_flags = MNT_INTERNAL;

	root = mount_fs(type, flags, name, &mnt->mnt, data);
	if (IS_ERR(root)) {
		mnt_free_id(mnt);
		free_vfsmnt(mnt);
		return ERR_CAST(root);
	}

	mnt->mnt.mnt_root = root;
	mnt->mnt.mnt_sb = root->d_sb;
	mnt->mnt_mountpoint = mnt->mnt.mnt_root;
	mnt->mnt_parent = mnt;
	lock_mount_hash();
	list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts);
	unlock_mount_hash();
	return &mnt->mnt;
}

调用:mount_fs函数

<4>.mount_fs函数

struct dentry *
mount_fs(struct file_system_type *type, int flags, const char *name, struct vfsmount *mnt, void *data)
{
	struct dentry *root;
	struct super_block *sb;
	char *secdata = NULL;
	int error = -ENOMEM;

	if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
		secdata = alloc_secdata();
		if (!secdata)
			goto out;

		error = security_sb_copy_data(data, secdata);
		if (error)
			goto out_free_secdata;
	}

	if (type->mount2)
		root = type->mount2(mnt, type, flags, name, data);
	else
		root = type->mount(type, flags, name, data);
	if (IS_ERR(root)) {
		error = PTR_ERR(root);
		goto out_free_secdata;
	}
	sb = root->d_sb;
	BUG_ON(!sb);
	WARN_ON(!sb->s_bdi);

	smp_wmb();
	sb->s_flags |= SB_BORN;

	error = security_sb_kern_mount(sb, flags, secdata);
	if (error)
		goto out_sb;
	WARN((sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "
		"negative value (%lld)\n", type->name, sb->s_maxbytes);

	up_write(&sb->s_umount);
	free_secdata(secdata);
	return root;
out_sb:
	dput(root);
	deactivate_locked_super(sb);
out_free_secdata:
	free_secdata(secdata);
out:
	return ERR_PTR(error);
}

<5>.debugfs_get_inode获取节点信息

static struct inode *debugfs_get_inode(struct super_block *sb)
{
	struct inode *inode = new_inode(sb);
	if (inode) {
		inode->i_ino = get_next_ino();
		inode->i_atime = inode->i_mtime =
			inode->i_ctime = current_time(inode);
	}
	return inode;
}

<6>.new_inode创建一个节点

struct inode *new_inode(struct super_block *sb)
{
	struct inode *inode;

	spin_lock_prefetch(&sb->s_inode_list_lock);

	inode = new_inode_pseudo(sb);
	if (inode)
		inode_sb_list_add(inode);
	return inode;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/500995.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

康耐视visionpro-CogDistancePointLineTool工具详细说明

CogDistancePointLineTool功能说明: 测量点到线的距离 备注&#xff1a;在“Geometry-Measurement”选项中的所有工具都是测量尺寸或角度工具&#xff0c;包括测量线与线 的角度、点与线的距离、圆与圆的距离等测量工具&#xff0c;工具使用的方法相似。 ①.打开工具栏&#…

正大国际:期货入门的基础知识是什么?

期货的概念很简单&#xff0c;就是一种远期合同&#xff0c;买卖双方约定交易物、交易价格与交易时间。难就难在如何理解它具备的杠杆率&#xff0c;人们是如何在这上面暴富或破产的 很多人抱有这么个错觉&#xff0c;觉得期货是一个小众市场。但其实&#xff0c;世界上所发生…

【服务端】node.js详细的配置

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

【御控物联】JavaScript JSON结构转换(5):对象To对象——转换映射方式

文章目录 一、JSON结构转换是什么&#xff1f;二、术语解释三、案例之《JSON对象 To JSON对象》四、代码实现五、在线转换工具六、技术资料 一、JSON结构转换是什么&#xff1f; JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换&#xff0…

学习鸿蒙基础(9)

目录 一、鸿蒙国际化配置 二、鸿蒙常用组件介绍 三、鸿蒙像素单位介绍 四、鸿蒙布局介绍 1、Row与Column线性布局 2、层叠布局-Stack 3、弹性布局 4、栅格布局 5、网格布局 一、鸿蒙国际化配置 base目录下为默认的string。en_US对应美国的。zh_CN对应中国的。新增一个s…

【c++】类和对象(五)赋值运算符重载

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本篇文章带大家认识赋值运算符重载&#xff0c;const成员&#xff0c;取地址及const取地址操作符重载等内容 目录 1.赋值运算符重载1.1运算符重载1.1.1特性&#…

【Python基础教程】3 . 算法的时间复杂度

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;python基础教程 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、…

首个基于SSM-Transformer混合架构,开源商业大模型Jamba

3月29日&#xff0c;知名AI研究实验室AI21在官网开源了&#xff0c;首个基于SSM-Transformer混合架构的商业大模型——Jamba。 目前&#xff0c;ChatGPT、Stable Difusion 、Lyria等产品使用的皆是Transformer架构&#xff0c;虽然在捕捉序列内长距离依赖关系、泛化能力、特征…

基于SpringBoot的农产品直卖平台

采用技术 基于SpringBoot的农产品直卖平台的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 用户功能 农产品信息 确认下单 农产品订单 购物车 商家功…

vue 组件基础

组件允许我们将 UI 划分为独立的、可重用的部分&#xff0c;并且可以对每个部分进行单独的思考。在实际应用中&#xff0c;组件常常被组织成层层嵌套的树状结构&#xff1a; 这和我们嵌套 HTML 元素的方式类似&#xff0c;Vue 实现了自己的组件模型&#xff0c;使我们可以在每…

在遭受攻击时如何有效监测服务器流量峰值——实战指南

引言 在网络安全领域&#xff0c;分布式拒绝服务攻击&#xff08;DDoS&#xff09;是一种常见的针对服务器及网络资源的恶意行为&#xff0c;它通过短时间内发送大量无效请求&#xff0c;导致服务器不堪重负而无法正常服务合法用户。当服务器遭受攻击时&#xff0c;快速识别并…

【重磅消息】HANA Cloud QRC1/2024发布了

SAP重棒消息&#xff0c;HANA Cloud于3月25日正式发布2024第一个版本QRC1 。有时候&#xff0c;我爱把它跟PostgreSQL的小版本进行类比。因为PG基本上也是一个季度&#xff0c;发布一个版本&#xff0c;但那个是小版本。看起来有些类似。如果以年份开头&#xff0c;HANA Cloud也…

ARP协议定义及工作原理

ARP的定义 地址解析协议(Address Resolution Protocol&#xff0c;ARP)&#xff1a;ARP协议可以将IPv4地址(一种逻辑地址)转换为各种网络所需的硬件地址(一种物理地址)。换句话说&#xff0c;所谓的地址解析的目标就是发现逻辑地址与物理地址的映射关系。 ARP仅用于IPv4协议&a…

원클릭으로 주류 전자상거래 플랫폼 상품 상세 데이터 수집 및 접속 시연 예제 (한국어판)

클릭 한 번으로 전자상거래 플랫폼 데이터를 캡처하는 것은 일반적으로 웹 페이지에서 정보를 자동으로 추출 할 수있는 네트워크 파충류 기술과 관련됩니다.그러나 모든 형태의 데이터 수집은 해당 웹 사이트의 사용 약관 및 개인 정보 보호 정책 및 현지 법률 및 규정을 준수…

手撕算法-跳跃游戏

描述 分析 如果某一个作为 起跳点 的格子可以跳跃的距离是 3&#xff0c;那么表示后面 3 个格子都可以作为 起跳点可以对每一个能作为 起跳点 的格子都尝试跳一次&#xff0c;把 能跳到最远的距离 不断更新如果可以一直跳到最后&#xff0c;就成功了 代码 class Solution {…

图论- 最小生成树

一、最小生成树-prim算法 1.1 最小生成树概念 一幅图可以有很多不同的生成树&#xff0c;比如下面这幅图&#xff0c;红色的边就组成了两棵不同的生成树&#xff1a; 对于加权图&#xff0c;每条边都有权重&#xff08;用最小生成树算法的现实场景中&#xff0c;图的边权重…

【测试篇】测试眼里的 BUG

文章目录 如何描述一个bug如何定义 bug 的级别BUG 的生命周期跟开发起争执怎么办&#xff08;高频面试题&#xff09; 如何描述一个bug 一个合格的bug描述应该包含以下几个部分&#xff1a; 发现问题的版本问题出现的环境错误重现的步骤预期行为的描述错误行为的描述其他&…

Python-基础部署

机器没法直接读懂我们写的代码&#xff0c;需要解释解释器作为中间的翻译&#xff0c;把代码转换成字节码在执行 安装python解释器 Download Python | Python.org 安装代码编辑器 pycharm Thank you for downloading PyCharm! 创建一个项目&#xff0c;每个项目里的文件夹…

全套医院手术麻醉系统源码 人工智能麻醉系统源码 医疗管理系统源码

全套医院手术麻醉系统源码 人工智能麻醉系统源码 医疗管理系统源码 手术麻醉临床信息系统有着完善的临床业务功能&#xff0c;能够涵盖整个围术期的工作&#xff0c;能够采集、汇总、存储、处理、展现所有的临床诊疗资料。通过该系统的实施&#xff0c;能够规范麻醉科的工作流…

【Node.JS】koa

文章目录 概述koa和express对比koa下载安装使用1.创建koa项目文件目录2. 创建koa服务3. 添加路由 koa-router4. 数据库服务 mongodb5. 添加请求参数json处理 koa-bodyparser6. 用户接口举例7.引入koa一些常用插件8.用户登录验证 koa-jwt9.webpack生产打包 来源 概述 Koa 是一个…