一、debugfs文件系统简介

debugfs虚拟文件系统是一种内核空间与用户空间的接口,基于libfs库实现,专用于开发人员调试,便于向用户空间导出内核空间数据(当然,反方向也可以)。debugfs在linux内核版本2.6.10引入,作者是Greg Kroah-Hartman。
与procfs和sysfs不同,前者主要提供进程信息(当然后来又加入设备、内存、网络等信息,比较杂乱),后者主要提供设备信息,且有一个文件提供一个值的“规则”,是Linux通用设备模型的影射。debugfs没有类似的限制,开发者可以放入任何信息。

二、debugfs的使用

1. 挂载debugfs文件系统

要使用debugfs,需要在内核编译配置中配置CONFIG_DEBUG_FS选项,一般的发行版都会默认编译进了内核,并且将其自动挂载默认的目录(/sys/kernel/debug),可通过以下命令查看:
也可手动挂载到其它位置:

$ mkdir /debugfs
$ mount -t debugfs none /debugfs

2. 利用debugfs导出基本数据类型的变量

debugfs可以将内核中基本整数类型的变量导出为单个文件,在用户空间中可以直接对其读写(如使用cat、echo命令),只要权限允许即可。支持的类型有:u8, u16, u32, u64, size_t和 bool。其中bool类型在内核中要定义为u32类型,在用户空间中对应的文件内容则显示为Y或N。示例代码如下:

static struct dentry *root_d = debugfs_create_dir("exam_debugfs", NULL); //在debugfs根目录下创建新目录exam_debugfs,然会新建目录的目录项指针
static u8 var8;
debugfs_create_u8("var-u8", 0664, root_d, &var8); //在exam_debugfs中创建变量var8对应的文件,名为var-u8,权限为0664
static u32 varbool;
debugfs_create_bool("var-bool", 0664, root_d, &varbool); //bool变量

3. 利用debugfs导出数据块(只读)

debugfs提供的debugfs_create_blob函数可导出数据块,示例代码如下:
char buf[] = "Hello debugfs!\n";
b.data = buf;
b.size = strlen(buf) + 1;
debugfs_create_blob("blob", 0644, root_d, &b); // blob is readonly, even if 0644

没错,debugfs提供的debugfs_blob_wrapper结构所导出的数据块只能读取,不能修改。

4. 利用debugfs导出u32数组(只读)

debugfs提供的debugfs_create_u32_array函数可导出内核中u32类型的数组。示例代码如下:
u32 arr[] = {1,2,3,4,5};
debugfs_create_u32_array("array", 0664, root_d, arr, sizeof(arr)/sizeof(u32));

5. 实现可读写数据块的导出

实现并不难,只需实现struct file_operations的open、write、read方法即可。然后调用debugfs提供的debugfs_create_file即可。该方法的原型如下:

struct dentry* debugfs_create_file	(	const char * 	name,
umode_t mode,
struct dentry * parent,
void * data, // 传入的data指针会被赋值给新建文件对应inode的i_private字段
const struct file_operations * fops
)

下面,仿照struct debugfs_blob_wrapper的实现,实现struct my_blob_wrapper和my_blob_wrapper_ops,提供可读写的“blob”:

/** 自定义可读写blob **/
struct my_blob_wrapper{
void *data;
unsigned long size; // data缓冲区长度
};
static int my_blob_wrapper_open(struct inode *inode, struct file *filp)
{
filp->private_data = inode->i_private; // inode->i_private被设置为debugfs_create_file传入的data参数
return 0;
}
static ssize_t my_blob_wrapper_read(struct file *filp, char __user *user_buf, size_t count, loff_t *ppos)
{
struct my_blob_wrapper *blob = filp->private_data;
return simple_read_from_buffer(user_buf, count, ppos,
blob->data, blob->size);//此函数有libfs提供,与下面逻辑等价
// if (*ppos >= blob->size) {
// return 0;
// }
// if (*ppos + count > blob->size) {
// count = blob->size - *ppos;
// }
// if (copy_to_user(user_buf, blob->data + *ppos, count) != 0) {
// return -EFAULT;
// }
// *ppos += count;
// return count;
}
static ssize_t my_blob_wrapper_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *ppos)
{
struct my_blob_wrapper *blob = filp->private_data;
return simple_write_to_buffer(blob->data, blob->size, ppos,
user_buf, count);//此函数由libfs提供,与下面逻辑等价
// if (*ppos >= blob->size) {
// return 0;
// }
// if (*ppos + count > blob->size) {
// count = blob->size - *ppos;
// }
// if (copy_from_user(blob->data + *ppos, user_buf, count) != 0) {
// return -EFAULT;
// }
// *ppos += count;
// return count;
}
static struct file_operations my_blob_wrapper_ops = {
.owner = THIS_MODULE,
.open = my_blob_wrapper_open,
.read = my_blob_wrapper_read,
.write = my_blob_wrapper_write,
.llseek = default_llseek,//VFS提供
};
struct dentry *my_create_blob(const char *name, umode_t mode,
struct dentry *parent,
struct my_blob_wrapper *blob)
{
return debugfs_create_file(name, mode, parent, blob, &my_blob_wrapper_ops);
}
/* done */

6. 注意:

① 在debugfs中创建的文件和目录在模块退出时,并不会自动删除,可调用debugfs_remove_recursive删除整个目录,或调用debugfs_remove删除单个文件。
② u32_array在用户空间文件中显示为空格隔开的元素
③ debugfs_create_x{8,16,32,64}与debugfs_create_u{8,16,32,64}的不同在于前者显示为16进制,后者显示为10进制

三、debugfs示例完整代码

#include <linux/module.h>
#include <linux/debugfs.h>
#include <linux/fs.h> // for libfs
#include <asm-generic/uaccess.h> /** 自定义可读写blob **/
struct my_blob_wrapper{
void *data;
unsigned long size;
};
static int my_blob_wrapper_open(struct inode *inode, struct file *filp)
{
filp->private_data = inode->i_private;
return 0;
}
static ssize_t my_blob_wrapper_read(struct file *filp, char __user *user_buf, size_t count, loff_t *ppos)
{
struct my_blob_wrapper *blob = filp->private_data;
return simple_read_from_buffer(user_buf, count, ppos,
blob->data, blob->size); // from libfs
}
static ssize_t my_blob_wrapper_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *ppos)
{
struct my_blob_wrapper *blob = filp->private_data;
return simple_write_to_buffer(blob->data, blob->size, ppos,
user_buf, count);
}
static struct file_operations my_blob_wrapper_ops = {
.owner = THIS_MODULE,
.open = my_blob_wrapper_open,
.read = my_blob_wrapper_read,
.write = my_blob_wrapper_write,
.llseek = default_llseek, // from vfs
};
/* 接口函数 */
struct dentry *my_create_blob(const char *name, umode_t mode,
struct dentry *parent,
struct my_blob_wrapper *blob)
{
return debugfs_create_file(name, mode, parent, blob, &my_blob_wrapper_ops);
}
/** my_clob implementation end **/ static struct dentry *root_d;
static u8 var8;
static u16 var16;
static u32 var32;
static u32 varbool;
static char buf[] = "Hello debugfs!\n";
static struct debugfs_blob_wrapper b;
static struct my_blob_wrapper b2;
static u32 arr[] = {1,2,3,4,5}; int __init mod_init(void)
{
printk(KERN_INFO "exam_debugfs: initialing...\n");
root_d = debugfs_create_dir("exam_debugfs", NULL);
if (!root_d) {
printk(KERN_INFO "exam_debugfs: error create root dir\n");
return 1;
}
/* u{8,16,32}, bool */
debugfs_create_u8("var-u8", 0664, root_d, &var8);
debugfs_create_u16("var-u16", 0664, root_d, &var16);
debugfs_create_u32("var-u32", 0664, root_d, &var32);
debugfs_create_bool("var-bool", 0664, root_d, &varbool);
/* u32_array */
debugfs_create_u32_array("array", 0664, root_d, arr, sizeof(arr)/sizeof(u32));
/* blob_wrapper */
b.data = buf;
b.size = strlen(buf) + 1;
debugfs_create_blob("blob", 0644, root_d, &b); // blob is readonly, even if 0644
/* my_blob_wrapper */
b2.data = buf;
b2.size = strlen(buf) + 1;
my_create_blob("myblob", 0644, root_d, &b2); return 0;
}
void __exit mod_exit(void)
{
debugfs_remove_recursive(root_d);
printk(KERN_INFO "exam_debugfs: exiting...\n");
} module_init(mod_init);
module_exit(mod_exit); MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("a demo for debugfs");
MODULE_AUTHOR("rsljdkt");

四、补充:debugfs bool的实现

static ssize_t read_file_bool(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
char buf[3];
u32 *val = file->private_data; if (*val)
buf[0] = 'Y';
else
buf[0] = 'N';
buf[1] = '\n';
buf[2] = 0x00;
return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
} static ssize_t write_file_bool(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
char buf[32];
size_t buf_size;
bool bv;
u32 *val = file->private_data; buf_size = min(count, (sizeof(buf)-1));
if (copy_from_user(buf, user_buf, buf_size))
return -EFAULT; if (strtobool(buf, &bv) == 0)
*val = bv; return count;
}

参考:

Linux内核空间-用户空间通信之debugfs的更多相关文章

  1. linux 内核与用户空间通信机制netlink初探

      1.Linux进程概述 Linux中的进程间通信机制源自于Unix平台上的进程通信机制.Unix的两大分支AT&T Unix和BSD Unix在进程通信实现机制上各有所不同,前者形成了运行 ...

  2. linux 内核与用户空间通信之netlink使用方法

    转自:http://blog.csdn.net/haomcu/article/details/7371835 Linux中的进程间通信机制源自于Unix平台上的进程通信机制.Unix的两大分支AT&a ...

  3. Linux内核和用户空间通信之netlink

    1. netlink Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口. Netlink 是一种特殊的 socket,它 ...

  4. linux内核空间与用户空间信息交互方法

    linux内核空间与用户空间信息交互方法     本文作者: 康华:计算机硕士,主要从事Linux操作系统内核.Linux技术标准.计算机安全.软件测试等领域的研究与开发工作,现就职于信息产业部软件与 ...

  5. Linux 内核空间与用户空间

    本文以 32 位系统为例介绍内核空间(kernel space)和用户空间(user space). 内核空间和用户空间 对 32 位操作系统而言,它的寻址空间(虚拟地址空间,或叫线性地址空间)为 4 ...

  6. linux 用户态和内核态以及进程上下文、中断上下文 内核空间用户空间理解

    1.特权级         Intel x86架构的cpu一共有0-4四个特权级,0级最高,3级最低,ARM架构也有不同的特权级,硬件上在执行每条指令时都会对指令所具有的特权级做相应的检查.硬件已经提 ...

  7. 使用/proc实现内核与用户空间通信

    1. 前言   Linux内核空间与用户空间的通信可通过"/proc"目录的文件读写来实现,如果只是控制内核中的参数而不是传输较多数据的话,用“/proc”是很合适的.另外一种内核 ...

  8. 资源限制 ( resource limit 或 rlimit ),是 Linux 内核控制 用户 或 进程 资源占用的机制。

    ###### https://learn-linux.readthedocs.io/zh_CN/latest/administration/kernel/rlimit.html ########### ...

  9. Linux内核访问用户空间文件:get_fs()/set_fs()的使用

    测试环境:Ubuntu 14.04+Kernel 4.4.0-31 关键词:KERNEL_DS.USER_DS.get_fs().set_fs().addr_limit.access_ok. 参考代码 ...

随机推荐

  1. ORACLE模拟一个数据文件坏块并使用RMAN备份来恢复

    1.创建一个实验用的表空间并在此表空间上创建表 create tablespace blocktest datafile '/u01/oradata/bys1/blocktest.dbf' size ...

  2. vi 替换命令“找不到模式”解决

    在linux vi编辑工具中使用替换命令操作时,会出现明明有匹配查找模式的数据.却报"找不到模式"问题. 原因是vi s///替换操作缺省针对行,若要生效,则须要将光标移动到指定行 ...

  3. 【转】CTE(公用表表达式)

    本文转自:爽朗的微笑  http://www.cnblogs.com/shuangnet/archive/2013/03/22/2975929.html 公用表表达式 (CTE) 具有一个重要的优点, ...

  4. Struts2详解

     struts2框架是SSH框架集中的框架之一,是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器层(Controller)来建立 ...

  5. FreeCodeCamp:Slasher Flick

    要求: 打不死的小强! 返回一个数组被截断n个元素后还剩余的元素,截断从索引0开始. 结果: slasher([1, 2, 3], 2) 应该返回 [3]. slasher([1, 2, 3], 0) ...

  6. VC++实现生成右键菜单及添加图标

    用VC++实现弹出菜单比较简单,这里介绍其中的一种来实现一个鼠标右键弹出菜单,效果如下图所示: 步骤: 一.新建一个基于对话框的MFC应用程序-----PopMenu 二.添加一个菜单资源------ ...

  7. Hibernate之工具类HibernateUtil

    原创文章,转载请注明:Hibernate之工具类HibernateUtil  By Lucio.Yang 1.最简单的工具类,实现SessionFactory的单例共享,session的管理 pack ...

  8. JavaScript基础知识----document对象

    对象属性document.title                 //设置文档标题等价于HTML的<title>标签document.bgColor               //设 ...

  9. HTML5 总结-视频-1

    HTML5 视频 视频格式 当前,video 元素支持三种视频格式: 格式 IE Firefox Opera Chrome Safari Ogg No 3.5+ 10.5+ 5.0+ No MPEG ...

  10. PHP自练项目之发送短信内容

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...