简介:本文目的是搞清楚①filp->f_op->ioctl是如何指向字符设备ioctl;或者socket控制ioctl。以及标准socket控制ioctl中②sock->ops->ioctl是如何指向inet_ioctl的。(
虽然我已清楚如何写,但双11到现在还没吃饭,先把所要参考的帖子附上并附上关健部分,后面再梳理和排版吧~.~...)
显然,使用ioctl()前,fd或用open()打开,或用socket()打开。
驱动程序运行于内核空间,用户空间的应用程序通过文件系统中/dev/目录下的一个文件来和它交互。这就是我们熟悉的那个文件操作流程:open() —— read() —— write() ——ioctl() ——close()。(需要注意的是也不是所有的内核驱动程序都是这个界面,网络驱动程序和各种协议栈的使用就不大一致,比如说“套接口编程”虽然也有open()close()等概念,但它的内核实现以及外部使用方式都和普通驱动程序有很大差异。)
使用ioctl系统调用是用户空间向内核交换数据的常用方法之一,从ioctl这个名称上看,本意是针对I/O设备进行的控制操作,但实际并不限制是真正的I/O设备,可以是任何一个内核设备即可。在内核空间中ioctl是很多内核操作结构的一个成员函数,如文件操作结构struct file_operations(include/linux/fs.h)、协议操作结构struct proto_ops(include/linux/net.h)等、tty操作结构struct tty_driver(include/linux/tty_driver.h)等,而这些操作结构分别对应各种内核设备,只要在用户空间打开这些设备, 如I/O设备可用open(2)打开,网络协议可用socket(2)打开等,获取一个文件描述符后,就可以在这个描述符上调用ioctl(2)来向内核交换数据。
一、字符设备ioctl
1.
filp->f_op->ioctl是如何指向spidev_ioctl的--->open()
参考:
Linux设备文件三大结构:inode,file,file_operations 以及其中指向的另一篇帖子。
Linux内核会为每一个进程维护一个文件描述符表,这个表其实就是struct file[]的索引。open()的过程其实就是根据传入的路径填充好一个file结构并将其赋值到数组中并返回其索引。
-
chrdev_open()
-
--352-389-->利用container_of等根据inode中的成员找到相应的cdev
-
--390-->用cdev.fops替换filp->f_op,即填充了一个空的struct file的f_op成员。
-
--392-->回调替换之后的filp->f_op->open,由于替换,这个其实就是cdev.fops
首先,在一个字符设备文件被创建的时候,内核会构造相应的inode。
由此可见,对一个字符设备的访问流程大概是:文件路径=>inode=>chrdev_open()=>(kobj_lookup=>)inode.i_cdev=>cdev.fops.my_chr_open()。所以只要通过VFS找到了inode,就可以找到chrdev_open(),这里我们就来关注一个chrdev_open()是怎么从内核的数据结构中找到我们的cdev并执行其中的my_chr_open()的。比较有意思的是,虽然我们有了字符设备的设备文件,inode也被构造并初始化了, 但是在第一次调用chrdev_open()之前,这个inode和具体的chr_dev对象并没有直接关系,而只是通过设备号建立的"间接"关系。在第一次调用chrdev_open()之后, inode->i_cdev才被根据设备号找到的cdev对象赋值,此后inode才和具体的cdev对象直接联系在了一起。
-
chrdev_open()
-
--359-->尝试将inode->i_cdev(一个cdev结构指针)保存在局部变量p中,
-
--360-->如果p为空,即inode->i_cdev为空,
-
--364-->我们就根据inode->i_rdev(设备号)通过kobj_lookup()搜索cdev_map,并返回与之对应kobj,
-
--367-->由于kobject是cdev的父类,我们根据container_of很容易找到相应的cdev结构并将其保存在inode->i_cdev中,
-
--374-->找到了cdev,我们就可以将inode->devices挂接到inode->i_cdev的管理链表中,这样下次就不用重新搜索,
-
--378-->直接cdev_get()即可。
-
--386-->找到了我们的cdev结构,我们就可以将其中的操作方法集inode->i_cdev->ops传递给filp->f_ops(386-390),
-
--392-->这样,我们就可以回调我们的设备打开函数my_chr_open();如果我们没有实现自己的open接口,就什么都不做,也不是错
二、
socket控制ioctl
2.
filp->f_op->ioctl是如何指向sock_ioctl的--->socket()
参考:
linux网络协议栈分析——ioctl的调用流程 linux内核与用户之间的通信方式——虚拟文件系统、ioctl以及netlink
2.1.标准socket控制ioctl中,
sock->ops->ioctl是如何指向inet_ioctl的
参考:同上2个。
阅读(4691) | 评论(0) | 转发(0) |