Linux用户与内核空间交互—procfs
Posted 为了维护世界和平_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux用户与内核空间交互—procfs相关的知识,希望对你有一定的参考价值。
目录
简介
用户空间与内核的交互方式,使用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);
以上是关于Linux用户与内核空间交互—procfs的主要内容,如果未能解决你的问题,请参考以下文章