用户空间与内核空间数据交换的方式(2)------procfs
procfs是比较老的一种用户态与内核态的数据交换方式,内核的很多数据都是通过这种方式出口给用户的,内核的很多参数也是通过这种方式来让用户方便设置的。除了sysctl出口到/proc下的参数,procfs提供的大部分内核参数是只读的。实际上,很多应用严重地依赖于procfs,因此它几乎是必不可少的组件。本节将讲解如何使用procfs。
Procfs提供了如下API:
该函数用于创建一个正常的proc条目,参数name给出要建立的proc条目的名称,参数mode给出了建立的该proc条目的访问权限,参数 parent指定建立的proc条目所在的目录。如果要在/proc下建立proc条目,parent应当为NULL。否则它应当为proc_mkdir 返回的struct proc_dir_entry结构的指针。
该函数用于删除上面函数创建的proc条目,参数name给出要删除的proc条目的名称,参数parent指定建立的proc条目所在的目录。
该函数用于创建一个proc目录,参数name指定要创建的proc目录的名称,参数parent为该proc目录所在的目录。
该函数用于建立一个proc条目的符号链接,参数name给出要建立的符号链接proc条目的名称,参数parent指定符号连接所在的目录,参数dest指定链接到的proc条目名称。
read_proc_t *read_proc, void * data);
该函数用于建立一个规则的只读proc条目,参数name给出要建立的proc条目的名称,参数mode给出了建立的该proc条目的访问权限,参 数base指定建立的proc条目所在的目录,参数read_proc给出读去该proc条目的操作函数,参数data为该proc条目的专用数据,它将 保存在该proc条目对应的struct file结构的private_data字段中。
get_info_t *get_info);
该函数用于创建一个info型的proc条目,参数name给出要建立的proc条目的名称,参数mode给出了建立的该proc条目的访问权限, 参数base指定建立的proc条目所在的目录,参数get_info指定该proc条目的get_info操作函数。实际上get_info等同于 read_proc,如果proc条目没有定义个read_proc,对该proc条目的read操作将使用get_info取代,因此它在功能上非常类似于函数create_proc_read_entry。
该函数用于在/proc/net目录下创建一个proc条目,参数name给出要建立的proc条目的名称,参数mode给出了建立的该proc条目的访问权限,参数get_info指定该proc条目的get_info操作函数。
该函数也用于在/proc/net下创建proc条目,但是它也同时指定了对该proc条目的文件操作函数。
该函数用于删除前面两个函数在/proc/net目录下创建的proc条目。参数name指定要删除的proc名称。
除了这些函数,值得一提的是结构struct proc_dir_entry,为了创建一了可写的proc条目并指定该proc条目的写操作函数,必须设置上面的这些创建proc条目的函数返回的指针 指向的struct proc_dir_entry结构的write_proc字段,并指定该proc条目的访问权限有写权限。
为了使用这些接口函数以及结构struct proc_dir_entry,用户必须在模块中包含头文件linux/proc_fs.h。
在源代码包中给出了procfs示例程序procfs_exam.c,它定义了三个proc文件条目和一个proc目录条目,读者在插入该模块后应当看到如下结构:
aint astring bigprocfile
$
读者可以通过cat和echo等文件操作函数来查看和设置这些proc文件。特别需要指出,bigprocfile是一个大文件(超过一个内存
页),对于这种大文件,procfs有一些限制,因为它提供的缓存,只有一个页,因此必须特别小心,并对超过页的部分做特别的考虑,处理起来比较复杂并且
很容易出错,所有procfs并不适合于大数据量的输入输出,后面一节seq_file就是因为这一缺陷而设计的,当然seq_file依赖于 procfs的一些基础功能。
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <asm/uaccess.h>
#define STR_MAX_SIZE 255
static int int_var;
static char string_var[256];
static char big_buffer[65536];
static int big_buffer_len = 0;
static struct proc_dir_entry * myprocroot;
static int first_write_flag = 1;
int int_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
count = sprintf(page, "%d", *(int *)data);
return count;
}
int int_write_proc(struct file *file, const char __user *buffer,unsigned long count, void *data)
{
unsigned int c = 0, len = 0, val, sum = 0;
int * temp = (int *)data;
while (count) {
if (get_user(c, buffer)) //从用户空间中得到数据
return -EFAULT;
len++;
buffer++;
count--;
if (c == 10 || c == 0)
break;
val = c - '0';
if (val > 9)
return -EINVAL;
sum *= 10;
sum += val;
}
* temp = sum;
return len;
}
int string_read_proc(char *page, char **start, off_t off,int count, int *eof, void *data)
{
count = sprintf(page, "%s", (char *)data);
return count;
}
int string_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
if (count > STR_MAX_SIZE) {
count = 255;
}
copy_from_user(data, buffer, count);
return count;
}
int bigfile_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
if (off > big_buffer_len) {
* eof = 1;
return 0;
}
if (count > PAGE_SIZE) {
count = PAGE_SIZE;
}
if (big_buffer_len - off < count) {
count = big_buffer_len - off;
}
memcpy(page, data, count);
*start = page;
return count;
}
int bigfile_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
char * p = (char *)data;
if (first_write_flag) {
big_buffer_len = 0;
first_write_flag = 0;
}
if (65536 - big_buffer_len < count) {
count = 65536 - big_buffer_len;
first_write_flag = 1;
}
copy_from_user(p + big_buffer_len, buffer, count);
big_buffer_len += count;
return count;
}
static int __init procfs_exam_init(void)
{
#ifdef CONFIG_PROC_FS
struct proc_dir_entry * entry;
myprocroot = proc_mkdir("myproctest", NULL);
entry = create_proc_entry("aint", 0644, myprocroot);
if (entry) {
entry->data = &int_var;
entry->read_proc = &int_read_proc;
entry->write_proc = &int_write_proc;
}
entry = create_proc_entry("astring", 0644, myprocroot);
if (entry) {
entry->data = &string_var;
entry->read_proc = &string_read_proc;
entry->write_proc = &string_write_proc;
}
entry = create_proc_entry("bigprocfile", 0644, myprocroot);
if (entry) {
entry->data = &big_buffer;
entry->read_proc = &bigfile_read_proc;
entry->write_proc = &bigfile_write_proc;
}
#else
printk("This module requires the kernel to support procfs,\n");
#endif
return 0;
}
static void __exit procfs_exam_exit(void)
{
#ifdef CONFIG_PROC_FS
remove_proc_entry("aint", myprocroot);
remove_proc_entry("astring", myprocroot);
remove_proc_entry("bigprocfile", myprocroot);
remove_proc_entry("myproctest", NULL);
#endif
}
module_init(procfs_exam_init);
module_exit(procfs_exam_exit);
MODULE_LICENSE("GPL");
用户空间与内核空间数据交换的方式(2)------procfs相关推荐
- 用户空间与内核空间数据交换的方式(zz)
用户空间与内核空间数据交换的方式(1)------debugfs 用户空间与内核空间数据交换的方式(2)------procfs 用户空间与内核空间数据交换的方式(3)------seq_file 用 ...
- linux 内核空间 sy,在 Linux 下用户空间与内核空间数据交换的方式,第 1 部分: 内核启动参数、模块参数与sysf...
级别: 初级 燚 杨 (), 计算机科学硕士 2006 年 2 月 16 日 本系列文章包括两篇,它们文详细地介绍了 Linux 系统下用户空间与内核空间数据交换的九种方式,包括内核启动参数.模块参数 ...
- 用户空间与内核空间数据交换的方式(9)------netlink【转】
转自:http://www.cnblogs.com/hoys/archive/2011/04/10/2011722.html Netlink 是一种特殊的 socket,它是 Linux 所特有的,类 ...
- 用户空间与内核空间数据交换的方式(1)------debugfs
内核开发者经常需要向用户空间应用输出一些调试信息,在稳定的系统中可能根本不需要这些调试信息,但是在开发过程中,为了搞清楚内核的行为,调试信息非常必要,printk可能是用的最多的,但它并不是最好的,调 ...
- 用户空间与内核空间数据交换的方式------seq_file
一般地,内核通过在procfs文件系统下建立文件来向用户空间提供输出信息,用户空间可以通过任何文本阅读应用查看该文件信息,但是procfs 有一个缺陷,如果输出内容大于1个内存页,需要多次读,因此处理 ...
- 用户空间与内核空间数据交换-2-generic netlink
转载自 : http://blog.chinaunix.net/uid-28541347-id-5589868.html https://blog.csdn.net/ty3219/article/de ...
- linux 物理内存用完了_Linux用户空间与内核空间(理解高端内存)
Linux内核地址映射模型 x86 CPU采用了段页式地址映射模型.进程代码中的地址为逻辑地址,经过段页式地址映射后,才真正访问物理内存. 段页式机制如下图. Linux内核地址空间划分 通常32位L ...
- (整理)用户空间_内核空间以及内存映射
内核空间和用户空间 现代操作系统采用虚拟存储器,对于32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也 ...
- linux 内核将两个设备相关联,linux用户空间和内核空间交换数据
转载地址:http://www.poluoluo.com/server/201107/138420.html 在研究dahdi驱动的时候,见到了一些get_user,put_user的函数,不知道其来 ...
最新文章
- 最长不含重复字符的子字符串
- 【原创】项目管理得失经验总结
- linux开启内部路由转发功能
- Java程序员需要掌握的计算机底层知识(一):CPU基本组成、指令乱序执行、合并写技术、非同一访问内存 NUMA
- 游牧大地的诗意:看龙力游的草原油画
- asp.net core AuthenticationMiddleware 在WebApi中的的使用
- hackintosh黑苹果_为什么您的下一个Mac应该是Hackintosh?
- properties加载的几种方式
- BULK INSERT, 实战手记:让百万级数据瞬间导入SQL Server
- jQuery--捕获键盘敲击
- iconv的用法,'GBK'转'utf-8'
- 系统调用 操作系统课程设计 Linux内核编译 centos Ubuntu
- HTMl 实现用户的登录注册界面
- Android 最常用的设计模式十 安卓源码分析——策略模式(Strategy)
- centos、Windows双系统安装及修复引导启动项
- [动态树] HDOJ 5467 Clarke and hunger games
- 20180710使用gh
- 力扣 LCP 42. 玩具套圈 (数学公式反推)
- linux中安装redis 使用make install 命令报错
- Google Chrome浏览器的回退功能快捷键
热门文章
- Ubuntu禁用网卡步骤(重启依然生效)
- 为什么实验是领英 DNA 的核心部分?
- 从技术到产品,转型的这一年我明白了很多道理
- PHP和MySQL Web开发从新手到高手,第1天-搭建PHP开发环境
- 一步一步重写 CodeIgniter 框架 (2) —— 实现简单的路由功能
- 测测实际带宽,预防使用“假带宽”
- FLASH AS3 TextField
- Python : 反斜杠
- shared_ptr使用场景、陷阱、性能分析,使用建议
- mysql5.7延迟_[MySQL] 号称永久解决了复制延迟问题的并行复制,MySQL5.7-阿里云开发者社区...