对ioctl()和内核头文件的困惑

Mat*_*t K 5 c linux ioctl linux-device-driver linux-kernel

据我所知,ioctl()用于向用户空间应用程序公开"扩展"系统调用接口.而不是添加数千个特定驱动程序独有的系统调用,ioctl()用于通过单个系统调用提供可扩展的驱动程序特定功能.

这看起来很清楚.但是,我正在尝试编译我的第一个使用ioctl()呼叫的应用程序,我开始怀疑我的理解.

具体来说,我想ioctl()打电话给"消毒"eMMC设备.看一下/usr/include/linux/mmc/ioctl.h(或者在内核源代码中include/uapi/linux/mmc/ioctl.h),我可以看到这个结构:

struct mmc_ioc_cmd {
        // Most fields omitted
        int write_flag;    
        __u32 opcode;
        __u32 arg;
};
Run Code Online (Sandbox Code Playgroud)

从用户空间,我没有任何问题,包括这个标题,并将此结构传递给我的ioctl()调用.

所以这就是我的最终消毒片段:

int sanitize(int fd)
{
  struct mmc_ioc_cmd command;
  memset(&command, 0, sizeof(command));

  command.write_flag = 1;
  command.opcode = MMC_SWITCH;
  command.arg = EXT_CSD_SANITIZE_START << 16;

  return ioctl(fd, MMC_IOC_CMD, &command);
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,MMC_SWITCH并且EXT_CSD_SANITIZE_START都在内核头文件中定义.具体来说,在我的内核源代码中,它们都被发现了include/linux/mmc/mmc.h.

我在互联网上看到的一切都说在构建用户空间项目时包含来自内核源代码的头文件.如果是这样的话,你怎么能合理地使用MMC ioctl()?内核公开了要传入的结构ioctl(),但似乎只能通过在内核源代码中隐藏的"隐藏"常量填充它来使用该结构.

我目前的解决方案是将必要的常量从内核头文件复制到我自己的项目中,但这对我来说很脏.

我误解了用例ioctl()吗?这是设计疏忽吗?

CL.*_*CL. 2

ioctlMMC_IOC_CMD和相应的mmc_ioc_cmd结构是 Linux 用户空间 API 的一部分,因此在uapi安装到的标头中定义/usr/include.

您输入该opcode字段的值将直接发送到设备。内核并不真正关心它是什么,并且不能保证设备支持哪些操作码,或者它对于任何特定操作码的行为如何。因此,类似的操作MMC_SWITCH不是的一部分。

据我所知,您应该从相关的 MMC 标准获取操作码。

(这并不是将这些符号保留在用户空间 API 之外的好理由;复制内核头比手动转录标准中的值要容易得多。并且内核实际上有一个通过EXT_CSD_SANITIZE_START此 ioctl 进行处理的特殊情况。 )