Итак, когда я вызываю ioctl на устройстве, с номером ioctl, как он узнает, какую функцию вызывать?
Как ioctls знает, какую функцию вызывать в linux?
Ответ 1
ioctl(2)
входит через функцию fs/ioctl.c
:
SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
{
struct file *filp;
int error = -EBADF;
int fput_needed;
filp = fget_light(fd, &fput_needed);
if (!filp)
goto out;
error = security_file_ioctl(filp, cmd, arg);
if (error)
goto out_fput;
error = do_vfs_ioctl(filp, fd, cmd, arg);
out_fput:
fput_light(filp, fput_needed);
out:
return error;
}
Обратите внимание, что уже связан файл filedescriptor fd
. Затем ядро вызывает fget_light()
для поиска filp
(грубо говоря, указателя файла, но не путайте его со стандартным указателем файла IO FILE *
). Вызов в security_file_ioctl()
проверяет, будет ли загруженный модуль безопасности разрешать ioctl
(будь то по имени, как в AppArmor и TOMOYO, или по меткам, как в SMACK и SELinux), а также, имеет ли пользователь правильная возможность (возможности (7)) для совершения вызова. Если вызов разрешен, то do_vfs_ioctl()
вызывается для обработки самих общих ioctls:
switch (cmd) {
case FIOCLEX:
set_close_on_exec(fd, 1);
break;
/* ... */
Если ни один из этих распространенных случаев не верен, ядро вызывает вспомогательную процедуру:
static long vfs_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg)
{
int error = -ENOTTY;
if (!filp->f_op || !filp->f_op->unlocked_ioctl)
goto out;
error = filp->f_op->unlocked_ioctl(filp, cmd, arg);
if (error == -ENOIOCTLCMD)
error = -EINVAL;
out:
return error;
}
Драйверы снабжают свой собственный указатель функции .unlocked_ioctl
, как и эта реализация в fs/pipe.c
:
const struct file_operations rdwr_pipefifo_fops = {
.llseek = no_llseek,
.read = do_sync_read,
.aio_read = pipe_read,
.write = do_sync_write,
.aio_write = pipe_write,
.poll = pipe_poll,
.unlocked_ioctl = pipe_ioctl,
.open = pipe_rdwr_open,
.release = pipe_rdwr_release,
.fasync = pipe_rdwr_fasync,
};
Ответ 2
В ядре есть карта. Вы можете зарегистрировать свои собственные коды ioctl, если вы пишете драйвер.
Изменить: я однажды написал драйвер ATA через Ethernet и внедрил пользовательский ioctl для настройки драйвера во время выполнения.
Ответ 3
Упрощенное объяснение:
Дескриптор файла, который вы передаете в ioctl
, указывает на структуру inode
, которая представляет устройство, которое вы собираетесь ioctl.
Структура inode
содержит номер устройства dev_t i_rdev
, который используется как индекс для поиска структуры драйвера file_operations
. В этой структуре есть указатель на функцию ioctl
, определенную драйвером устройства.
Вы можете прочитать драйверы устройств Linux, 3-е издание для более подробного объяснения. Это может быть немного устаревшим, но, тем не менее, хорошим чтением.