Confusion over ioctl () and kernel headers

As far as I know, ioctl() used to expose the "advanced" system call interface for user space applications. Instead of adding thousands of system calls that are unique to specific drivers, ioctl() used to provide extensible driver-related functions with a single system call.

This seems clear enough. However, I'm trying to compile my first application that uses the ioctl() call, and I'm starting to doubt my understanding.

In particular, I want to make an ioctl() call to "sanitize" an eMMC device. Having looked at /usr/include/linux/mmc/ioctl.h (or in the kernel source code in include/uapi/linux/mmc/ioctl.h ), I see this structure:

 struct mmc_ioc_cmd { // Most fields omitted int write_flag; __u32 opcode; __u32 arg; }; 

From user space, I have no problem including this header and passing this structure to my ioctl() calls.

So this is what my last piece of sanitation looks like:

 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); } 

My problem is that MMC_SWITCH and EXT_CSD_SANITIZE_START defined in the kernel headers. In particular, in my kernel source code they are in include/linux/mmc/mmc.h

Everything I saw on the Internet does not tell the kernel source headers when creating user space projects. If so, how can you reasonably use MMC ioctl() ? The kernel provides a structure to go into ioctl() , but it looks like you can use this structure by filling it with "hidden" constants hidden in the kernel source.

My current solution is to copy the necessary constants from the kernel headers to my own project, but it seems dirty to me.

Have I misunderstood the use case for ioctl() ? Is it design supervision?

+5
source share
2 answers

MMC_IOC_CMD and the corresponding MMC_IOC_CMD structure are part of the Linux user space API and are therefore defined in the uapi headers that are installed in /usr/include .

The value that you put in the opcode field is sent directly to the device. The kernel does not care what it is, and cannot guarantee what operation codes are supported by the device, or how it behaves for any particular operation code. Therefore, opcodes like MMC_SWITCH are not part of the API.

As far as I can tell, you should get the transaction codes from the relevant MMC standards.

(This is not a good reason for these characters to be excluded from the user API; copying the kernel header is much easier than manually transferring the values ​​from the standard, and there is a special case on the kernel for processing EXT_CSD_SANITIZE_START through this ioctl.)

+2
source

If you can #include without adding any additional -I paths to include GCC in your command line, then you're fine.

Everything I've seen on the Internet says it doesn't include headers from the kernel source when creating user space projects.

This tip means not including headers directly from the source kernel tree. uapi headers uapi intended for use in user space and are set to /usr/include .

+1
source

Source: https://habr.com/ru/post/1260171/


All Articles