Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1743096
  • 博文数量: 143
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1462
  • 用 户 组: 普通用户
  • 注册时间: 2016-08-23 11:14
文章分类

全部博文(143)

文章存档

2022年(3)

2021年(13)

2020年(21)

2019年(8)

2018年(28)

2017年(7)

2016年(63)

我的朋友

分类: LINUX

2018-11-11 20:40:33

简介:ioctl有针对IO设备的ioctl,还有网络ioctl,本文就来跟踪下ioctl的系统调用。而由于本文中的IO设备是以Linux设备中使用最多的字符设备为例来跟踪代码的,所以建议先彻读之前写的Linux 字符设备和SPI系列文章;而网络部分不仅跟踪了标准socket控制,而且重点跟踪了无线扩展socket控制。
文章主架构参考:
其中的标准socket控制参考:linux网络协议栈分析——ioctl的调用流程  linux内核与用户之间的通信方式——虚拟文件系统、ioctl以及netlink
其中的无线扩展socket控制参考:WIFI设备管理工具iwconfig/iwpriv及对应内核态的实现机制
  在linux中,设备大致可分为:字符设备,块设备,和网络接口(字符设备包括那些必须以顺序方式,像字节流一样被访问的设备;如字符终端,串口等。块设备是指那些可以用随机方式,以整块数据为单位来访问的设备,如硬盘等;网络接口,就指通常网卡和协议栈等复杂的网络输入输出服务)。
一、用户态
1.字符设备ioctl

点击(此处)折叠或打开

  1. int main(int argc,char **argv)
  2. {

  3.     fd = open(/dev/spidev1.1”,O_RDWR);

  4.     ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);

  5. }
2.标准socket控制ioctl

点击(此处)折叠或打开

  1. int main(int argc,char **argv)
  2. {

  3.     sockfd = socket(AF_INET,SOCK_DGRAM,0);

  4.     if(ioctl(sockfd,SIOCGIFADDR,&ifr))

  5. }
3.无线扩展socket控制ioctl

点击(此处)折叠或打开

  1. int main(int argc,char **argv)
  2. {

  3.     sockfd = socket(AF_INET,SOCK_DGRAM,0);

  4.     if(ioctl(sockfd,IEEE80211_IOCTL_STA_INFO,&ifr))

  5. }
二、内核态
进入系统调用。先看个老代码作为辅助参考:

点击(此处)折叠或打开

  1. /linux/fs/ioctl.c
  2. asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
  3. {
  4.     struct file * filp;
  5. ...
  6.     filp = fget(fd);//通过文件句柄fd来获得需要操作的文件的指针
  7. ...
  8.     switch (cmd) {
  9. ...
  10.         default:
  11.             error = -ENOTTY;
  12.             if (S_ISREG(filp->f_dentry->d_inode->i_mode))//普通文件
  13.                 error = file_ioctl(filp, cmd, arg);
  14.             else if (filp->f_op && filp->f_op->ioctl)
  15.                 error = filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
  16.     }
  17. ...
  18. }
而,我本地openWRT中代码实现:

点击(此处)折叠或打开

  1. /linux/fs/ioctl.c
  2. int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
  3.              unsigned long arg)
  4. {
  5.     int error = 0;
  6.     int __user *argp = (int __user *)arg;
  7.     struct inode *inode = file_inode(filp);//filp->f_inode

  8.     switch (cmd) {
  9. ...
  10.         default:
  11.             if (S_ISREG(inode->i_mode))
  12.                 error = file_ioctl(filp, cmd, arg);
  13.             else if (filp->f_op && filp->f_op->unlocked_ioctl)
  14.                 error = filp->f_op->unlocked_ioctl(filp, cmd, arg);
  15.             break;
  16.         }
  17.         return error;
  18. }
  19. SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
  20. {
  21.         int error;
  22.         struct fd f = fdget(fd);
  23. ...
  24.         error = security_file_ioctl(f.file, cmd, arg);
  25.         if (!error)
  26.                 error = do_vfs_ioctl(f.file, fd, cmd, arg);
  27.         fdput(f);
  28.         return error;
  29. }
这里注释下关健宏定义

点击(此处)折叠或打开

  1. include/linux/stat.h
  2. #define S_ISLNK(m)    (((m) & S_IFMT) == S_IFLNK)//符号连接文件
  3. #define S_ISREG(m)    (((m) & S_IFMT) == S_IFREG)//普通文件
  4. #define S_ISDIR(m)    (((m) & S_IFMT) == S_IFDIR)//目录文件
  5. #define S_ISCHR(m)    (((m) & S_IFMT) == S_IFCHR)//字符设备文件
  6. #define S_ISBLK(m)    (((m) & S_IFMT) == S_IFBLK)//块设备文件
  7. #define S_ISFIFO(m)    (((m) & S_IFMT) == S_IFIFO)//管道文件
  8. #define S_ISSOCK(m)    (((m) & S_IFMT) == S_IFSOCK)//socket套接字文件(linux内核把socket套接字当作文件来处理,内核在创建socket套接字时,为套接字分配文件id以及生成与id对应的文件节点,节点的i_mode域是代表文件类型的位域标志字段)
接下来我们就是关健的,filp->f_op->ioctl是如何找到和区分:字符设备ioctl、标准socket控制ioctl、无线扩展socket控制ioctl的呢?这个问题我将在下一文章顺着讲解。本文直捣黄龙,直接看调用关健点:
1.字符设备ioctl

点击(此处)折叠或打开

  1. struct file {
  2. ...
  3.     struct file operations *f_op;
  4. ...
  5. }
  6. static const struct file_operations spidev_fops = {
  7. ...
  8.     .open = spidev_open;
  9.     .unlocked_iotctl = spidev_ioctl;
  10. ...
  11. }
而上面的spidev_fops是来自:(怎么来的看下一文章)

点击(此处)折叠或打开

  1. struct cdev {
  2. ...
  3.     const struct file operations *ops;
  4. ...
  5. }
  6. static const struct file_operations spidev_fops = {//同上
  7. ...
  8.     .open = spidev_open;
  9.     .unlocked_iotctl = spidev_ioctl;
  10. ...
  11. }
2.socket控制ioctl

点击(此处)折叠或打开

  1. struct file {
  2. ...
  3.     struct file operations *f_op;
  4. ...
  5. }
  6. static const struct file_operations socket_file_ops = {
  7. ...
  8.     .unlocked_ioctl = sock_ioctl;
  9. ...
  10. };
(而上面的socket_file_ops是怎么来的看下一文章)
接着看,socket_ioctl,先看个老代码:

点击(此处)折叠或打开

  1. /linux/net/socket.c
  2. int sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
  3. {
  4.     struct socket *sock;
  5. ...
  6.     sock = socki_lookup(inode);//通过inode找到套接字对应的socket结构
  7.     err = sock->ops->ioctl(sock, cmd, arg);
  8. ...
  9. }
而我本地包含Wireless Externsions的代码实现:

点击(此处)折叠或打开

  1. /linux/net/socket.c
  2. static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
  3. {
  4.     struct socket *sock;
  5.     struct sock *sk;
  6.     void __user *argp = (void __user *)arg;
  7.     int pid, err;
  8.     struct net *net;

  9.     sock = file->private_data;
  10.     sk = sock->sk;
  11.     net = sock_net(sk);
  12.     if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) {
  13.             err = dev_ioctl(net, cmd, argp);
  14.     } else
  15. #ifdef CONFIG_WEXT_CORE
  16.     if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
  17.             err = dev_ioctl(net, cmd, argp);
  18.     } else
  19. #endif
  20.         switch (cmd) {
  21. ...
  22.             default:
  23.                 err = sock->ops->ioctl(sock, cmd, arg);

  24.                 /*
  25.                  * If this ioctl is unknown try to hand it down
  26.                  * to the NIC driver.
  27.                  */
  28.                 if (err == -ENOIOCTLCMD)
  29.                     err = dev_ioctl(net, cmd, argp);//whj_note:这里应该不会跑到
  30.                 break;
  31.         }
  32.     return err;
  33. }
2.1.无线扩展socket控制ioctl

点击(此处)折叠或打开

  1. /linux/net/core/dev_ioctl.c
  2. int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)//所有的和接口相关的ioctl请求(SIOCxIFyyyy 和 SIOCDEVPRIVATE)将会调用dev_ioctl(),而实际的动作将由dev_ifsioc()来实现。
  3. {
  4.         struct ifreq ifr;
  5. ...
  6.         switch (cmd) {
  7. ...
  8.         /*
  9.          * Unknown or private ioctl.
  10.          */
  11.         default:
  12.                 if (cmd == SIOCWANDEV ||
  13.                     cmd == SIOCGHWTSTAMP ||
  14.                     (cmd >= SIOCDEVPRIVATE &&
  15.                      cmd <= SIOCDEVPRIVATE + 15)) {
  16.                         dev_load(net, ifr.ifr_name);
  17.                         rtnl_lock();
  18.                         ret = dev_ifsioc(net, &ifr, cmd);
  19.                         rtnl_unlock();
  20.                         if (!ret && copy_to_user(arg, &ifr,
  21.                                                  sizeof(struct ifreq)))
  22.                                 ret = -EFAULT;
  23.                         return ret;
  24.                 }
  25.                 /* Take care of Wireless Extensions */
  26.                 if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)
  27.                         return wext_handle_ioctl(net, &ifr, cmd, arg);
  28.                 return -ENOTTY;
  29.         }
  30. }
这里注释下关健宏定义:

点击(此处)折叠或打开

  1. /linux/user_headers/include/linux/sockios.h
  2. /* Linux-specific socket ioctls */
  3. #define SIOCINQ FIONREAD
  4. #define SIOCOUTQ TIOCOUTQ /* output queue size (not sent + not acked) */

  5. /* Routing table calls. */
  6. #define SIOCADDRT 0x890B /* add routing table entry */
  7. #define SIOCDELRT 0x890C /* delete routing table entry */
  8. #define SIOCRTMSG 0x890D /* call to routing system */

  9. /* Socket configuration controls. */
  10. #define SIOCGIFNAME 0x8910 /* get iface name */
  11. #define SIOCSIFLINK 0x8911 /* set iface channel */
  12. #define SIOCGIFCONF 0x8912 /* get iface list */
  13. #define SIOCGIFFLAGS 0x8913 /* get flags */
  14. #define SIOCSIFFLAGS 0x8914 /* set flags */
  15. ...
  16. /* ARP cache control calls. */
  17.                     /* 0x8950 - 0x8952 * obsolete calls, don't re-use */
  18. #define SIOCDARP 0x8953 /* delete ARP table entry */
  19. #define SIOCGARP 0x8954 /* get ARP table entry */
  20. #define SIOCSARP 0x8955 /* set ARP table entry */

  21. /* RARP cache control calls. */
  22. #define SIOCDRARP 0x8960 /* delete RARP table entry */
  23. #define SIOCGRARP 0x8961 /* get RARP table entry */
  24. #define SIOCSRARP 0x8962 /* set RARP table entry */

  25. /* Driver configuration calls */

  26. #define SIOCGIFMAP 0x8970 /* Get device parameters */
  27. #define SIOCSIFMAP 0x8971 /* Set device parameters */

  28. /* DLCI configuration calls */

  29. #define SIOCADDDLCI 0x8980 /* Create new DLCI device */
  30. #define SIOCDELDLCI 0x8981 /* Delete DLCI device */

  31. #define SIOCGIFVLAN 0x8982 /* 802.1Q VLAN support */
  32. #define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options */

  33. /* bonding calls */

  34. #define SIOCBONDENSLAVE 0x8990 /* enslave a device to the bond */
  35. #define SIOCBONDRELEASE 0x8991 /* release a slave from the bond*/
  36. #define SIOCBONDSETHWADDR 0x8992 /* set the hw addr of the bond */
  37. #define SIOCBONDSLAVEINFOQUERY 0x8993 /* rtn info about slave state */
  38. #define SIOCBONDINFOQUERY 0x8994 /* rtn info about bond state */
  39. #define SIOCBONDCHANGEACTIVE 0x8995 /* update to a new active slave */

  40. /* bridge calls */
  41. #define SIOCBRADDBR 0x89a0 /* create new bridge device */
  42. #define SIOCBRDELBR 0x89a1 /* remove bridge device */
  43. #define SIOCBRADDIF 0x89a2 /* add interface to bridge */
  44. #define SIOCBRDELIF 0x89a3 /* remove interface from bridge */

  45. /* hardware time stamping: parameters in linux/net_tstamp.h */
  46. #define SIOCSHWTSTAMP 0x89b0 /* set and get config */
  47. #define SIOCGHWTSTAMP 0x89b1 /* get config */

  48. /* Device private ioctl calls */

  49. /*
  50.  * These 16 ioctls are available to devices via the do_ioctl() device
  51.  * vector. Each device should include this file and redefine these names
  52.  * as their own. Because these are device dependent it is a good idea
  53.  * _NOT_ to issue them to random objects and hope.
  54.  *
  55.  * THESE IOCTLS ARE _DEPRECATED_ AND WILL DISAPPEAR IN 2.5.X -DaveM
  56.  */

  57. #define SIOCDEVPRIVATE 0x89F0 /* to 89FF */

  58. /*
  59.  * These 16 ioctl calls are protocol private
  60.  */

  61. #define SIOCPROTOPRIVATE 0x89E0 /* to 89EF */
2.1.1.

点击(此处)折叠或打开

  1. /linux/net/core/dev_ioctl.c
  2. /*
  3.  * Perform the SIOCxIFxxx calls, inside rtnl_lock()
  4.  */
  5. static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
  6. {
  7.         int err;
  8.         struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name);//找到与ifr->ifr_name相匹配的设备结构

  9.         if (!dev)
  10.                 return -ENODEV;

  11.         switch (cmd) {
  12. ...
  13.         /*
  14.          * Unknown or private ioctl
  15.          */
  16.         default:
  17.                 if ((cmd >= SIOCDEVPRIVATE &&
  18.                     cmd <= SIOCDEVPRIVATE + 15) ||
  19.                     cmd == SIOCBONDENSLAVE ||
  20.                     cmd == SIOCBONDRELEASE ||
  21.                     cmd == SIOCBONDSETHWADDR ||
  22.                     cmd == SIOCBONDSLAVEINFOQUERY ||
  23.                     cmd == SIOCBONDINFOQUERY ||
  24.                     cmd == SIOCBONDCHANGEACTIVE ||
  25.                     cmd == SIOCGMIIPHY ||
  26.                     cmd == SIOCGMIIREG ||
  27.                     cmd == SIOCSMIIREG ||
  28.                     cmd == SIOCBRADDIF ||
  29.                     cmd == SIOCBRDELIF ||
  30.                     cmd == SIOCSHWTSTAMP ||
  31.                     cmd == SIOCGHWTSTAMP ||
  32.                     cmd == SIOCWANDEV) {
  33.                         err = -EOPNOTSUPP;
  34.                         if (dev->netdev_ops->ndo_do_ioctl) {
  35.                                 if (netif_device_present(dev))
  36.                                         err = dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd);
  37.                                 else
  38.                                         err = -ENODEV;
  39.                         }
  40.                 } else
  41.                         err = -EINVAL;

  42.         }
  43.         return err;
  44. }
这里注释下关健结构的定义:

点击(此处)折叠或打开

  1. /linux/user_headers/include/linux/if.h
  2. struct ifreq{}//PS:iwreq结构体,其对应的普通数据结构类型是ifreq。ifreq结构体专门用于往socket句柄传递ioctl控制参数

  3. /linux/user_headers/include/linux/netdevice.h
  4. struct net_device{}
2.1.2.

点击(此处)折叠或打开

  1. int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd,
  2.                       void __user *arg)
  3. {
  4.         struct iw_request_info info = { .cmd = cmd, .flags = 0 };
  5.         int ret;

  6.         ret = wext_ioctl_dispatch(net, ifr, cmd, &info,
  7.                                   ioctl_standard_call,
  8.                                   ioctl_private_call);
  9.         if (ret >= 0 &&
  10.             IW_IS_GET(cmd) &&
  11.             copy_to_user(arg, ifr, sizeof(struct iwreq)))
  12.                 return -EFAULT;

  13.         return ret;
  14. }
  15. static int wext_ioctl_dispatch(struct net *net, struct ifreq *ifr,
  16.                                unsigned int cmd, struct iw_request_info *info,
  17.                                wext_ioctl_func standard,
  18.                                wext_ioctl_func private)
  19. {
  20.         int ret = wext_permission_check(cmd);

  21.         if (ret)
  22.                 return ret;

  23.         dev_load(net, ifr->ifr_name);
  24.         rtnl_lock();
  25.         ret = wireless_process_ioctl(net, ifr, cmd, info, standard, private);
  26.         rtnl_unlock();

  27.         return ret;
  28. }
  29. static int wireless_process_ioctl(struct net *net, struct ifreq *ifr,
  30.                                   unsigned int cmd,
  31.                                   struct iw_request_info *info,
  32.                                   wext_ioctl_func standard,
  33.                                   wext_ioctl_func private)
  34. {
  35.         struct iwreq *iwr = (struct iwreq *) ifr;
  36.         struct net_device *dev;
  37.         iw_handler handler;

  38.         /* Permissions are already checked in dev_ioctl() before calling us.
  39.          * The copy_to/from_user() of ifr is also dealt with in there */

  40.         /* Make sure the device exist */
  41.         if ((dev = __dev_get_by_name(net, ifr->ifr_name)) == NULL)//找到与ifr->ifr_name相匹配的设备结构
  42.                 return -ENODEV;

  43.         /* A bunch of special cases, then the generic case...
  44.          * Note that 'cmd' is already filtered in dev_ioctl() with
  45.          * (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) */
  46.         if (cmd == SIOCGIWSTATS)
  47.                 return standard(dev, iwr, cmd, info,
  48.                                 &iw_handler_get_iwstats);

  49. #ifdef CONFIG_WEXT_PRIV
  50.         if (cmd == SIOCGIWPRIV && dev->wireless_handlers)
  51.                 return standard(dev, iwr, cmd, info,
  52.                                 iw_handler_get_private);
  53. #endif

  54.         /* Basic check */
  55.         if (!netif_device_present(dev))
  56.                 return -ENODEV;

  57.         /* New driver API : try to find the handler */
  58.         handler = get_handler(dev, cmd);
  59.         if (handler) {
  60.                 /* Standard and private are not the same */
  61.                 if (cmd < SIOCIWFIRSTPRIV)
  62.                         return standard(dev, iwr, cmd, info, handler);
  63.                 else if (private)
  64.                         return private(dev, iwr, cmd, info, handler);
  65.         }
  66.         /* Old driver API : call driver ioctl handler */
  67.         if (dev->netdev_ops->ndo_do_ioctl) {//whj_note:这里应该不会跑到
  68. #ifdef CONFIG_COMPAT
  69.                 if (info->flags & IW_REQUEST_FLAG_COMPAT) {
  70.                         int ret = 0;
  71.                         struct iwreq iwr_lcl;
  72.                         struct compat_iw_point *iwp_compat = (void *) &iwr->u.data;

  73.                         memcpy(&iwr_lcl, iwr, sizeof(struct iwreq));
  74.                         iwr_lcl.u.data.pointer = compat_ptr(iwp_compat->pointer);
  75.                         iwr_lcl.u.data.length = iwp_compat->length;
  76.                         iwr_lcl.u.data.flags = iwp_compat->flags;

  77.                         ret = dev->netdev_ops->ndo_do_ioctl(dev, (void *) &iwr_lcl, cmd);

  78.                         iwp_compat->pointer = ptr_to_compat(iwr_lcl.u.data.pointer);
  79.                         iwp_compat->length = iwr_lcl.u.data.length;
  80.                         iwp_compat->flags = iwr_lcl.u.data.flags;

  81.                         return ret;
  82.                 } else
  83. #endif
  84.                         return dev->netdev_ops->ndo_do_ioctl(dev, ifr, cmd);
  85.         }
  86.         return -EOPNOTSUPP;
  87. }
  88. static iw_handler get_handler(struct net_device *dev, unsigned int cmd)
  89. {
  90.         /* Don't "optimise" the following variable, it will crash */
  91.         unsigned int index; /* *MUST* be unsigned */
  92.         const struct iw_handler_def *handlers = NULL;

  93. #ifdef CONFIG_CFG80211_WEXT
  94.         if (dev->ieee80211_ptr && dev->ieee80211_ptr->wiphy)
  95.                 handlers = dev->ieee80211_ptr->wiphy->wext;
  96. #endif
  97. #ifdef CONFIG_WIRELESS_EXT
  98.         if (dev->wireless_handlers)
  99.                 handlers = dev->wireless_handlers;
  100. #endif

  101.         if (!handlers)
  102.                 return NULL;

  103.         /* Try as a standard command */
  104.         index = IW_IOCTL_IDX(cmd);
  105.         if (index < handlers->num_standard)
  106.                 return handlers->standard[index];

  107. #ifdef CONFIG_WEXT_PRIV
  108.         /* Try as a private command */
  109.         index = cmd - SIOCIWFIRSTPRIV;
  110.         if (index < handlers->num_private)
  111.                 return handlers->private[index];
  112. #endif

  113.         /* Not found */
  114.         return NULL;
  115. }
2.2.标准socket控制ioctl
而上面的sock->ops->ioctl是来自:(怎么来的看下一文章的第二章节

点击(此处)折叠或打开

  1. struct socket {
  2. ...
  3.     const struct proto_ops *ops;
  4. ...
  5. }
  6. const struct proto_ops inet_stream_ops = {
  7. ...
  8.     .ioctl = inet_ioctl;
  9. ...
  10. }
  11. EXPORT_SYMBOL(inet_stream_ops);
接着看inet_ioctl:

点击(此处)折叠或打开

  1. /linux/net/ipv4/af_inet.c
  2. static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
  3. {
  4. ...
  5.     switch(cmd)
  6.     {
  7. ...
  8.         case SIOCADDRT:
  9.         case SIOCDELRT:
  10.         case SIOCRTMSG:
  11.             return(ip_rt_ioctl(cmd,(void *) arg));//IP路由配置
  12.         case SIOCDARP:
  13.         case SIOCGARP:
  14.         case SIOCSARP:
  15.             return(arp_ioctl(cmd,(void *) arg));//arp配置
  16.         case SIOCGIFADDR:
  17.         case SIOCSIFADDR:
  18.         case SIOCGIFBRDADDR:
  19.         case SIOCSIFBRDADDR:
  20.         case SIOCGIFNETMASK:
  21.         case SIOCSIFNETMASK:
  22.         case SIOCGIFDSTADDR:
  23.         case SIOCSIFDSTADDR:
  24.         case SIOCSIFPFLAGS:
  25.         case SIOCGIFPFLAGS:
  26.         case SIOCSIFFLAGS:
  27.             return(devinet_ioctl(cmd,(void *) arg));//网络接口相关配置(linux内核自带的ifconfig的很多处理都是通过这里实现的)
  28. ...
  29.     }
  30. ...
  31. }
三、关于unlocked_ioctl()与compat_ioctl()取代ioctl()
1.选自ioctl()分析——从用户空间到设备驱动,其中有如下片段直接选用:
  在新版内核中,unlocked_ioctl()与compat_ioctl()取代了ioctl()。unlocked_ioctl(),顾名思义,应该在无大内核锁(BKL)的情况下调用;compat_ioctl(),compat全称compatible(兼容的),主要目的是为64位系统提供32位ioctl的兼容方法,也是在无大内核锁的情况下调用。在《Linux Kernel Development》中对两种ioctl方法有详细的解说。
  tips:在字符设备驱动开发中,一般情况下只要实现unlocked_ioctl()即可,因为在vfs层的代码是直接调用unlocked_ioctl()。
2.关于unlocked_ioctl()取代ioctl()的历史由来,可见对于struct file_operations中ioctl消失的学习笔记
四、课后测试
  如果你真的看懂了本篇关于“设备ioctl”和“网络ioctl”,你对网上的两篇帖子中的话,毫无疑问:
  filp->f_op->ioctl()函数,调用设备对应的ioctl函数;对于使用socket创建文件描述符,它应该调用sock_ioctl()函数
  /*如果filp本身是一个设备,则执行filp->f_op->ioctl()函数,对设备进行ioctl函数操作,该指针在初始化时就已经指向了设备函数接口中的ioctl函数,因此在设备初始化时,只要向内核提交了file_operations{}结构或block_device_operations{},其中的ioctl函数就会被调用到*/
  另外,附上我自己画的函数调用关系图,和如上所参考文章中的函数调用关系图:
1.



2.

阅读(9889) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~