使用seq_file接口导出内核数据到应用层---seq_open()/single_open()

一、seq_file使用说明

从内核中将信息导出到应用层有很多方法,比如我们写一个简单的驱动文件,当我们cat或echo节点时,最终会调用到驱动file_operations的read或write函数,我们在对应函数中使用copy_to_user,copy_from_user可以实现内核数据与应用层数据的交互,大家可以参考之前写的这篇文章:
Linux字符设备驱动新写法

当然还有其他的方法比如在驱动中添加属性文件,当我cat或echo时最终会调用节点属性文件的xx_show函数或xx_store函数,更加方便同时实现的代码也比较少,在内核中属于比较常见的调试方法,大家也可以参考之前写的这一篇文章:
Linux—驱动属性文件添加

二、seq_file使用实例

今天介绍另外一种方法—使用seq_file接口,关于该类接口在内核Documentation/filesystems/seq_file.txt 中有详细的介绍,相比较于之前的方法其优势可以向应用层导出比较多的数据,例如大于1个PAGE_SIZE,同时驱动文件中我们不用关注复杂的缓冲区管理,这些内核自己处理,属于比较成熟的内核接口。

/* by 面朝大海0902*/

下面我们实操一下,来个简单示例代码:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/fs.h>

static void *my_debug_seq_start(struct seq_file *seq, loff_t *pos)
    __acquires(RCU)
{
    if (*pos >= 1)
        return NULL;
    return 1;
}

static void *my_debug_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
    (*pos)++;
    return NULL;
}

static void my_debug_seq_stop(struct seq_file *s, void *v)
    __releases(RCU)
{
    return;
}

static int my_debug_seq_show(struct seq_file *s, void *v)
{
    seq_printf(s, "hello word\n");
    return 0;
}

static const struct seq_operations my_debug_seq_ops= {
    .start = my_debug_seq_start,
    .next  = my_debug_seq_next,
    .stop  = my_debug_seq_stop,
    .show  = my_debug_seq_show,
};

static int my_debug_open(struct inode *inode, struct file *file)
{
    return seq_open(file, &my_debug_seq_ops);
}

static const struct file_operations my_debug_fops = {
    .owner = THIS_MODULE,
    .open = my_debug_open,
    .read = seq_read,
    .llseek = seq_lseek,
    .release = seq_release,
};

static struct dentry *seq_file_demo_dir;

int my_debug_init(void)
{
    seq_file_demo_dir = debugfs_create_file("my_debug", 0444, NULL,
                NULL, &my_debug_fops);
    return 1;
}

static void __exit my_debug_exit(void)
{
	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    if (seq_file_demo_dir)
            debugfs_remove(seq_file_demo_dir);
}


module_init(my_debug_init);
module_exit(my_debug_exit);

MODULE_LICENSE("GPL");

实例测试:

root@ubuntu:/home/book/Desktop/test# insmod ./seq_file.ko 
root@ubuntu:/home/book/Desktop/test# cat /sys/kernel/debug/my_debug 
hello word
root@ubuntu:/home/book/Desktop/test# 

这个示例创建的文件是debugfs,我们也可以调用proc_create()函数,在/proc下面创建节点,其他的代码我们参考模板直接copy就行,只需要实现xx_show函数就行,内核中也有很多文件用到了这类接口,大家可以自行参考,有一点说明一下file_operations my_debug_fops结构体中open成员必须要有。

/* by 面朝大海0902*/

另外基于上面的代码还有一个更加精简的版本使用了single_open()函数,如下示例:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/fs.h>

static int my_debug_seq_show(struct seq_file *s, void *v)
{
    seq_printf(s, "hello word, This use single_open\n");
    return 0;
}

static int my_debug_open(struct inode *inode, struct file *file)
{
    return single_open(file, &my_debug_seq_show, NULL);
}

static const struct file_operations my_debug_fops = {
    .owner = THIS_MODULE,
    .open = my_debug_open,
    .read = seq_read,
    .llseek = seq_lseek,
    .release = seq_release,
};

static struct dentry *seq_file_demo_dir;

int my_debug_init(void)
{
    seq_file_demo_dir = debugfs_create_file("my_debug", 0444, NULL,
                NULL, &my_debug_fops);
    return 0;
}

static void __exit my_debug_exit(void)
{
	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
	if (seq_file_demo_dir)
                debugfs_remove(seq_file_demo_dir);
}


module_init(my_debug_init);
module_exit(my_debug_exit);

MODULE_LICENSE("GPL");

测试结果如下:

root@ubuntu:/home/book/Desktop/test# insmod seq_file.ko 
root@ubuntu:/home/book/Desktop/test# cat /sys/kernel/debug/my_debug 
hello word, This use single_open
root@ubuntu:/home/book/Desktop/test# 

如测试打印,代码更加的精简,希望对大家有所帮助。/* by 面朝大海0902*/

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值