1、消失的确切时间
    ioctl的消失到底是从哪个版本开始的?网上给出的时间是2.6.36开始。网上就是这么说,但是自己必须找到代码中的证据。于是我通过git搜索主线内核代码,找到的删除ioctl的那个提交:

commit b19dd42faf413b4705d4adb38521e82d73fa4249
Author: Arnd Bergmann
Date: Sun Jul 4 00:15:10 2010 +0200
bkl: Remove locked .ioctl file operation
The last user is gone, so we can safely remove this
Signed-off-by: Arnd Bergmann
Cc: John Kacur
Cc: Al Viro
Cc: Thomas Gleixner
Signed-off-by: Frederic Weisbecker

好不容易找到了这个提交,好的,这样就可以确定消失的时间了:

git tag --contains b19dd42
v2.6.36
v2.6.36-rc1
v2.6.36-rc2
v2.6.36-rc3
v2.6.36-rc4
v2.6.36-rc5
v2.6.36-rc6
v2.6.36-rc7
v2.6.36-rc8
......以下省略ooxx行

可以证明ioctl消失的版本是v2.6.35到v2.6.36-rc1间,于是我导出了v2.6.35到v2.6.36-rc1的补丁,果真在其中!
git diff v2.6.35..v2.6.36-rc1 > ./temp.patch

2、消失的原因

简单的概括:这次ioctl的消失,并不是要把ioctl清理出去,而是要逐步的清理大内核锁(BKL)。

这个让ioctl消失的过渡期长达5年,从2005年开始内核黑客就开始替换ioctl了。

3、ioctl的替代者

对于原来的ioctl,其实可以叫做locked ioctl。这个其实是相对于他的替代方法来讲的。我们来看看2.6.35以前在struct file_operations中有关ioctl的成员:

/** NOTE:* read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl* can be called without the big kernel lock held in all filesystems.*/
struct file_operations {struct module *owner;loff_t (*llseek) (struct file *, loff_t, int);ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);int (*readdir) (struct file *, void *, filldir_t);unsigned int (*poll) (struct file *, struct poll_table_struct *);int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);long (*compat_ioctl) (struct file *, unsigned int, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct inode *, struct file *);int (*flush) (struct file *, fl_owner_t id);int (*release) (struct inode *, struct file *);int (*fsync) (struct file *, struct dentry *, int datasync);int (*aio_fsync) (struct kiocb *, int datasync);int (*fasync) (int, struct file *, int);int (*lock) (struct file *, int, struct file_lock *);ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);int (*check_flags)(int);int (*flock) (struct file *, int, struct file_lock *);ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);int (*setlease)(struct file *, long, struct file_lock **);
};

这个结构体其实是在过渡期的结构体,unlocked_ioctl就是ioctl的替代者。对于新的驱动,不要再使用ioctl了,而是使用unlocked_ioctl。

4、调用ioctl与unlocked_ioctl在内核代码上的不同

其实ioctl与unlocked_ioctl所对应的系统调用都是ioctl。但是在应用层调用ioctl的时候,对于我们实现ioctl或者unlocked_ioctl有什么不同呢?这里我们可以追溯一下ioctl系统调用代码的执行过程,这里我简单的写出这个系统调用对于设备驱动(一般是设备驱动使用ioctl)的执行顺序: (fs/ioctl.c)

SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)--->do_vfs_ioctl---> vfs_ioctl

而ioctl与unlocked_ioctl的区别就体现在了这个vfs_ioctl中,我们先来看ioctl被删除前的函数:

/*** vfs_ioctl - call filesystem specific ioctl methods* @filp:    open file to invoke ioctl method on* @cmd:    ioctl command to execute* @arg:    command-specific argument for ioctl** Invokes filesystem specific ->unlocked_ioctl, if one exists; otherwise* invokes filesystem specific ->ioctl method. If neither method exists,* returns -ENOTTY.** Returns 0 on success, -errno on error.*/
static long vfs_ioctl(struct file *filp, unsigned int cmd,unsigned long arg)
{int error = -ENOTTY;if (!filp->f_op)goto out;if (filp->f_op->unlocked_ioctl) {error = filp->f_op->unlocked_ioctl(filp, cmd, arg);if (error == -ENOIOCTLCMD)error = -EINVAL;goto out;} else if (filp->f_op->ioctl) {lock_kernel();error = filp->f_op->ioctl(filp->f_path.dentry->d_inode,filp, cmd, arg);unlock_kernel();}out:return error;
}

从这个函数中我们可以看出:

1.ioctl是受到大内核锁保护的,而unlocked_ioctl是直接执行的。

2.unlocked_ioctl优先级高于ioctl,如果存在unlocked_ioctl,则执行unlocked_ioctl,否则才执行ioctl。这个优先级的产生明显是为了过渡。

而在ioctl被删除后,vfs_ioctl函数也做了相应的改变(Linux-3.0):

/*** vfs_ioctl - call filesystem specific ioctl methods* @filp:    open file to invoke ioctl method on* @cmd:    ioctl command to execute* @arg:    command-specific argument for ioctl** Invokes filesystem specific ->unlocked_ioctl, if one exists; otherwise* returns -ENOTTY.** Returns 0 on success, -errno on error.*/
static long vfs_ioctl(struct file *filp, unsigned int cmd,unsigned long arg)
{int error = -ENOTTY;if (!filp->f_op || !filp->f_op->unlocked_ioctl)goto out;error = filp->f_op->unlocked_ioctl(filp, cmd, arg);if (error == -ENOIOCTLCMD)error = -EINVAL;out:return error;
}

5、在驱动编程时的注意事项

在注册文件操作方法的结构体

struct file_operations的时候原先的.ioctl=OOXX;替换为 .unlocked_ioctl=OOXX;

但是要注意ioctl和unlocked_ioctl的定义有一点不同:unlocked_ioctl少了一个inode参数。但是如果方法中真的需要其中的数据,可以通过filp->f_dentry->d_inode获得。

由于失去了大内核锁的保护,所以必须在unlocked_ioctl方法中自行实现锁机制,以保证不会在操作设备的时候(特别在SMP系统中)产生竞态。(也就实现了用小锁替换大锁)

linux 内核 struct file_operations中 ioctl 变为 unlocked_ioctl相关推荐

  1. Linux内核源码中使用宏定义的若干技巧

    在C中,宏定义的概念虽然简单,但是真要用好却并不那么容易,下面从Linux源码中抽取一些宏定义的使用方法,希望能从中得到点启发: 1. 类型检查 比如module_init的宏定义: 点击(此处)折叠 ...

  2. CVE-2021-20226:详解 Linux 内核 IO_URING 子系统中的引用计数漏洞

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士 趋势科技 ZDI 发布文章,详细描述了2020年6月收到的最近引入的 io_uring 子系统的引用计数漏洞情况.该漏洞导致在任意 fil ...

  3. 【Linux 内核】Linux 操作系统结构 ( Linux 内核在操作系统中的层级 | Linux 内核子系统及关系 | 进程调度 | 内存管理 | 虚拟文件系统 | 网络管理 | 进程间通信 )

    文章目录 一.Linux 内核在操作系统中的层级 二.Linux 内核子系统 三.Linux 内核子系统之间的关系 一.Linux 内核在操作系统中的层级 Linux 内核 所在层级 : 整个计算机系 ...

  4. 解析Linux内核源码中数据同步问题丨C++后端开发丨Linux服务器开发丨Linux内核开发丨驱动开发丨嵌入式开发丨内核操作系统

    剖析Linux内核源码数据同步 1.pdflush机制原理 2.超级块同步/inode同步 3.拥塞及强制回写技术 视频讲解如下,点击观看: 解析Linux内核源码中数据同步问题丨C++后端开发丨Li ...

  5. linux问号符号,调试linux内核时gdb中的问号符号4.10

    我想从linux内核中的函数start_kernel()调试linux内核.调试linux内核时gdb中的问号符号4.10 这基本上就是我已经做了 从kernel.org 下载4.10内核源提取源后: ...

  6. linux内核完全注释百度网盘,LINUX内核完全注释中.pdf

    LINUX内核完全注释中 6.8 floppy.c 程序 122 } 123 printk ("\010\010\010\010\010done \n"); 124 ROOT_DE ...

  7. linux 内核 数据结构 file_operations、file、inode

    文件操作结构 将驱动程序操作连接到设备编号,结构定义在<linux/fs.h>,其中包含一组函数指针,每个打开的文件(在内部由一个file结构表示)和一组函数关联(通过包含指向一个file ...

  8. uboot通过u盘烧写linux内核,向Flash中烧写uboot和linux操作系统

    向Flash中烧写uboot和linux操作系统 2011年03月28日 向Flash中烧写uboot和linux操作系统 ====================================== ...

  9. linux启动过程中内核拷贝,轻松识破linux内核启动过程中的“”套路“”

    内核启动流程相关的内容让很多热爱linux的小伙伴既爱又恨,因为这是了解linux系统基本构造的良好过程同时由于其本身复杂且底层,脑子中的脉络不是很清晰,本文就总结了一些优秀博文,以自己的理解来解构一 ...

最新文章

  1. KVM虚拟化实践(一)
  2. data (phantonjs onclick)exploring cleaning
  3. U811.1接口EAI系列之一--通用把XML传送给EAI处理方法--PowerBuilder语言
  4. mysql常见错误及解决办法_mysql常见错误代码、原因及处理办法
  5. linux编译ios动态库,[Linux] linux下生成静态库和动态库
  6. 苹果从来不飙配置,也从不关注配置,即使一般的配置也能卖好价钱,为啥没人喷?
  7. JSP 九大内置对象及四大作用域
  8. mysql存储过程的学习(mysql提高执行效率之进阶过程)
  9. Ubuntu 16.04下安装激活pycharm 2018.3版本
  10. kaggle比赛:房价预测(基于MXNet框架)
  11. Hinduja Global Solutions借助OpManager一年节省300万美元
  12. 前端开发基础-JavaScript
  13. linux启动服务日志,linux 服务启动日志
  14. 扫码枪 - 优惠卷核销
  15. 鼎捷E10视频教程合集19大模块
  16. 【CV】国内外优秀的计算机视觉团队汇总|最新版
  17. 数据库安全那些事儿 访安华金和CEO
  18. 苹果天气无线网连接到服务器,苹果手机天气怎么设置?教你玩转天气应用
  19. ElecSuper ESN4485 MOS场效应晶体管
  20. BentoML核心概念(二):API 和 IO 描述符

热门文章

  1. MOS管好坏的判别方法
  2. Linux - Red Hat 7.3 介绍安装
  3. 网站被黑搜索快照被劫持怎么办
  4. 数据结构-王道-树和二叉树
  5. VR跨界一触即发,探秘87870“魔都之夜”VR派对
  6. 各种编程语言功能综合简要介绍(C,C++,JAVA,PHP,PYTHON,易语言)
  7. linux密码修改实验
  8. 电商啥职位最赚钱?投资薪资最高,客服垫底
  9. 关于mysql的调优
  10. ActiveReports 报表应用教程 (2)---清单类报表