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,说明当前内核不支持调试文件系统,需要自定义内核。如果需要帮助,可以阅读之前我写的博客,在Arch Linux上编写自定义内核模块。

开始

文件系统有自己一套fops。与我们对文件系统的理解一样,文件系统提供了对设备的一套抽象访问读写等操作的句柄。因此,我们需要实现这些基本操作,如打开文件、读文件和写文件。

文件系统将以模块的方式动态加载到内核中。所以我们需要首先学习如何编写模块,并掌握相关知识。如果您之前不熟悉这方面的知识,可以阅读我之前的博客,先掌握这些内容,然后进行实践。

现在,让我们继续编写模块的Makefile:

obj-m:= charlie.o
pwd:= $(shell pwd)
ker-ver:= $(shell uname -r)
KDIR:= /lib/modules/$(ker-ver)/build

all:
	make -C $(KDIR) M=$(pwd) modules 

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)
{
    int retval = 0;
    if((*offp + cnt) > 512)
        cnt = 512 - *offp;
    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 -C /lib/modules/6.9.7-arch1-1/build M=/home/Charliechen/Works/opearte_system/module/test2 modules
sudo insmod charlie.ko && lsmod | grep charlie

模块正确挂载后,下一步是测试我们编写的功能。

sudo ls /sys/kernel/debug/ | grep Charliedir
sudo ls /sys/kernel/debug/Charliedir
sudo ls /sys/kernel/debug/Charliedir/CharlieSubDir
sudo echo 114514 > /sys/kernel/debug/Charliedir/CharlieSubDir/Charlie 

测试过程已经完成。

image1 image2
热门手游下载
下载排行榜