Linux如何知道调用哪个ioctl函数?

9

这里是用户空间中的 ioctl 调用:

int ioctl(int fd, int cmd, ...);

据我所知,当我们想要执行IO操作时,我们需要定义自己的ioctl函数和一组请求(命令),将我们的ioctl赋值给file_operations结构体,代码如下:
struct file_operations fops = {
 .read = device_read,
 .write = device_write,
 .ioctl = device_ioctl, // device_ioctl is our function
 .open = device_open,
 .release = device_release,
};

而且,与用户空间接口相比,device_ioctl函数的定义有所不同:

static long device_ioctl(struct file *f, unsigned int cmd, unsigned long arg)

我认为基于文件描述符,内核可以获得适当的文件结构并调用设备的ioctl函数。这只是猜测,因为我找不到内核根据传递给通用ioctl接口的文件描述符fd选择适当的ioctl函数的通用函数定义。我只能找到3个ioctl定义,但显然这些只是设备的定义,而不是内核的定义:ioctl

1
请问这里的点号(**.**)是什么意思,它如何作为函数指针工作?我很想知道。 - ind79ra
4个回答

8

请查看Linux源代码,fs/ioctl.c文件(http://lxr.free-electrons.com/source/fs/ioctl.c)。


您会看到ioctl的系统调用:

SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)

这将调用do_vfs_ioctl(),该函数调用vfs_ioctl(),然后调用文件操作结构中为该文件系统定义的unlocked_ioctl函数。
这将是您注册的device_ioctl函数。


我们的驱动 ioctl 将使用 fd inode 链接进行调用,那么为什么我们需要神秘数字呢? - Haswell

3

device_ioctl 是一个函数指针。内核仅将 fd 作为索引传递给 struct file_operations 数组的对应元素,并调用其 .ioctl 函数。内核从不需要知道函数本身是哪个设备的。

这就是“一切皆文件”的基础,这是 Unix 的口号。


谢谢。我知道这是一个函数指针。但是在用户空间中实现通用的ioctl以正确选择文件操作数组中的函数的位置在哪里? - Amumu
@Shabaz 我指的是通常在用户应用程序中使用的 ioctl,也称为用户空间 ioctl。是的,我知道它会在内核空间选择适当的 ioctl。但是,我想知道通用的内核空间 ioctl 是在哪里实现的。我进行了搜索,只找到了 3 个定义,而这 3 个定义都是驱动程序的 ioctl:http://lxr.free-electrons.com/ident?i=ioctl - Amumu
1
也许查看fs/ioctl.c可以帮到你!我不知道用户空间的ioctl。据我所知,它们是内核空间实现。如果在用户空间中有这样的东西,您需要搜索glibc中的ioctl实现。 - Shahbaz
那可能是一个不错的提示。我会尝试查看glibc。我已经查看了fs/ioctl.c,但仍然找不到完全相同的定义,具有接受文件描述符的相同ioctl接口。 - Amumu
@jww,您可以像操作普通文件一样open()read()/write()串行端口。这意味着任何应用程序的很大一部分都可以对实际底层“存储”(实际文件、套接字、端口等)保持不可知。这是一个非常强大的设计,肯定比小问题更重要。我可以使用echo命令将数据发送到串行端口,而echo命令甚至不知道自己正在处理一个串行端口,这真是太神奇了。 - Shahbaz
显示剩余3条评论

1
内核会根据文件描述符知道调用哪个ioctl函数。 要从用户空间调用ioctl(),您需要打开一个文件以获取fd,通常是/dev/[some_device],其驱动程序将实现file_operations结构,正如您所指出的那样。

我们的驱动程序 ioctl 将使用 fd inode 链接进行调用,为什么还需要魔数呢? - Haswell

1
当您调用ioctl时,需要传递文件描述符。您可以通过打开设备文件(如/dev/tty0)来获取文件描述符:
$ ls -l /dev/tty0
crw--w---- 1 root tty 4, 0 Mar  6 10:47 /dev/tty0
$

这里的数字4是设备主要编号,需要编码到内核驱动模块中以供使用。

你知道内核代码中在哪里基于文件描述符选择适当的设备ioctl吗? - Amumu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接