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

目录

简介

一、 procfs

1、proc文件系统的功能

2、proc文件值的修改与查看

3、procfs文件系统的优缺点

二、 API

三、procfs编程示例

1、实现的功能:

2、源码


简介

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

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

本文学习procfs


一、 procfs

在命令行下可以看到procfs下的内容,整数代表当前活动的进程。

root@ubuntu:/proc# ls
1     128    144    15868  18    1914  2030   2119   2310   25028  2540  277  295  311   328   41    4667  53   860  963            fb           misc               sysvipc
10    13     145    159    180   1922  2038   2127   23152  25062  2561  278  296  312   329   42    467   54   862  996            filesystems  modules            thread-self
1020  130    146    15951  1809  1938  2045   2133   23154  25064  2565  28   297  313   330   424   469   55   866  997            fs           mounts             timer_list
1061  1308   147    16     181   1940  2048   2137   2384   25068  2566  280  298  314   34    4261  47    553  867  acpi           interrupts   mpt                tty
6    873  bus            kallsyms     partitions         vmallocinfo

文件夹下/proc/PID 包含有关进程的信息。通过man 5 proc可以查看相应的文档介绍。

1、proc文件系统的功能

  • 接口简单,能够获得内核中的进程、硬件信息;
  • 在root权限下,子文件下有各种内核参数,这个特性叫sysctl,如IPV4网络参数的目录/proc/sys/net/ipv4;

2、proc文件值的修改与查看

# cat /proc/sys/kernel/threads-max
15741
# echo 10000 > /proc/sys/kernel/threads-max
# cat /proc/sys/kernel/threads-max
10000
#

备注: 修改的值是临时的,系统重启后将恢复到默认值。 

3、procfs文件系统的优缺点

优点:

        功能强大,容易编程的接口。通常用来输出状态,调试内核系统。

缺点:

        在2.6内核后,不再使用proc 文件系统,其原因是不保证正确性和稳定性。


二、 API

头文件:

#include <linux/proc_fs.h>
  • 在proc文件系统下创建目录
struct proc_dir_entry *proc_mkdir(const char *name,
                                        struct proc_dir_entry *parent);
  • 创建procfs的文件
struct proc_dir_entry *proc_create(const char *name, umode_t mode,
                                struct proc_dir_entry *parent,
                                const struct file_operations *proc_fops);
  •  删除目录
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)

三、procfs编程示例

1、实现的功能:

        通过proc文件系统,动态控制debug_level的值

创建 procfs_simple_dir文件夹,

  • 创建debug_level文件,动态查询、设置debug_level
  • 创建debug_only_read文件,只读;

2、源码


#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>  /* procfs APIs etc */
#include <linux/seq_file.h>

#include <linux/uaccess.h>
MODULE_AUTHOR("wy");
MODULE_DESCRIPTION("simple procfs interfacing demo");
MODULE_LICENSE("Dual MIT/GPL");
MODULE_VERSION("0.1");

//文件夹
#define PROC_DIR "procfs_simple_dir"
//文件
#define PROC_FILE "debug_level"
//属性
#define PROC_FILE_PARAMS 0600

#define PROC_FILE1 "debug_only_read"
#define PROC_FILE1_PARAMS1 0444

//互斥体
DEFINE_MUTEX(mtx);

//全局的debug_level,可动态修改
static int debug_level;

//debug_level的调整范围
#define DEBUG_LEVEL_MIN         0
#define DEBUG_LEVEL_MAX         2
#define DEBUG_LEVEL_DEFAULT     DEBUG_LEVEL_MIN
static ssize_t proc_write_dbg_level(struct file * filp,
		const char __user *ubuf,size_t count,loff_t *off)
{
	char buf[12];
	int ret = count;
    //互斥体保护数据
	if(mutex_lock_interruptible(&mtx))
		return -ERESTARTSYS;
	if(count == 0 || count > 12)
	{
		ret = -EINVAL;
		goto out;
	}
    //从用户接收数据
	if(copy_from_user(buf,ubuf,count))
	{
		ret = -EFAULT;
		goto out;
	}
	buf[count - 1]='\0';
	pr_debug("user sent mesg=%s\n",buf);
    //内核中奖字符型转化为int型
	ret = kstrtoint(buf,0,&debug_level);
	if(ret)
		goto out;
    //debug_level的范围验证
	if(debug_level < DEBUG_LEVEL_MIN || debug_level > DEBUG_LEVEL_MAX)
	{
		pr_info("set vaild value");
		debug_level = DEBUG_LEVEL_DEFAULT;
		ret = -EFAULT;
		goto out;
	}

	//use userspace value
	//xxxxx
	
	ret = count;
out:
    //解锁
	mutex_unlock(&mtx);
	return ret;
}
//显示debug_level的函数
static int proc_show_debug_level(struct seq_file *seq,void *v)
{
	if(mutex_lock_interruptible(&mtx))
		return -ERESTARTSYS;
    //通过seq_printf,将debug_level参数赋赋值到seq
	seq_printf(seq,"debug_level:%d\n",debug_level);
	mutex_unlock(&mtx);
	return 0;
}

static int proc_open_dbg_level(struct inode *inode,struct file *file)
{
    //打开文件file,回调函数proc_show_debug_level
	return single_open(file,proc_show_debug_level,NULL);
}

//fops的函数 seq_xxx是内核提供的函数,
static const struct proc_ops fops_dbg_level = 
{
	.proc_open = proc_open_dbg_level,
	.proc_read = seq_read,
	.proc_write= proc_write_dbg_level,
	.proc_lseek = seq_lseek,
	.proc_release = single_release,
};

//read only
static int proc_show_pgoff(struct seq_file *seq, void *v)
{
        seq_printf(seq, "%s:PAGE_OFFSET:0x%px\n", PROC_DIR, PAGE_OFFSET);
        return 0;
}

//函数的初始化
static int __init procfs_simple_intf_init(void)
{
	int stat = 0;
	static struct proc_dir_entry * procdir;
    //检测procfs文件系统有没有配置
	if(unlikely(!(IS_ENABLED(CONFIG_PROC_FS))))
	{
		pr_warn("procfs not supported!\n");
		return -EINVAL;
	}
    //创建proc下的目录
	procdir = proc_mkdir(PROC_DIR,NULL);
	if(!procdir)
	{
		pr_warn("proc_mkdir failed,aborting...\n");
		stat = -ENOMEM;
		goto out_fail_1;
	}
	pr_debug("proc dir (/proc/%s) created\n",PROC_DIR);
    //创建文件PROC_FILE,属性为PROC_FILE_PARAMS, fops_dbg_level函数注册
	if(!proc_create(PROC_FILE,PROC_FILE_PARAMS,procdir,&fops_dbg_level))
	{
		pr_warn("proc_create failed,aborting...\n");
		stat = -ENOMEM;
		goto out_fail_1;
	}
	pr_debug("proc file (/proc/%s/%s) created\n",PROC_DIR,PROC_FILE);

	//read only                              PROC_FILE1_PARAMS1
    //API  proc_create_single_data
	if (!proc_create_single_data(PROC_FILE1, PROC_FILE1_PARAMS1,
                                        procdir, proc_show_pgoff, 0)) {
                pr_warn("proc_create [2] failed, aborting...\n");
                stat = -ENOMEM;
                goto out_fail_1;
        }
        pr_debug("proc file 3 (/proc/%s/%s) created\n", PROC_DIR, PROC_FILE1);

out_fail_1:
	return stat;
}

//退出时处理
static void __exit procfs_simple_intf_cleanup(void)
{
        remove_proc_subtree(PROC_DIR, NULL);
        pr_info("removed\n");
}


module_init(procfs_simple_intf_init);
module_exit(procfs_simple_intf_cleanup);


  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为了维护世界和平_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值