Coding:小写一个debugfs
Coding:小写一个debugfs
上一次整活还是在上一个月,写了一个简单的module并且熟悉了module的挂载查看和卸载。这一次我们自然玩一个大的,就是利用linux的debugfs API写一个调试文件系统。
事实上,底层的API全写好了,我们就是简单的调调API就成的事情!
事先检查
第一步是检查我们当前的内核是否支持debugfs调试:
zcat /proc/config.gz | grep DEBUG_FS
# CONFIG_XEN_DEBUG_FS is not set
CONFIG_BLK_DEBUG_FS=y
CONFIG_BLK_DEBUG_FS_ZONED=y
# CONFIG_SCSI_SNIC_DEBUG_FS is not set
# CONFIG_SCSI_LPFC_DEBUG_FS is not set
# CONFIG_USB_GADGET_DEBUG_FS is not set
# CONFIG_OCFS2_DEBUG_FS is not set
CONFIG_DEBUG_FS=y
CONFIG_DEBUG_FS_ALLOW_ALL=y
# CONFIG_DEBUG_FS_DISALLOW_MOUNT is not set
# CONFIG_DEBUG_FS_ALLOW_NONE is not set
在这里,我们是要查看的是:CONFIG_DEBUG_FS=y
,在这件事情上,如果是n,说明当前内核是不支持调试文件系统的,这就要求我们另外编译内核(打开这个开关),安装并进入内核才行。这里不再赘述如何自定义内核了。
开干
我们的文件系统有自己的一套fops,这里,也不是意外的。和我们对文件系统自身的认知,我们知道文件系统实际上就是提供一种对目标设备一套被抽象出来的访问读写等若干操作的句柄。所以我们所需要做的就是自己实现这一套句柄。显然我们需要实现的有打开文件 ,读文件以及写文件,这是最基本的!
我们的文件系统将会以模块的方式动态的加载到内核。所以这就要求我们需要先掌握学习如何编写模块的知识,这个在我之前的博客里有所提到。关于如何在Arch Linux上编写自己的第一个module_archlinux modules-CSDN博客
各位看官之前并没有了解到这方面的知识,可以阅读我上面所写的博客等掌握这个知识之后,再进行下一步的实践。
现在,我们沿用写模块的Makefile:
obj-m:= charlie.o
pwd:= $(shell pwd)
ker-ver:= $(shell uname -r)
KDIR:= /lib/modules/$(ker-ver)/build
# 下面这一行是用来调试的
# ccflags-y += -DDEBUG -g -ggdb -gdwarf-4 -Og \
-Wall -fno-omit-frame-pointer -fvar-tracking-assignments
all:
make -C $(KDIR) M=$(pwd) modules # 先调整一下目录,用人家的Makefile
clean:
rm -rf *.o .* .cmd *.ko *.mod.c .tmp_versions *.order *.symvers *.mod写代码!
撸代码
我们首先需要引入写模块和调试文件系统的基本头文件。
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/errno.h>
#include <linux/types.h>
然后完成读写,打开等基本操作。
static int charlie_fs_open(struct inode* inode, struct file* pfile)
{
// 函数是打开某一个文件,准备进行读或者写。
printk("Charlie_filesystem_open\n");
pfile->private_data = inode->i_private;
return 0;
}
static ssize_t charlie_fs_read(struct file* pFile, char __user *buf, size_t cnt, loff_t* offp)
{
// 函数完成的任务是对传入进来的内存块进行存入buf里。
int retval = 0;
if((*offp + cnt) > 512)
cnt = 512 - *offp;
// printk函数主要是向控制台打印一些控制信息,这个信息需要通过这条指令进行查看: sudo dmesg
printk("Received read request! count:%ld, offset:%lld\n", cnt, *offp);
if(copy_to_user(buf, charlie_buf + *offp, cnt)){
// 警告!
pr_warn("Oh no, failed to copy to user! count is %ld\n", cnt);
retval = -EFAULT;
goto out;
}
*offp += cnt;
retval = cnt;
out:
return retval;
}
static ssize_t charlie_fs_write(struct file* pFile, const char __user *buf, size_t cnt, loff_t* offp)
{
// 函数完成的任务是向文件块进行写入。
int retval;
pr_info("Write request is here: count: %ld, offset:%lld\n", cnt, *offp);
if(*offp > 512)
return 0;
if((*offp + cnt) > 512)
cnt = 512 - *offp;
if(copy_from_user(charlie_buf + *offp, (const void*)buf, cnt)){
pr_warn("Oh no, failed to copy from user! count is %ld\n", cnt);
retval = -EFAULT;
goto out;
}
*offp += cnt;
retval = cnt;
out:
return retval;
}
关于这里的几个所用到的函数都是什么意思,各位看官可自行百度更加详细的说明!
我们的文件系统是通过模块进行载入和卸载的,这就意味着我们仍然需要写初始化函数和析构函数。我们所做的就是要在初始化的时候完成对文件系统处理函数的注册。即在卸载文件系统的时候,移除我们在初始化时进行注册的相关函数。
// 句柄
struct file_operations charlie_fs_fops = {
.owner = THIS_MODULE,
.read = charlie_fs_read,
.write = charlie_fs_write,
.open = charlie_fs_open
};
// 模块的初始化
static int __init charlie_debug_fs_init(void)
{
pr_info("The module is initing...");
charlie_dir = debugfs_create_dir("Charliedir", NULL);
if(!charlie_dir){
pr_crit("Failing shit! can not create any dir at all!");
goto failed;
}
static struct dentry* sub_charlie_dir;
sub_charlie_dir = debugfs_create_dir("CharlieSubDir", charlie_dir);
if(!sub_charlie_dir){
pr_crit("Failing shit! can not create any sub dir at all!");
goto failed;
}
struct dentry* filent = debugfs_create_file("Charlie", 0644, sub_charlie_dir, NULL, &charlie_fs_fops);
if(!filent){
pr_err("Can not create file!");
goto failed;
}
pr_info("Init finish!");
return 0;
failed:
return -ENOENT;
}
// 模块的析构函数
static void __exit charlie_debug_fs_exit(void)
{
pr_info("Safe quit! begin");
debugfs_remove_recursive(charlie_dir);
pr_info("Safe quit! end");
}
module_init(charlie_debug_fs_init);
module_exit(charlie_debug_fs_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Charliechen");
到这里我们保存,然后make一下
make -C /lib/modules/6.9.7-arch1-1/build M=/home/Charliechen/Works/opearte_system/module/test2 modules
make[1]: Entering directory '/usr/lib/modules/6.9.7-arch1-1/build'
CC [M] /home/Charliechen/Works/opearte_system/module/test2/charlie.o
MODPOST /home/Charliechen/Works/opearte_system/module/test2/Module.symvers
CC [M] /home/Charliechen/Works/opearte_system/module/test2/charlie.mod.o
LD [M] /home/Charliechen/Works/opearte_system/module/test2/charlie.ko
BTF [M] /home/Charliechen/Works/opearte_system/module/test2/charlie.ko
make[1]: Leaving directory '/usr/lib/modules/6.9.7-arch1-1/build'
➜ sudo insmod charlie.ko && lsmod | grep charlie
[sudo] password for Charliechen:
charlie 16384 0
看到我们的模块已经被正确的挂载!下一步,则是测试我们写的一系列功能。
➜ sudo ls /sys/kernel/debug/ | grep Charliedir
Charliedir
➜ sudo ls /sys/kernel/debug/Charliedir
CharlieSubDir
➜ sudo ls /sys/kernel/debug/Charliedir/CharlieSubDir
Charlie
➜ su
Password:
[root@ArchLinux test2]# ls
charlie.c charlie.ko charlie.mod charlie.mod.c charlie.mod.o charlie.o Makefile modules.order Module.symvers
[root@ArchLinux test2]# sudo insmod charlie.ko && lsmod | grep charlie
charlie 16384 0
[root@ArchLinux test2]# echo 114514 > /sys/kernel/debug/Charliedir/CharlieSubDir/Charlie
[root@ArchLinux test2]# dmesg | tail -4
[18109.769088] The module is initing...
[18109.769097] Init finish!
[18117.722104] Charlie_filesystem_open
[18117.722177] Write request is here: count: 7, offset:0
[root@ArchLinux test2]# cat /sys/kernel/debug/Charliedir/CharlieSubDir/Charlie
114514
[root@ArchLinux test2]# dmesg | tail -7
[18109.769088] The module is initing...
[18109.769097] Init finish!
[18117.722104] Charlie_filesystem_open
[18117.722177] Write request is here: count: 7, offset:0
[18147.692623] Charlie_filesystem_open
[18147.692645] Received read request! count:512, offset:0
[18147.692666] Received read request! count:0, offset:512
[root@ArchLinux test2]# rmmod charlie.ko
[root@ArchLinux test2]# dmesg | tail -8
[18109.769088] The module is initing...
[18109.769097] Init finish!
[18117.722104] Charlie_filesystem_open
[18117.722177] Write request is here: count: 7, offset:0
[18147.692623] Charlie_filesystem_open
[18147.692645] Received read request! count:512, offset:0
[18147.692666] Received read request! count:0, offset:512
[18165.395570] Safe quit! begin
完成!
Coding:小写一个debugfs的更多相关文章
- Coding girl一个老程序员谈到的一个女程序员的故事
因为有人说我给一个女程序员的建议不靠谱,我不服,因为我的工作经历中的一些女程序员都很不错,比那些男程序员都强,所以,我在新浪微博和twitter上征集女程序员的故事和想法,这两天来,我收到了好几封邮件 ...
- GitHub & Bitbucket & GitLab & Coding 的对比分析
目前基于 Git 做版本控制的代码托管平台有很多种,比较流行的服务有 Github.Bitbucket. GitLab. Coding,他们各自有什么特点,个人使用者和开发团队又该如何选择? 在这篇文 ...
- sublime 插件zen coding
sublime的插件Zen Coding是一个编写html的神器,现在已经更名为Emmet了. 在sublime中的package需要搜索的是Emmet 相关网站: 官网 Zen Coding: 一种 ...
- Emmet(前身是zen coding)介绍和使用
Zen coding - 一种快速编写HTML/CSS代码的方法.它使用仿CSS选择器的语法来快速开发HTML和CSS - 由Sergey Chikuyonok开发. 现在它改名为了Emmet,并且搭 ...
- 关于Zen Coding:css,html缩写
zen coding 是一个俄罗斯人写的编辑器(支持大部分现下流行的编辑器)插件,其安装也是非常简单,只要安装插件,然后在项目中拷贝js文件就可以.像Webstorm6.0.2中已经包含这样的插件.什 ...
- Zen Coding css,html缩写替换大观 快速写出html,css
阅读本文,先仔细阅读网站文章. Zen Coding 快速编写HTML/CSS代码的实现 复制代码 代码如下:E 元素名称(div, p); E#id 使用id的元素(div#content, p#i ...
- Zen Coding 快速编写HTML/CSS代码的实现
在本文中我们将展示一种新的使用仿CSS选择器的语法来快速开发HTML和CSS的方法.它由Sergey Chikuyonok开发. 你在写HTML代码(包括所有标签.属性.引用.大括号等)上花费多少时间 ...
- 基于 CODING 的 Spring Boot 持续集成项目
本文作者:CODING 用户 - 廖石荣 持续集成的概念 持续集成(Continuous integration,简称 CI)是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少 ...
- 使用 CODING 进行 Hexo 项目的持续集成
本文作者:CODING 用户 - 廖石荣 关于持续集成的概念 持续集成指的是,频繁地(一天多次)将代码集成到主干. 持续集成的过程 如图所示: CI 过程:代码编写 -> 源代码库(GitHub ...
- 一个有界任务队列的thradpoolexcutor, 直接捕获错误日志
基于官方的需要改版 1.改为有界,官方是吧所有任务添加到线程池的queue队列中,这样内存会变大,也不符合分布式的逻辑(会把中间件的所有任务一次性取完,放到本地的queue队列中,导致分布式变差) 2 ...
随机推荐
- NumPy 数组切片及数据类型介绍
NumPy 数组切片 NumPy 数组切片用于从数组中提取子集.它类似于 Python 中的列表切片,但支持多维数组. 一维数组切片 要从一维数组中提取子集,可以使用方括号 [] 并指定切片.切片由起 ...
- go-admin migrate 数据表迁移
目录 视频教程 应用场景 目录说明 数据迁移 迁移步骤 配置数据库 常用命令示例 新建模型实例 3.1 方式一:不编译运行(推荐) 3.2 方式二:编译并运行迁移 3.3 方式三:golangIDE ...
- 通过 OpenAPI 部署 Npcf_PolicyAuthorization-PostAppSessions API Service
目录 文章目录 目录 OpenAPI 部署步骤 OpenAPI 官方网站:https://github.com/OAI/OpenAPI-Specification 支持通过标准的 yaml 文件来生成 ...
- Django信号与扩展:深入理解与实践
title: Django信号与扩展:深入理解与实践 date: 2024/5/15 22:40:52 updated: 2024/5/15 22:40:52 categories: 后端开发 tag ...
- 当装饰者模式遇上Read Through缓存,一场技术的浪漫邂逅
在<经验之谈:我为什么选择了这样一个激进的缓存大Key治理方案>一文中,我提到在系统中使用的缓存是旁路缓存模式,有读者朋友问,有没有用到过其他的缓存模式,本文将结合一个我曾经工作中的案例, ...
- VAE-可变自动编码器
VAE 有什么作用? 简而言之,它改进了生成的图像.VAE 针对图像的某些方面进行训练,并且我们的 UI ( vae-ft-mse-840000-ema-pruned) 中捆绑的默认 VAE 改善了生 ...
- Vue History模式IIS的配置补充
摘自 :https://blog.csdn.net/ssdnif/article/details/103856283 官方提供的配置<?xml version="1.0" e ...
- yapi-plugin-notifier 插件安装报react 16.9.0版本错误 解决
使用yapi 1.9.2版本. 将配置的json文件替换掉. 参考这个issues解决方案:https://github.com/YMFE/yapi/issues/2109
- 基于FPGA的计算器设计---第一版
欢迎各位朋友关注"郝旭帅电子设计团队",本篇为各位朋友介绍基于FPGA的计算器设计---第一版. 功能说明: 1. 计算器的显示屏幕为数码管. 2. 4x4矩阵键盘作为计算器的输入 ...
- C++笔记(13)数组的引用和引用的数组
数组的引用 数组有二个特性,影响作用在数组上的函数:一是不能复制数组,二是使用数组名时, 数组名会自动指向其第一个元素的指针. 因为不能复制,所以无法编写使用数组类型的形参,数组会自动转化为指针.比如 ...