对 ioctl() 和内核的混淆 headers
Confusion over ioctl() and kernel headers
据我所知,ioctl()
用于向用户空间应用程序公开 "extended" 系统调用接口。 ioctl()
不是添加数千个特定驱动程序独有的系统调用,而是用于通过单个系统调用提供可扩展的 driver-specific 功能。
这似乎很清楚。但是,我正在尝试编译我的第一个使用 ioctl()
调用的应用程序,我开始怀疑我的理解。
具体来说,我想对 "sanitize" 一个 eMMC 设备进行 ioctl()
调用。查看 /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;
};
从用户空间,我没有任何问题,包括这个 header 并将这个结构传递到我的 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);
}
我的问题是 MMC_SWITCH
和 EXT_CSD_SANITIZE_START
都在内核 header 中定义。具体来说,在我的内核源代码中,它们都位于 include/linux/mmc/mmc.h
。
我在 Internet 上看到的所有内容都说 not 在构建用户空间项目时包含来自内核源代码的 headers。那样的话,如何合理使用MMCioctl()
?内核公开要传递给 ioctl()
的结构,但似乎您只能通过在内核源代码中隐藏的 "hidden" 常量填充它来使用该结构。
我目前的解决方案是将必要的常量从内核 headers 复制到我自己的项目中,但这对我来说感觉很脏。
我是否将 use-case 误解为 ioctl()
?这是设计疏忽吗?
如果您可以 #include
它而不添加任何额外的 -I
在您的 GCC 命令行上包含路径,那么您就可以了。
Everything I've seen on the internet says to not include headers from the kernel source when building userspace projects.
该建议意味着不要直接从内核源代码树中包含 headers。 uapi
headers 旨在从用户空间使用,并安装到 /usr/include
。
MMC_IOC_CMD
ioctl 和相应的 mmc_ioc_cmd
结构是 Linux 用户空间 API 的一部分,因此在 uapi
中定义header 安装到 /usr/include
。
您在 opcode
字段中输入的值会直接发送到设备。内核并不真正关心它是什么,也不能保证设备支持什么操作码,或者它对任何特定操作码的行为方式。因此,像 MMC_SWITCH
这样的操作码是 而不是 API.
的一部分
据我所知,您应该从相关的 MMC 标准中获取操作码。
(这并不是将这些符号保留在 user-space API 之外的好理由;复制内核 header 比手动转录标准中的值容易得多.而且内核实际上有一个特例来通过这个ioctl来处理EXT_CSD_SANITIZE_START
。)
据我所知,ioctl()
用于向用户空间应用程序公开 "extended" 系统调用接口。 ioctl()
不是添加数千个特定驱动程序独有的系统调用,而是用于通过单个系统调用提供可扩展的 driver-specific 功能。
这似乎很清楚。但是,我正在尝试编译我的第一个使用 ioctl()
调用的应用程序,我开始怀疑我的理解。
具体来说,我想对 "sanitize" 一个 eMMC 设备进行 ioctl()
调用。查看 /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;
};
从用户空间,我没有任何问题,包括这个 header 并将这个结构传递到我的 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);
}
我的问题是 MMC_SWITCH
和 EXT_CSD_SANITIZE_START
都在内核 header 中定义。具体来说,在我的内核源代码中,它们都位于 include/linux/mmc/mmc.h
。
我在 Internet 上看到的所有内容都说 not 在构建用户空间项目时包含来自内核源代码的 headers。那样的话,如何合理使用MMCioctl()
?内核公开要传递给 ioctl()
的结构,但似乎您只能通过在内核源代码中隐藏的 "hidden" 常量填充它来使用该结构。
我目前的解决方案是将必要的常量从内核 headers 复制到我自己的项目中,但这对我来说感觉很脏。
我是否将 use-case 误解为 ioctl()
?这是设计疏忽吗?
如果您可以 #include
它而不添加任何额外的 -I
在您的 GCC 命令行上包含路径,那么您就可以了。
Everything I've seen on the internet says to not include headers from the kernel source when building userspace projects.
该建议意味着不要直接从内核源代码树中包含 headers。 uapi
headers 旨在从用户空间使用,并安装到 /usr/include
。
MMC_IOC_CMD
ioctl 和相应的 mmc_ioc_cmd
结构是 Linux 用户空间 API 的一部分,因此在 uapi
中定义header 安装到 /usr/include
。
您在 opcode
字段中输入的值会直接发送到设备。内核并不真正关心它是什么,也不能保证设备支持什么操作码,或者它对任何特定操作码的行为方式。因此,像 MMC_SWITCH
这样的操作码是 而不是 API.
据我所知,您应该从相关的 MMC 标准中获取操作码。
(这并不是将这些符号保留在 user-space API 之外的好理由;复制内核 header 比手动转录标准中的值容易得多.而且内核实际上有一个特例来通过这个ioctl来处理EXT_CSD_SANITIZE_START
。)