这篇博文将针对linux内核态与用户态通信方式中的procfs进行详细的学习。

/proc主要存放内核的一些控制信息,所以这些信息大部分的逻辑位置位于内核控制的内存,在/proc下使用ls -l你会发现大部分的文件或者文件夹的大小都是0,不过使用cd命令进到文件夹下或者使用cat命令查看某些文件的内容确实能查看到一些信息。这是因为/proc文件系统和其他常规文件系统一下把自己注册到虚拟文件系统层(VFS),但是直到VFS调用它,请求文件或者目录的i节点时,/proc才根据内核中信息建立相应的目录或者文件(可以理解为这些虚拟文件是动态创建的)。

/proc开始的设计只是为了满足内核向用户态进程报告自己的状态而设计的,随着发展/proc文件系统已经成为“内核态-用户态”交互的一种半双工的方式。用户不但可以从/proc中读取内核的相关信息,而且可以通过改变/proc下相应的文件来改变内核的某些行为状态。

在这里先简单的了解下/proc目录下的一些文件。

--cmdline:系统启动时输入给内核的命令行参数

--cpuinfo:cpu的硬件信息(型号,家族,缓存大小..)

--filesystems:当前内核支持的文件系统,当没有给mount(1)指明文件系统时,mount(1)就根据该文件便利不同的文件系统

--nterrupts:中断的使用和触发次数,据说在调试中断时候很有用

--ioports:当前在用的已注册的IO端口的范围

--kmsg:对应dmesg命令。可以代替系统调用syslog(2)来记录内核日志信息。

--filesystems:内核符号表,该文件保存了内核输出的符号定义。

--loadavg:

cat /proc/loadavg

4.61 4.36 4.15 9/84 5662

每个值的含义为:

参数 解释

lavg_1 (4.61) 1-分钟平均负载

lavg_5 (4.36) 5-分钟平均负载

lavg_15(4.15) 15-分钟平均负载

nr_running (9) 在采样时刻,运行队列的任务的数目,与/proc/stat的procs_running表示相同意思

nr_threads (84) 在采样时刻,系统中活跃的任务的个数(不包括运行已经结束的任务)

last_pid(5662) 最大的pid值,包括轻量级进程,即线程。

--locks:内核锁

--modules:已经加载的模块列表,对应lsmod命令。

--mounts:已加载的文件系统的列表,对应mount命令不带参数。

--mtd:每个mtd设备对应的分区名称。

--partitions:系统识别的分区表。

--stat:全面统计状态表,cpu内存的利用率等都是从这里提取出来的。

--version:对应的版本号。

--sys:可以通过修改sys目录中的信息来修改内核的某些控制参数。

好了,切入正题。

1.通过proc文件系统来进行内核态用户态通信主要需要用到的函数:

在此处输入内容

------------创建一个目录:struct proc_dir_entry *proc_mkdir(const char *name , struct proc_dir_entry *parent)

其中name为要创建的目录名,parent为带创建的目录的上一级,如果parent为null则创建到/proc目录之下。

------------创建一个文件:struct proc_dir_entry *create_proc_entry(const char *name,mode_t mode,struct proc_die_entry *parent)

其中name和parent同上,mode为要创建文件的掩码,即文件权限。

------------上述两个函数中牵扯到一个结构体struct proc_dir_entry.此结构体定义在在include/linux/proc_fs.h文件中:

这里只列出我们这次学习中会用到的成员

struct proc_dir_entry{

...

read_proc_t *read_proc;

write_proc_t *write_proc;

...

};

①关于read_proc

typedef int (read_proc_t)(char *page, char **start, off_t off, int count, int *eof, void *data);

page是这些数据写到的位置,位于内核空间,大小为一个页。count定义了可以写入的最大字符数。在返回多页数据时(通常一个页是4k)我们会用到start和off。当所有数据全部写入之后需要设置*eof为1。data参数是一个指向私有参数的指针。

当我们使用cat命令,或者其他操作队proc目录下的文件进行读的操作时,这个函数会将内核中要读取的数据copy到page指向的内核空间,这里的page存在于内核空间,不需要调用copy_to_user,proc的驱动程序会自动将这块内存中的内容复制到用户空间。

对于read_proc,我个人的一点点猜测,因为不知道从哪里深入了解这个函数,所以关于这个函数的具体原理我目前无法考证,但是这里放出个人的一点点猜测,如果有深入了解的同学,烦请告知。我的猜测:①此函数的返回值为每次读取的字节数,每次调用此函数时系统会在off的基础上再加上上次调用此函数的返回值然后赋值给off,所以此函数的返回值必须是本次调用读取的字节数,这样就会保证每次调用时候off为可以写入的内存的地址的首。②如果未置*eof为1,并且read_proc的返回值不为0会一直读取下去。③关于start我的猜测是start指向的是每个页。也就是如果是多页的数据的话,读取时候是从*start页的off处开始读取。如下图:

②关于write_proc

typedef int (write_proc_t)(struct file *file, const char __user *buffer, unsigned long count, void *data);

file这个参数先可以忽略,buffer是传递给你的字符串数据,位于用户空间的一个缓冲区中,我们不能直接读取他,要先使用copy_from_user后使用。count定义了在buffer中有多少字符要被写入。data通read_proc一样是私有数据指针,即read_proc或者write_proc被调用时传给他的一个参数。

好了,一起来写一个damo程序吧。

代码:

点击(此处)折叠或打开

#include

#include

#include

#include

#define PROC_NAME "yzy_test"

struct proc_dir_entry *my_proc_fs;

static char kernel_buf[128];

int read_proc(char *page, char **start, off_t off,int count, int *eof, void *data);

int write_proc(struct file *file, const char __user *buffer,unsigned long count, void *data);

static int __init module_test_init(void)

{

memset(kernel_buf,0x00,128);

my_proc_fs=create_proc_entry(PROC_NAME,0666,NULL);

my_proc_fs->read_proc=read_proc;

my_proc_fs->write_proc=write_proc;

return 0;

}

static void __exit module_test_exit(void)

{

remove_proc_entry(PROC_NAME,0);

}

int read_proc(char *page, char **start, off_t off,int count, int *eof, void *data)

{

int len=strlen(kernel_buf);

if(count>len-off)

{

*eof=1;

}

if( count>strlen(kernel_buf)-off )

{

count=strlen(kernel_buf)-off;

}

memcpy(page+off,kernel_buf+off,count);

printk("read:%s\n",page);

return count;

}

int write_proc(struct file *file, const char __user *buffer,unsigned long count, void *data)

{

int len=strlen(kernel_buf);

if(count>len)

{

count=len-1;

}

if(!copy_from_user(kernel_buf,buffer,count))//成功返回0,失败返回拷贝失败的字节数.

{

return -1;

}

kernel_buf[count]=0;

printk("write:%s\n",kernel_buf);

return count;

}

module_init(module_test_init);

module_exit(module_test_exit);

MODULE_AUTHOR("yanzhiyao");

MODULE_DESCRIPTION("procfs test module");

MODULE_LICENSE("GPL");

点击(此处)折叠或打开

makefile:

ifneq ($(KERNELRELEASE),)

procfs-objs := test_procfs.o

obj-m := test_procfs.o

else

K_VER ?= $(shell uname -r)

K_DIR := /lib/modules/$(K_VER)/build

M_DIR := $(shell pwd)

all:

make -C $(K_DIR) M=$(M_DIR)

clean:

rm -rf *.o *.ko *.symvers *.order *mod.c

endif

好了,代码写好了,编一把吧。

生成的.ko文件,使用/sbin/insmod 装载,卸载时使用/sbin/rmmod 卸载 ,使用lsmod可以查看是否装载成功。

linux 用户态 内核态 通信,procfs(从0开始,内核态和用户态通信charpter2)相关推荐

  1. <LINUX内核完全剖析:基于0.12内核> 笔记一

    gcc编译C程序过程

  2. Linux 0.11-从内核态到用户态-23

    Linux 0.11-从内核态到用户态-23 从内核态到用户态 转载 从内核态到用户态 书接上回,上回书咱们从整体上鸟瞰了一下第三部分要讲的内容,代码上就是还差四句话就走到了 main 函数的尽头. ...

  3. Linux下的LWP(轻量级进程)、进程 、 线程、用户级线程、内核线程

    一.定义 再看正文之前我要先强调一下几点: 1. Linux中没有真正的线程,但windows中确实有线程 2. Linux中没有的线程是由进程来模拟实现的(又称作:轻量级进程) 3. 所以在Linu ...

  4. 【Linux开发】linux设备驱动归纳总结(四):5.多处理器下的竞态和并发

    linux设备驱动归纳总结(四):5.多处理器下的竞态和并发 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  5. Linux进程地址空间与进程内存布局详解,内核空间与用户空间

    Linux进程地址空间与进程内存布局详解 程序段(Text):程序代码在内存中的映射,存放函数体的二进制代码. 初始化过的数据(Data):在程序运行初已经对变量进行初始化的数据. 未初始化过的数据( ...

  6. linux 返回非法指令,linux – ARM Cortex A7在内核模式下返回PMCCNTR = 0,在用户模式下返回非法指令(即使在PMUSERENR = 1之后)...

    我想在Raspberry Pi 2上读取循环计数寄存器(PMCCNTR),它有一个ARM Cortex A7内核.我为它编译了一个内核模块,如下所示: #include #include int in ...

  7. Linux下的C编程实战(开发平台搭建,文件系统编程,进程控制与进程通信编程,“线程”控制与“线程”通信编程,驱动程序设计,专家问答)

    Linux下的C编程实战(一) ――开发平台搭建 1.引言 Linux操作系统在服务器领域的应用和普及已经有较长的历史,这源于它的开源特点以及其超越Windows的安全性和稳定性.而近年来,Linux ...

  8. Linux 0.11内核分析04:多进程视图

    目录 1 进程概念的引入 1.1 使用CPU的直观想法 1.2 直观用法的缺点 1.3 直观用法的改进 1.4 进程的概念 1.4.1 保存程序执行状态 1.4.2 进程与PCB 1.5 Linux ...

  9. Linux 0.11内核分析03:系统调用

    目录 1 概述 1.1 什么是系统调用 1.2 为什么需要系统调用 2 系统调用基础设施 2.1 安装系统门 2.1.1 中断描述符 2.1.2 中断描述符安装函数 2.1.3 安装0x80系统门 2 ...

最新文章

  1. Python学习第四天----Linux之用户与用户组权限
  2. hibernate mysql缓存机制_Hibernate的缓存机制
  3. jupyter安装插件,以及远程访问服务器上的jupyter notebook
  4. 服务器工具个人免费版下载使用,xshell个人免费版,xftp个人免费版
  5. outlook搜索栏跑到上面去了_长春企业网站搜索优化如何做
  6. 拓端tecdat|R语言用RNN循环神经网络 、LSTM长短期记忆网络实现时间序列长期利率预测
  7. es5 html片段拼接,es5的 reduce怎样用在拼接html字符串??? - 社区 - 妙味课堂
  8. NodeJS:图片验证码登录
  9. python如何取消上一步操作的快捷键_ai返回上一步的快捷键是什么
  10. word2016 尾注后加致谢
  11. Python中的any函数
  12. debian apache2不执行php,Debian下Apache2的安装与配置
  13. 沉病孩子留遗嘱 父疏申请接济劫持红十字员农
  14. 【Mysql】InnoDB 中的 B+ 树索引
  15. 电脑怎么压缩图片大小,4个通用方法分享
  16. c语言词典课程设计报告,英汉电子词典C语言课程设计
  17. MATLAB——求系统的零状态响应
  18. matlab dim是什么意思,哪位大神给我解释下这两句程序是什么意思
  19. 【数据结构】图-图的遍历_深度优先遍历(动态图解、c++、java)
  20. [深度学习][原创]使用labelImg+yolov5完成所有slowfast时空动作检测项目-训练测试篇

热门文章

  1. JAVA基础系列:反射
  2. 作业帮:最长连续序列(头部插入)
  3. [USB].USB总线详解
  4. 2018百度之星资格赛:1002:子串查询
  5. CentOS7(mini) 急速部署ASP.NET应用
  6. JMeter使用总结
  7. SQL SERCER 控制 SERVERICE BROKER 服务
  8. 数学趣题——渔夫抓鱼问题
  9. 第二章 UML与设计模式
  10. 管理端口_内网渗透 | 红蓝对抗:Windows利用WinRM实现端口复用打造隐蔽后门