因此,当我在设备上使用ioctl号码调用ioctl时,它如何知道要调用哪个函数?
答案 0 :(得分:15)
ioctl(2)
通过fs/ioctl.c
函数输入:
SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
{
struct file *filp;
int error = -EBADF;
int fput_needed;
filp = fget_light(fd, &fput_needed);
if (!filp)
goto out;
error = security_file_ioctl(filp, cmd, arg);
if (error)
goto out_fput;
error = do_vfs_ioctl(filp, fd, cmd, arg);
out_fput:
fput_light(filp, fput_needed);
out:
return error;
}
请注意,已存在关联的文件描述符fd
。然后内核调用fget_light()
来查找filp
(粗略地说,文件指针,但不要将其与标准IO FILE *
文件指针混淆)。对security_file_ioctl()
的调用检查加载的安全模块是否允许ioctl
(无论是通过名称,如AppArmor和TOMOYO,还是通过标签,如SMACK和SELinux),以及是否用户具有正确的能力(能力(7))来进行呼叫。如果允许调用,则调用do_vfs_ioctl()
来处理常见的ioctl本身:
switch (cmd) {
case FIOCLEX:
set_close_on_exec(fd, 1);
break;
/* ... */
如果这些常见情况都不正确,那么内核会调用辅助程序:
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;
}
驱动程序提供自己的.unlocked_ioctl
函数指针,就像fs/pipe.c
中的此管道实现一样:
const struct file_operations rdwr_pipefifo_fops = {
.llseek = no_llseek,
.read = do_sync_read,
.aio_read = pipe_read,
.write = do_sync_write,
.aio_write = pipe_write,
.poll = pipe_poll,
.unlocked_ioctl = pipe_ioctl,
.open = pipe_rdwr_open,
.release = pipe_rdwr_release,
.fasync = pipe_rdwr_fasync,
};
答案 1 :(得分:1)
内核中有一张地图。如果你写一个驱动程序,你可以注册自己的ioctl代码。
编辑:我在以太网驱动程序上编写了一次ATA并实现了一个自定义ioctl,用于在运行时调整驱动程序。
答案 2 :(得分:1)
简化说明:
传递给ioctl
的文件描述符指向代表您要进行ioctl的设备的inode
结构。
inode
结构包含设备号dev_t i_rdev
,用作查找设备驱动程序file_operations
结构的索引。在此结构中,有一个指向设备驱动程序定义的ioctl
函数的指针。
您可以阅读Linux Device Drivers, 3rd Edition以获取更详细的说明。它可能有点过时,但仍然是一个很好的阅读。