对于struct file_operations中ioctl消失的学习笔记
2011-12-15 13:21
351 查看
转自:http://qgqceo.chinaunix.com/space.php?uid=20543672&do=blog&id=3015637
很久都没有写驱动代码了,对于一些驱动相关的内核变化也没有怎么关心。这次重游《LDD3》获益良多,其值对于struct file_operations中ioctl的消失也让我长了不少见识。
当年看《LDD3》的时候已经注意到了书中对ioctl的评价不是很好:“ioctl调用的非结构化本质导致众多内核开发者倾向于放弃它。” ,而在这次阅读3.0代码的时候,这个成员在struct file_operations中早已消失了。这个激起了我学习的兴趣,以下是对这个ioctl的学习小结:
1、消失的确切时间
ioctl的消失到底是从哪个版本开始的?网上给出的时间是2.6.36开始。网上就是这么说,但是自己必须找到代码中的证据。于是我通过git搜索主线内核代码,找到的删除ioctl的那个提交:
commit b19dd42faf413b4705d4adb38521e82d73fa4249
Author: Arnd Bergmann <arnd@arndb.de>
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 <arnd@arndb.de>
Cc: John Kacur <jkacur@redhat.com>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
好不容易找到了这个提交,好的,这样就可以确定消失的时间了:
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了。具体的原因在lwn.net中有一篇很好的文章:The
new way of ioctl()。我将他翻译了一下: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;
}
从这个函数中我们可以看出:
ioctl是受到大内核锁保护的,而unlocked_ioctl是直接执行的。
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系统中)产生竞态。(也就实现了用小锁替换大锁)
很久都没有写驱动代码了,对于一些驱动相关的内核变化也没有怎么关心。这次重游《LDD3》获益良多,其值对于struct file_operations中ioctl的消失也让我长了不少见识。
当年看《LDD3》的时候已经注意到了书中对ioctl的评价不是很好:“ioctl调用的非结构化本质导致众多内核开发者倾向于放弃它。” ,而在这次阅读3.0代码的时候,这个成员在struct file_operations中早已消失了。这个激起了我学习的兴趣,以下是对这个ioctl的学习小结:
1、消失的确切时间
ioctl的消失到底是从哪个版本开始的?网上给出的时间是2.6.36开始。网上就是这么说,但是自己必须找到代码中的证据。于是我通过git搜索主线内核代码,找到的删除ioctl的那个提交:
commit b19dd42faf413b4705d4adb38521e82d73fa4249
Author: Arnd Bergmann <arnd@arndb.de>
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 <arnd@arndb.de>
Cc: John Kacur <jkacur@redhat.com>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
好不容易找到了这个提交,好的,这样就可以确定消失的时间了:
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了。具体的原因在lwn.net中有一篇很好的文章:The
new way of ioctl()。我将他翻译了一下: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;
}
从这个函数中我们可以看出:
ioctl是受到大内核锁保护的,而unlocked_ioctl是直接执行的。
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系统中)产生竞态。(也就实现了用小锁替换大锁)
相关文章推荐
- 对于struct file_operations中ioctl消失的学习笔记
- 对于struct file_operations中ioctl消失的学习笔记
- 【转】对于struct file_operations中ioctl消失的学习笔记
- 对于struct file_operations中ioctl消失的学习笔记
- 对于struct file_operations中ioctl消失的学习笔记
- 对于struct file_operations中ioctl消失的学习笔记
- 对于struct file_operations中ioctl消失的学习笔记
- 对于struct file_operations中ioctl消失的学习笔记
- 对于struct file_operations中ioctl消失的学习笔记
- struct file_operations中ioctl消失的学习笔记
- 转载 对于struct file_operations中ioctl消失的学习笔记
- struct file_operations中 ioctl 和 unlocked_ioctl
- Ldd3 学习笔记3 —file_operations
- Linux 驱动学习笔记(file_operations结构体详细分析)
- 在kernel 2.6.36 中已经完全删除了struct file_operations 中的ioctl 函数指针
- Python学习笔记015——文件file的常规操作(二进制文件)
- Android开发学习笔记:数据存取之File浅析
- caffe学习笔记30-关于梯度消失与溢出
- C++学习笔记二十二 - 简单的结构体struct
- Linux学习笔记4 file,文件系统,mkdir,tree,rm,rmdir,touch