linux 内核 struct file_operations中 ioctl 变为 unlocked_ioctl
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相关推荐
- Linux内核源码中使用宏定义的若干技巧
在C中,宏定义的概念虽然简单,但是真要用好却并不那么容易,下面从Linux源码中抽取一些宏定义的使用方法,希望能从中得到点启发: 1. 类型检查 比如module_init的宏定义: 点击(此处)折叠 ...
- CVE-2021-20226:详解 Linux 内核 IO_URING 子系统中的引用计数漏洞
聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士 趋势科技 ZDI 发布文章,详细描述了2020年6月收到的最近引入的 io_uring 子系统的引用计数漏洞情况.该漏洞导致在任意 fil ...
- 【Linux 内核】Linux 操作系统结构 ( Linux 内核在操作系统中的层级 | Linux 内核子系统及关系 | 进程调度 | 内存管理 | 虚拟文件系统 | 网络管理 | 进程间通信 )
文章目录 一.Linux 内核在操作系统中的层级 二.Linux 内核子系统 三.Linux 内核子系统之间的关系 一.Linux 内核在操作系统中的层级 Linux 内核 所在层级 : 整个计算机系 ...
- 解析Linux内核源码中数据同步问题丨C++后端开发丨Linux服务器开发丨Linux内核开发丨驱动开发丨嵌入式开发丨内核操作系统
剖析Linux内核源码数据同步 1.pdflush机制原理 2.超级块同步/inode同步 3.拥塞及强制回写技术 视频讲解如下,点击观看: 解析Linux内核源码中数据同步问题丨C++后端开发丨Li ...
- linux问号符号,调试linux内核时gdb中的问号符号4.10
我想从linux内核中的函数start_kernel()调试linux内核.调试linux内核时gdb中的问号符号4.10 这基本上就是我已经做了 从kernel.org 下载4.10内核源提取源后: ...
- linux内核完全注释百度网盘,LINUX内核完全注释中.pdf
LINUX内核完全注释中 6.8 floppy.c 程序 122 } 123 printk ("\010\010\010\010\010done \n"); 124 ROOT_DE ...
- linux 内核 数据结构 file_operations、file、inode
文件操作结构 将驱动程序操作连接到设备编号,结构定义在<linux/fs.h>,其中包含一组函数指针,每个打开的文件(在内部由一个file结构表示)和一组函数关联(通过包含指向一个file ...
- uboot通过u盘烧写linux内核,向Flash中烧写uboot和linux操作系统
向Flash中烧写uboot和linux操作系统 2011年03月28日 向Flash中烧写uboot和linux操作系统 ====================================== ...
- linux启动过程中内核拷贝,轻松识破linux内核启动过程中的“”套路“”
内核启动流程相关的内容让很多热爱linux的小伙伴既爱又恨,因为这是了解linux系统基本构造的良好过程同时由于其本身复杂且底层,脑子中的脉络不是很清晰,本文就总结了一些优秀博文,以自己的理解来解构一 ...
最新文章
- KVM虚拟化实践(一)
- data (phantonjs onclick)exploring cleaning
- U811.1接口EAI系列之一--通用把XML传送给EAI处理方法--PowerBuilder语言
- mysql常见错误及解决办法_mysql常见错误代码、原因及处理办法
- linux编译ios动态库,[Linux] linux下生成静态库和动态库
- 苹果从来不飙配置,也从不关注配置,即使一般的配置也能卖好价钱,为啥没人喷?
- JSP 九大内置对象及四大作用域
- mysql存储过程的学习(mysql提高执行效率之进阶过程)
- Ubuntu 16.04下安装激活pycharm 2018.3版本
- kaggle比赛:房价预测(基于MXNet框架)
- Hinduja Global Solutions借助OpManager一年节省300万美元
- 前端开发基础-JavaScript
- linux启动服务日志,linux 服务启动日志
- 扫码枪 - 优惠卷核销
- 鼎捷E10视频教程合集19大模块
- 【CV】国内外优秀的计算机视觉团队汇总|最新版
- 数据库安全那些事儿 访安华金和CEO
- 苹果天气无线网连接到服务器,苹果手机天气怎么设置?教你玩转天气应用
- ElecSuper ESN4485 MOS场效应晶体管
- BentoML核心概念(二):API 和 IO 描述符