最近做的事情很多地方用到Linux驱动层与应用层的通信,在此总结下常见的并且在我工作中用到的通信方法。
由于每种方法都可以找到大量的示例代码,同时还有详细的函数手册,我就不贴代码了。只列下相关的方法和一个链接。
syscall的范围就广了,通过注册字符设备可以使用mmap和ioctl等来进行操作,要注意的是在内核态ioctl已经被废弃,现在应该使用unlocked_ioctl,需要自己来加锁。
用户态通过系统暴露出来的系统调用来进行操作,如mmap,ioctl,open,close,read,write,内核态通过建立共享内存remap_pfn_range或者copy_to_user, copy_from_user来进行操作。
选择哪种方式需要考虑是用户态单进程与内核态通信还是多进程的通信,还要考虑通信的数据量。根据不同的需求来使用不同的方法。
PROCFS
/proc目录是系统模拟出来的一个文件系统,本身并不存在于磁盘上,其中的文件都表示内核参数的信息,这些信息分两类,一类是可都可写的,这类参数都在“/proc/sys”目录下,另一类是只读的,就是“/proc/sys”目录之外的其他目录和文件,当然这只是一种惯例,实际在其他目录下建立可读写的/proc文件也是可以的。
/proc文件系统是一个特殊的软件创建的文件系统, 内核用来输出消息到外界. /proc 下的每个文件都绑到一个内核函数上, 当文件被读的时候即时产生文件内容. 我们已经见到一些这样的文件起作用; 例如, /proc/modules, 常常返回当前已加载的模块列表.
/proc 在 Linux 系统中非常多地应用. 很多现代 Linux 发布中的工具, 例如 ps, top, 以及 uptime, 从 /proc 中获取它们的信息. 一些设备驱动也通过 /proc 输出信息.
在 /proc 下添加文件是不鼓励的. /proc 文件系统在内核开发者看作是有点无法控制的混乱, 它已经远离它的本来目的了(是提供关于系统中运行的进程的信息). 建议新代码中使信息可获取的方法是利用 sysfs. 如同建议的, 使用 sysfs 需要对 Linux 设备模型的理解.
内核和用户空间进行通信,大概有如下几种方式可以考虑:
采用内存映射的方式,将内核地址映射到用户态。这种方式最直接,可以适用大量的数据传输机制。这种方式的缺点是很难进行“业务控制”,没有一种可靠的机制保障内核和用户态的调动同步,比如信号量等都不能跨内核、用户层使用。因此内存映射机制一般需要配合一种“消息机制”来控制数据的读取,比如采用“消息”类型的短数据通道来完成一个可靠的数据读取功能。
ioctl机制,ioctl机制可以在驱动中扩展特定的ioctl消息,用于将一些状态从内核反应到用户态。Ioctl有很好的数据同步保护机制,不要担心内核和用户层的数据访问冲突,但是ioctl不适合传输大量的数据,通过和内存映射结合可以很好的完成大量数据交换过程。但是,ioctl的发起方一定是在用户态,因此如果需要内核态主动发起一个通知消息给用户层,则非常的麻烦。可能需要用户态程序采用轮询机制不停的ioctl。
其他一些方式比如系统调用必须通过用户态发起,proc方式不太可靠和实时,用于调试信息的输出还是非常合适的。
通过前面的项目背景,我需要一种可以在内核态主动发起消息的通知方式,而用户态的程序最好可以采用一种“阻塞调用”的方式等待消息。这样的模型可以最大限度的节省CPU的调度,同时可以满足及时处理的要求,最终选择了netlink完成通信的过程。