对ioctl()和内核头的混淆

对ioctl()和内核头的混淆,c,linux,linux-kernel,linux-device-driver,ioctl,C,Linux,Linux Kernel,Linux Device Driver,Ioctl,据我所知,ioctl()用于向用户空间应用程序公开“扩展”系统调用接口。使用ioctl()通过单个系统调用提供可扩展的特定于驱动程序的函数,而不是添加特定驱动程序特有的数千个系统调用 这似乎很清楚。然而,我正在尝试编译我的第一个使用ioctl()调用的应用程序,我开始怀疑我的理解 具体来说,我想调用ioctl()对eMMC设备进行“消毒”。看看/usr/include/linux/mmc/ioctl.h(或者在内核源代码include/uapi/linux/mmc/ioctl.h),我可以看到这

据我所知,
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;
};
从用户空间,我没有任何问题,包括这个头和将这个结构传递到我的
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);
}
int清理(int-fd)
{
struct mmc_ioc_cmd命令;
memset(&command,0,sizeof(command));
command.write_标志=1;
command.opcode=MMC\U开关;
command.arg=EXT_CSD_SANITIZE_START如果您可以在GCC命令行中包含它,而不添加任何额外的
-I
包含路径,那么您就可以了

我在互联网上看到的一切都表明,在构建用户空间项目时,包含来自内核源的头文件


该建议意味着不要直接从内核源代码树中包含头文件。
uapi
头文件旨在从用户空间中使用,并安装在
/usr/include
MMC_IOC_CMD
ioctl和相应的
MMC_IOC_CMD
结构是Linux用户空间API的一部分,并且refore在安装在
/usr/include
中的
uapi
标题中定义

您在
操作码
字段中输入的值将直接发送到设备。内核并不真正关心它是什么,也不能保证设备支持什么操作码,或者它对任何特定操作码的行为。因此,像
MMC\u开关
这样的操作码不是API的一部分

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


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

这里的情况并非如此。
linux/mmc/ioctl.h
是一个
uapi
标题,并且是公开的。这让我看到了
mmc\u ioc\u cmd
的定义。问题是,
mmc\u ioc\u cmd
在不知道进入其字段的常量/宏的情况下是没有意义的。这些不是
uapi
标题(它们位于
include/linux/mmc/mmc.h
——请注意缺少
uapi
),所以我需要特别地将gcc指向我的内核源代码以查看它们。@Matt:听起来这可能是内核本身的问题。你发电子邮件给该子系统的维护人员询问过吗?@dave:没有。我没有在内核上花太多时间,所以我想我应该确保我没有误解
ioctl()
在对维护人员进行窃听之前。这听起来是一个很好的下一步。FWIW,的源代码包括它自己从内核头派生的头文件。