文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>更改内核ioctl的例子

更改内核ioctl的例子

时间:2010-07-28  来源:chenye2865

概述
从ioctl这个名称上看,它是设备驱动程序中对设备的 I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等, 但实际上ioctl所处理的对象并不限制是真正的I/O设备,还可以是其它任何一个内核设备.ioctl以系统调用的形式提供了一条用户与内核交互的便捷 途径。当前一些宽带计费网关、防火墙系统均利用Ioctl与内核良好的通信互动特点支持用户对基于内核模块的软件系统的控制.本文针对i386平台下的 ioctl内核网络源代码控制框架进行剖析解释,在文章最后列举一个实例,通过编程实践展示如何通过ioctl控制函数实现自定义的功能的控制,使读者可 以对ioctl实现原理有一个全面的认识,本文只对ioctl实现流程框架做一定的叙述,并不会深入到具体的控制函数。为了更好的阅读本文,要求读者对 Linux 下的网络编程有一定的了解。
本文约定:
1、以下内容如果没有特殊说明,均参照linux内核2.4.0版本
2、“->”箭头符表示函数调用关系,如sys_socket->sock_map_fd表示sys_socket函数调用的sock_map_fd函数。
3、第五节的实践是在redhat9上实现,基于2.4.20内核,但本文所述在2.4内核下都适用。
二、用户空间ioctl控制函数调用形式
通过man 2 ioctl命令查看ioctl函数的调用形式类似如下:
#include <sys/ioctl.h>
int ioctl(int d, int request, ...);
其中d就是用户程序打开设备时使用open函数返回的文件描述符,request就是用户程序对设备的控制命令,至于后面的省略号,则是一些补充参数,一般最多一个,有或没有是和request的意义相关的,详情请参考man 2 ioctl_list以了解更多。ioctl函数是文件结构中的一个属性分量,就是说如果驱动程序提供了对ioctl的支持,用户就可以在用户程序中使用ioctl函数控制设备的I/O通道或其它一些自己想要控制且设备支持的功能。
三、内核主要函数调用框架
内核实现ioctl()函数的是sys_ioctl(),在内核中主要调用框架图如下,它清晰地给我们展示ioctl的控制传递框架,我们接下来的内容将根据此图向大家做详细的解释:

四、IOCTL框架源代码分析
根据前面的图示,我们从入口函数sys_ioctl开始分析:
4.1、入口函数:sys_ioctl
以下源码在fs/ioctl.c中,其中删除了部分与网络控制关系不大的代码:
asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{    
       …//根据fd获取文件结构(struct file)
       lock_kernel();
       switch (cmd) {
              case FIOCLEX://对文件设置专用标志,通知内核自动关闭打开的文件
              …
              case FIONCLEX://与FIOCLEX标志相反,清除专用标志
              …
              case FIONBIO://将文件操作设置成阻塞/非阻塞
              …
              case FIOASYNC:// 将文件操作设置成同步/异步IO
              …    //以上省略的代码是关于具体的磁盘文件系统的控制处理,
                     //关于socket的阻塞或非阻塞等设置很简单,有兴趣的读者直接阅读源码吧
default: //文件其它部分的处理被放在了default部分
                     error = -ENOTTY;
                     if (S_ISREG(filp->f_dentry->d_inode->i_mode)) //普通文件
                            error = file_ioctl(filp, cmd, arg); //
                     else if (filp->f_op && filp->f_op->ioctl) //socket控制在此处理
                            error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
       }
       unlock_kernel();
       fput(filp);
out:
       return error;
}
注意上面蓝色字体部分,即为调用网络部分的代码入口。大家注意在default情况下,有个S_ISREG宏对文件类型作判断,其定义在include/linux/stat.h中:
#define S_ISLNK(m)     (((m) & S_IFMT) == S_IFLNK) //符号连接文件
#define S_ISREG(m)     (((m) & S_IFMT) == S_IFREG) //普通文件
#define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)   //目录文件
#define S_ISCHR(m)     (((m) & S_IFMT) == S_IFCHR) //字符设备文件
#define S_ISBLK(m)     (((m) & S_IFMT) == S_IFBLK)   //块设备文件
#define S_ISFIFO(m)    (((m) & S_IFMT) == S_IFIFO)   //管道文件
#define S_ISSOCK(m)   (((m) & S_IFMT) == S_IFSOCK)       //socket套接字文件
因为linux内核把socket套接字当作文件来处理, 内核在创建socket套接字时,为套接字分配文件id以及生成与id对应的文件节点,节点的i_mode域是代表文件类型的位域标志字段,所以内核定义 了上述宏来简化判断操作。由于套接字文件不属于普通文件之列,所以程序直接执行蓝色字体部分。
4.2、入口函数跳转
我们来看一下filp->f_op->ioctl函数指针指向了什么函数,可以参考net/socket.c文件中的sys_socket->sock_map_fd函数中的一行代码(蓝色部分代码):
static int sock_map_fd(struct socket *sock)
{
       …
       sock->file = file;
       file->f_op = sock->inode->i_fop = &socket_file_ops;
       file->f_mode = 3;
       file->f_flags = O_RDWR;
       file->f_pos = 0;
       …
}
内核在用户创建socket套接字时就将此套接字的文件操 作函数指针初始化了。从上面的代码我们可以看到,filp->f_op以及文件对应的socket节点的i_fop指针都被赋值为指向 socket_file_ops结构,所以我们来看看内核是如何实现这个控制过程的转移的。还是在内核的net/socket.c文件中,定义了 socket_file_ops结构如下:
static struct file_operations socket_file_ops = {
llseek:             sock_lseek,
read:                     sock_read,
write:             sock_write,
poll:               sock_poll,
ioctl:              sock_ioctl,
mmap:            sock_mmap,
open:              sock_no_open,       /* special open code to disallow open via /proc */
release:           sock_close,
fasync:           sock_fasync,
readv:             sock_readv,
writev:           sock_writev
};
从上面的代码来看,这个结构定义了socket描述字的文 件操作函数,如对描述字调用read函数读数据时最终将访问sock_read函数,对描述字调用write函数读数据时最终将访问sock_write 函数,等等。而对ioctl的访问最终将转化为调用sock_ioctl函数,看到此处我们明白了,filp->f_op->ioctl (filp->f_dentry->d_inode, filp, cmd, arg)调用实质上转化为对sock_ioctl函数的调用。
4.3、sock_ioctl函数
sock_ioctl函数依然在net/socket.c文件中,列出如下:
int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
       struct socket *sock;
       int err;
       unlock_kernel();
       sock = socki_lookup(inode);
       err = sock->ops->ioctl(sock, cmd, arg);
       lock_kernel();
       return err;
}
相关阅读 更多 +
排行榜 更多 +
辰域智控app

辰域智控app

系统工具 下载
网医联盟app

网医联盟app

运动健身 下载
汇丰汇选App

汇丰汇选App

金融理财 下载