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

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;
}

相关文章:

  • 每日一题 --- 四数相加 II[力扣][Go]
  • 星闪BLE与蓝牙
  • maven 依赖机制
  • 鸿蒙系统,作为华为自主研发的一款全新操作系统
  • 要将Oracle中的表从按年分区转换为按月分区,并且保持数据不变,不锁表
  • 程序汪若依微服务华为云Linux部署保姆教程
  • QGraphicsView实现图片放大、缩小、鼠标拖动、以鼠标点放大缩小
  • SpringBoot集成Solr全文检索
  • 非隔离恒压AC-DC电源IC:SM7035P
  • 服务器被挖矿了怎么办,实战清退
  • RK3568-开启ptp服务
  • Docker常见软件部署2
  • 简单了解原型模式
  • C++——vector类及其模拟实现
  • 专业130+总分410+西南交通大学924信号与系统考研经验西南交大电子信息通信工程,真题,大纲,参考书。
  • 【echart】数据可视化+vue+vite遇到问题
  • 【python】数据库操作
  • buy me a btc 使用数字货币进行打赏赞助
  • 算法打卡day28|贪心算法篇02|Leetcode 122.买卖股票的最佳时机 II、55. 跳跃游戏、45.跳跃游戏 II
  • Git--08--Git分支合并操作
  • 追光|铁皮房、土操场,这有一座“筑梦”摔跤馆
  • 九家企业与上海静安集中签约,投资额超10亿元
  • 阿森纳被打得毫无脾气,回天无力的阿尔特塔只剩嘴硬
  • 司法部:持续规范行政执法行为,加快制定行政执法监督条例
  • 全国首例在沪完成,这项近视治疗手术不到10秒
  • 金融监管总局将推出8项增量政策:涉房地产金融、险资入市、稳外贸等