Как ioctls знает, какую функцию вызывать в linux? - PullRequest
10 голосов
/ 21 февраля 2011

Итак, когда я вызываю ioctl на устройстве с номером ioctl, как он узнает, какую функцию вызывать?

Ответы [ 3 ]

15 голосов
/ 21 февраля 2011

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

Обратите внимание, что с файловым дескриптором fd уже связан. Затем ядро ​​вызывает fget_light() для поиска filp (грубо говоря, указатель файла, но не путайте это со стандартным указателем файла IO FILE *). Вызов в security_file_ioctl() проверяет, разрешит ли загруженный модуль безопасности ioctl (по имени, как в AppArmor и TOMOYO, или по меткам, как в SMACK и SELinux), а также, имеет ли пользователь правильная возможность (возможности (7)) совершить звонок. Если вызов разрешен, то do_vfs_ioctl() вызывается для обработки самого общего ioctl:

    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,
};
1 голос
/ 21 февраля 2011

Упрощенное объяснение:

Дескриптор файла, который вы передаете ioctl, указывает на структуру inode, которая представляет устройство, к которому вы собираетесь подключиться.

Структура inodeсодержит номер устройства dev_t i_rdev, который используется в качестве индекса для поиска структуры file_operations драйвера устройства.В этой структуре есть указатель на функцию ioctl, определенную драйвером устройства.

Вы можете прочитать Драйверы устройств Linux, 3-е издание для более подробного объяснения.Это может быть немного устаревшим, но, тем не менее, хорошее чтение.

1 голос
/ 21 февраля 2011

В ядре есть карта.Вы можете зарегистрировать свои собственные коды ioctl, если напишите драйвер.

Редактировать: я написал драйвер ATA через Ethernet один раз и реализовал собственный ioctl для настройки драйвера во время выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...