Linux用户与内核空间交互—debugfs

Posted 为了维护世界和平_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux用户与内核空间交互—debugfs相关的知识,希望对你有一定的参考价值。

目录

简介

一、debugfs

API

二、程序源码

输出


简介

用户空间与内核的交互方式,使用copy_from_user(), copy_to_user().

除了这两种交互方式,内核还提供了其他高级的方式,对于写驱动来说很重要。有proc、sysfs、debugfs、netlink、ioctl。

本文学习debugfs

一、debugfs

在开发调试过程,通过输入cat file 文件命令,内核触发回调函数将所需要的信息提供给用户

内核配置:CONFIG_DEBUG_FS

查看是否已经挂载

# mount | grep -w debugfs
debugfs on /sys/kernel/debug type debugfs (rw,nosuid,nodev,noexec,relatime)

root@ubuntu:/sys/kernel/debug# ls
acpi   cleancache       device_component  dma_pools      error_injection     gpio          kprobes  pmc_core  regmap      sleep_time        sync     virtio-ports    zswap
bdi    clear_warn_once  devices_deferred  dri            extfrag             hid           mce      pm_genpd  regulator   split_huge_pages  tracing  vmmemctl
block  clk              dma_buf           dynamic_debug  fault_around_bytes  interconnect  opp      pwm       remoteproc  suspend_stats     ttm      wakeup_sources
cec    devfreq          dmaengine         energy_model   frontswap           iosf_sb       pinctrl  ras       sched       swiotlb           usb      x86

API

debugfs_create_dir  创建debugfs目录

debugfs_create_file 创建debugfs文件

debugfs_create_u32 自动创建内部回调函数,读写无符号32位数;其优点是不需要显示提供file_operations 结构体函数;

debugfs_create_bool 布尔类型的参数

debugfs_remove_recursive 删除文件,模块退出时没有调用此函数,继续访问debugfs文件,将引起oops错误。

二、程序源码

创建debugfs文件夹 dbgfs_simple_intf

创建两个文件,dbgfs_debug_level(显示一个值),dbgfs_show_drvctx(显示一组值)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/uaccess.h>
#include <linux/sched/signal.h>

//debugfs文件
#define OURMODNAME      "dbgfs_simple_intf"

MODULE_AUTHOR("wy");
MODULE_LICENSE("Dual MIT/GPL");
MODULE_VERSION("0.1");

/* Module parameters */
static int cause_an_oops;
module_param(cause_an_oops, int, 0644);
MODULE_PARM_DESC(cause_an_oops,

//目录
static struct dentry *gparent;

//互斥体
DEFINE_MUTEX(mtx);

//参数结构体
struct drv_ctx 
	int tx, rx, err, myword, power;
	u32 config1;
	u32 config2;
	u64 config3; /* updated to the 'jiffies' value ... */
#define MAXBYTES   128
	char oursecret[MAXBYTES];
;
static struct drv_ctx *gdrvctx;
//debug_level参数
static int debug_level;		

//文件名
#define DBGFS_FILE2	"dbgfs_debug_level"
#define DBGFS_FILE1	"dbgfs_show_drvctx"

//当read函数触发时,自动调用此函数
static ssize_t dbgfs_show_drvctx(struct file *filp, char __user *ubuf,
				 size_t count, loff_t *fpos)

	struct drv_ctx *data = (struct drv_ctx *)filp->f_inode->i_private;
#define MAXUPASS 256	// 内核的栈非常小
	char locbuf[MAXUPASS];
    
	if (mutex_lock_interruptible(&mtx))
		return -ERESTARTSYS;
    //config参数值修改
	data->config3 = jiffies;
    //打包参数值
	snprintf(locbuf, MAXUPASS - 1,
		 "prodname:%s\\n"
		 "tx:%d,rx:%d,err:%d,myword:%d,power:%d\\n"
		 "config1:0x%x,config2:0x%x,config3:0x%llx (%llu)\\n"
		 "oursecret:%s\\n",
		 OURMODNAME,
		 data->tx, data->rx, data->err, data->myword, data->power,
		 data->config1, data->config2, data->config3, data->config3,
		 data->oursecret);

	mutex_unlock(&mtx);
    //将参数值传递给user,对copy_to_user的封装
	return simple_read_from_buffer(ubuf, MAXUPASS, fpos, locbuf,
				       strlen(locbuf));


//fops read方法
static const struct file_operations dbgfs_drvctx_fops = 
	.read = dbgfs_show_drvctx,
;

//结构体内存分配,并赋初始值
static struct drv_ctx *alloc_init_drvctx(void)

	struct drv_ctx *drvctx = NULL;

	drvctx = kzalloc(sizeof(struct drv_ctx), GFP_KERNEL);
	if (!drvctx)
		return ERR_PTR(-ENOMEM);
	drvctx->config1 = 0x0;
	drvctx->config2 = 0x48524a5f;
	drvctx->config3 = jiffies;
	drvctx->power = 1;
	strncpy(drvctx->oursecret, "AhA yyy", 8);

	pr_info("allocated and init the driver context structure\\n");
	return drvctx;


//模块入口函数
static int __init debugfs_simple_intf_init(void)

	int stat = 0;
	struct dentry *file1, *file2;

    //检查是否开启debugfs
	if (!IS_ENABLED(CONFIG_DEBUG_FS)) 
		return -EINVAL;
	

    //创建目录
	gparent = debugfs_create_dir(OURMODNAME, NULL);
	if (!gparent) 
		goto out_fail_1;
	

    //创建ctx并赋初值
	gdrvctx = alloc_init_drvctx();
	if (IS_ERR(gdrvctx)) 
		goto out_fail_2;
	

    //创建文件1
	file1 = debugfs_create_file(DBGFS_FILE1, 0440, gparent, (void *)gdrvctx, &dbgfs_drvctx_fops);
	if (!file1) 
		goto out_fail_3;
	

    //创建文件2 创建的函数使用与第一个不同
    file2 = debugfs_create_u32(DBGFS_FILE2, 0644, gparent, &debug_level);
    if (!file2) 
        goto out_fail_3;
       
	return 0;

 out_fail_3:
	kfree(gdrvctx);
 out_fail_2:
	debugfs_remove_recursive(gparent);
 out_fail_1:
	return stat;


static void __exit debugfs_simple_intf_cleanup(void)

	kfree(gdrvctx);
	if (!cause_an_oops)//参数控制循环释放引起错误
		debugfs_remove_recursive(gparent);


module_init(debugfs_simple_intf_init);
module_exit(debugfs_simple_intf_cleanup);

输出

root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# ls -l
total 0
-rw-r--r-- 1 root root 0 Sep 30 01:37 dbgfs_debug_level
-r--r----- 1 root root 0 Sep 30 01:37 dbgfs_show_drvctx
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# cat dbgfs_show_drvctx 
prodname:dbgfs_simple_intf
tx:0,rx:0,err:0,myword:0,power:1
config1:0x0,config2:0x48524a5f,config3:0x10053c457 (4300457047)
oursecret:AhA yyy
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# 
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# 
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# 
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# cat dbgfs_debug_level 
0
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# echo 1 > dbgfs_debug_level 
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# cat dbgfs_debug_level 
1
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# echo 10 > dbgfs_debug_level 
root@ubuntu:/sys/kernel/debug/dbgfs_simple_intf# cat dbgfs_debug_level 
10


参考:

https://course.0voice.com/v1/course/intro?courseId=2&agentId=0

以上是关于Linux用户与内核空间交互—debugfs的主要内容,如果未能解决你的问题,请参考以下文章

Linux用户与内核空间交互—netlink

Linux用户与内核空间交互—netlink

Linux用户与内核空间交互—ioctl

Linux用户与内核空间交互—ioctl

Linux用户与内核空间交互—sysfs

Linux用户与内核空间交互—sysfs