9

Here is the ioctl call in user space:

int ioctl(int fd, int cmd, ...);

As far as I know, when we want to perfrom IO operations, we define our own ioctl function with a set of requests (commands), assign our ioctl to a file_operations structure like this:

struct file_operations fops = {
 .read = device_read,
 .write = device_write,
 .ioctl = device_ioctl, // device_ioctl is our function
 .open = device_open,
 .release = device_release,
};

And the device_ioctl function is defined differently compared to the user space interface:

static long device_ioctl(struct file *f, unsigned int cmd, unsigned long arg)

I think based on the file descriptor, the kernel can get the appropriate file structure and calls the device's ioctl.

This is just a guess because I cannot find it the generic function definition where the kernel selects appropriate ioctl function based on the file descriptor fd passed into the generic ioctl interface? There are only 3 ioctl definitions I can find, but apparently those are just the devices' definitions, not the kernel: ioctl

sergico
  • 2,595
  • 2
  • 29
  • 40
Amumu
  • 17,924
  • 31
  • 84
  • 131
  • 1
    can please let me know what these dots (**.**) mean here and how it is works as function pointer ? I am curious to know. – ind79ra Jun 28 '16 at 10:23
  • @indranil - [How to initialize a struct in accordance with C programming language standards](https://stackoverflow.com/q/330793/608639) – jww Mar 17 '19 at 14:14

4 Answers4

8

Look in the Linux source code, fs/ioctl.c (http://lxr.free-electrons.com/source/fs/ioctl.c)
There you will see the syscall for ioctl:

SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)

This in turns calls do_vfs_ioctl(), which calls vfs_ioctl() which then calls the unlocked_ioctl function defined for that filesystem in the file_operations structure.
This will be your device_ioctl function that you registered.

  • why do we need magic number if our driver ioctl will be called using the fd inode linkage anyways – Haswell Jan 23 '23 at 10:35
3

device_ioctl is a function pointer. The kernel simply takes fd as an index to an array of struct file_operations and calls the .ioctl of the corresponding element. The kernel never needs to knows what the function itself is which device it refers to.

This is the basis of "Everything is a file", which is Unix's moto.

Shahbaz
  • 46,337
  • 19
  • 116
  • 182
  • Thanks. I know it's a function pointer. But where is the place where the generic `ioctl` in user space implemented to correctly select the function in the array of file_operations? – Amumu May 21 '14 at 16:12
  • @Amumu, it's _not_ in user-space at all. The user-space `ioctl` merely calls the ioctl system call, passing in the parameters. It's the generic `ioctl` in _kernel space_ that looks at the array of `struct file_operations`. – Shahbaz May 21 '14 at 16:19
  • @Shabaz I refer to the `ioctl` typically used in user application as user-space `ioctl`. Yes I know it selects appropriate `ioctl` in kernel space. But, I wonder where is the generic `ioctl` in kernel space implemented. I searched, and it only gives 3 definitions, and all these 3 definitions are `ioctl` of drivers: http://lxr.free-electrons.com/ident?i=ioctl – Amumu May 21 '14 at 16:23
  • 1
    Perhaps looking at [fs/ioctl.c](https://github.com/torvalds/linux/blob/master/fs/ioctl.c) may get you somewhere! I don't know about user-space ioctl. As far as I knew, they were a kernel-space implementation. If there is such a thing in user-space, you need to search the implementation of `ioctl` in glibc. – Shahbaz May 21 '14 at 16:23
  • That could be a good hint. I will try to look into glibc. I already looked at `fs/ioctl.c` but still cannot find the exact same definition with the same `ioctl` interface that accepts file descriptor. – Amumu May 21 '14 at 16:30
  • *"This is the basis of "Everything is a file", which is Unix's moto..."* - Yeah, until everything is not and the model breaks down like with serial ports. – jww Mar 17 '19 at 14:23
  • @jww, you can `open()` and `read()`/`write()` to a serial port like normal files. That means a very good deal of any application can be agnostic of the actual underlying "storage" (actual file, sockets, ports etc). That's a very powerful design which certainly outweighs minor nuisances. The fact that I can `echo` into a serial port, with `echo` never even knowing it's dealing with one is truly amazing. – Shahbaz Mar 19 '19 at 04:05
  • @Shahbaz why do we need magic number if our driver ioctl will be called using the fd inode linkage anyways – Haswell Jan 23 '23 at 10:36
1

The kernel will know which ioctl function to call because of the file descriptor. To be able to call an ioctl() from userspace you will have to open a file to get the fd, tipically a /dev/[some_device] whose driver will implement the file_operations struct, as you pointed out.

sergico
  • 2,595
  • 2
  • 29
  • 40
  • why do we need magic number if our driver ioctl will be called using the fd inode linkage anyways – Haswell Jan 23 '23 at 10:36
1

When you call ioctl you pass a file descriptor. You got the file descriptor from opening a device file like /dev/tty0:

$ ls -l /dev/tty0
crw--w---- 1 root tty 4, 0 Mar  6 10:47 /dev/tty0
$

The number 4 here is the device major number which is encoded into the driver module the kernel has to use.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • Do you know where in the kernel code it selects appropriate device `ioctl` based on the fd? – Amumu May 21 '14 at 16:25