ioctls如何知道在linux中调用哪个函数?

mdo*_*ogg 10 linux linux-kernel

因此,当我在设备上调用ioctl时,使用ioctl编号,它如何知道要调用哪个函数?

sar*_*old 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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,已经存在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;
    /* ... */
Run Code Online (Sandbox Code Playgroud)

如果这些常见情况都不正确,那么内核会调用辅助例程:

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;
}
Run Code Online (Sandbox Code Playgroud)

驱动程序提供自己的.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,
};
Run Code Online (Sandbox Code Playgroud)