linux下内核与用户层数据的交换,linux内核交换


1.基本有系统调用接口file_operation系列接口:read write ioctl?

module driver的module param(模块驱动的模块参数)这个不算

2.内核启动参数:?
通过识别bootloader传递过来的参数?
__setup("para_name=", parse_func)

3.异步通知?
特殊的netlink?
netlink的好处在于它可以向用户层传递一组消息,而异步信号通知只能传递一个标志去通知,不能传递一组消息(数据),再通知后还需要应用层调用系统接口?
去从底层获取这个消息,很麻烦。而netlink可以直接上传一组消息?

4.使用debugfs

5.使用sysfs

6.使用procfs

7.relayfs:?
relayfs是一个快速的转发(relay)数据的文件系统

8.使用共享内存或者共享文件的方式通信,基本不受描述符个数的限制?
思路:底层创建一个私有的文件,将fd传递到上层,上层使用一个select或者epoll来监听这个描述符,底层每次有消息时将消息写到这片文件,然后使用一个标志通知上层,?
上层监测到后就会去按照互相定义好的结构去在这个文件上读。这样就可以完成一次通信

netlink和8这种方式是异步通知一般适用于底层向上层不定时主动的发送数据

内核与用户空间信息交互方式小结 :?
总结一些常用的内核于用户态信息交互的方式。?
1.什么时候需要内核态与用户态进行信息交互呢??
在进行设备驱动程序开发,内核功能模块等系统级开发时,常常需要在内核和用户态之间交互信息。Linux针对不同的情况提供了多种方法实现内核态和用户态的交互。包括内核启动参数、模块参数与 sysfs、sysctl、系统调用、netlink、procfs、seq_file、debugfs和relayfs,除此之外,还有其他的一些,比如brk()系统调用,信号,内存映射机制等等。

2.各种方法的简要介绍?
(1)内核启动参数:linux提供了一种通过bootloader向内核传输启动参数的功能。一般的使用方法是,廷议一个解析参数的函数,然后调用内核提供的宏__setup()将其注册到内核中,__setup()定义在linux/init.h中:?
#define __setup(str, fn) \?
__setup_param(str, fn, fn, 0)?
str是要解析的参数名字,fn是分析参数值的函数,负责将要解析的参数的值转换为相应的内核变量的值并设置那个内核变量。?
注:BootLoader在操作系统内核运行之前运行的一段程序。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。?
(2)模块参数与sysfs:内核子系统或设备驱动可以直接编译到内核,也可以编译成模块,如果编译到内核,可以使用内核启动参数的方法通过内核启动参数来向它们传递参数,如果编译成模块,可以通过命令行在插入模块时传递参数,或者在运行时,通过sysfs来设置或读取模块数据。?
(3)Sysctl:这是一种由用户来设置和获得运行时内核配置参数的一种有效方式,通过这种方法,用户可以在系统运行的任何时刻改变内核的配置参数,也可以在任何时候获得内核的配置参数;一般,内核的这些配置参数也都出现在/proc/sys目录下,用户应用程序可以直接通过这个目录下的文件来实现内核配置参数的读写操作。?
(4)系统调用:这是内核提供给应用程序的接口。应用程序对底层硬件的大多数操作都是通过系统调用实现的。?

(5)Netlink:这是linux所特有的一种特殊的socket。Netlink是一种在内核与用户应用间进行双向数据传输的非常好的方式,用户态应用使用标准的 socket API 就可以使用 netlink 提供的强大功能,内核态需要使用专门的内核 API 来使用 netlink。?
(6)/proc:/proc是一种比较早的一种用户态与内核态数据交互方式,用户可以从这个文件系统中获得许多内核信息,方便用户读取和修改,不过,实际上,内核提供的大多数内核参数都是只读的。?
(7)Seq_file:通常,内核通过在procfs文件系统下建立文件来向用户空间提供输出信息,用户空间可以通过任何文本阅读应用查看该文件信息,但是procfs有一个缺陷,如果输出内容大于1个内存页,需要多次读,因此处理起来很难,另外,如果输出太大,速度比较慢,有时会出现一些意想不到的情况,所以开发者实现了seq_file功能,使得内核输出大文件信息更容易。?
(8)Debugfs:在内核的测试版本中常常需要输出一些调试信息到用户空间,printk很好用,但是要改变内核的一些行为的时候,printk就很无力,所以就有了debugfs,这也是一个虚拟文件系统,可以再debugfs中建立一个或者多个文件来向用户空间应用程序提供信息。?
(9)Relayfs:这是一个快速转发(relay)数据的文件系统,主要是为那些需要从内核空间转发大量数据到用户空间的工具和应用提供了快速有效的转发机制。?
在上面这些方法中,内核启动参数和seq_file都是单向信息传递,都只能向内核传递信息;其余的都能用于双向信息交互,但是其中最简单高效的还是netlink。?

3.其他的信息交互方式:?
(1)brk():在有明确的提供用户空间的缓冲区位置的情况下,内核和用户空间交互数据主要用的是get_user()和put_user()例程,但是如果用户空间缓冲区没有明确,此时,就不能再用get_user()和put_user()了,此时要借用brk系统调用和当前进程空间,brk用于给进程设置堆空间大小。每个进程拥有一个独立的堆空间,malloc等动态内存分配函数其实就是进程的堆空间中获取内存的。我们将利用brk在当前进程(current process)的堆空间上扩展一块新的临时缓冲区,再用put_user将内核数据导出到这个确定的用户空间去。?
(2)信号:信号在内核里的用途主要集中在通知用户程序出现重大错误,强行杀死当前进程,这时内核通过发送SIGKILL信号通知进程终止,内核发送信号使用send_sign(pid,sig)例程,可以看到信号发送必须要事先知道进程序号(pid),所以要想从内核中通过发信号的方式异步通知用户进程执行某项任务,那么必须事先知道用户进程的进程号才可。而内核运行时搜索到特定进程的进程号是个费事的工作,可能要遍历整个进程控制块链表。所以用信号通知特定用户进程的方法很糟糕,一般在内核不会使用。内核中使用信号的情形只出现在通知当前进程(可以从current变量中方便获得pid)做某些通用操作,如终止操作等。因此对内核开发者该方法用处不大。?
(3)内存映射机制:linux提供内存映射机制实现了用户进程直接访问内存的能力。就是把内核中特定部分的内存空间映射到用户级程序的内存空间去,实现内核与用户空间共享一块内存空间。一般在对实时性要求比较强或者交互数据量大的应用中会使用这种方法。?
关于内核与用户空间数据交互的方式还有很多,由用户级程序主动发起的信息交互,无论是采用标准的调用方式还是透过驱动程序界面,一般都要用到系统调用。而由内核主动发起信息交互的情况不多,一般在程序设计时,针对用户态应用程序,内核就是一个被动的信息提供者,所以要遵循合理的原则来选择使用哪种信息交互方式。

相关内容