не проходит вызов ioctl();

Вопросы программного кода и архитектуры Linux

Модератор: Olej

just_a_student
Писатель
Сообщения: 20
Зарегистрирован: 11 июл 2013, 20:57
Контактная информация:

не проходит вызов ioctl();

Непрочитанное сообщение just_a_student » 01 ноя 2013, 13:01

Здравствуйте!
Столкнулся с непонятной для меня ошибкой:
Есть драйвер, в котором объявлена структура file_operations:

Код: Выделить всё

static struct file_operations fops = {
	.owner        = THIS_MODULE,
	.open         = Open,
	.release      = Close,
        .compat_ioctl = Ioctl,
	.mmap         = Mmap,
};
Из кода тестовой программы происходит вызов:

Код: Выделить всё

::ioctl(arg1, arg2, arg3);
где: arg1 = 3 (файловый дескриптор), arg2 - целое число, arg3 - указатель на первый элемент массива. Все аргументы корректные.
Проблема в том, что функция Ioctl(), описанная в коде драйвера при этом не вызывается. Это установлено точно, с помощью отладочных выводов. А вызов ioctl из тестовой программы возвращает -1 (при том что в коде драйвера в Ioctl() в принципе нет return -1;).
При этом, все остальные функции из file_operations успешно вызываются из тестовой программы (установлено так же с помощью отладочных выводов).

Подскажите пожалуйста, в чем может быть причина этой проблемы и как от нее избавится?
Заранее спасибо!

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: не проходит вызов ioctl();

Непрочитанное сообщение Olej » 01 ноя 2013, 13:45

just_a_student писал(а): Столкнулся с непонятной для меня ошибкой:
1. Как всегда ;-) , : чудес не бывает!
just_a_student писал(а): Есть драйвер, в котором объявлена структура file_operations:

Код: Выделить всё

    static struct file_operations fops = {
       .owner        = THIS_MODULE,
       .open         = Open,
       .release      = Close,
            .compat_ioctl = Ioctl,
       .mmap         = Mmap,
    };
Что-то мне подсказывает ;-) , что там должно быть:

Код: Выделить всё

    .ioctl = Ioctl
И какая у вас версия ядра? ... с чего всегда нужно начинать!
just_a_student писал(а): Из кода тестовой программы происходит вызов:

Код: Выделить всё

::ioctl(arg1, arg2, arg3);
где: arg1 = 3 (файловый дескриптор), arg2 - целое число, arg3 - указатель на первый элемент массива. Все аргументы корректные.
2. Я думаю, что вам это показалось (корректность аргументов) ;-)
- что это за вызов такой ::ioctl() ? ... вы что, на C++ тестовые программы пишете? :-o
- действительно ли открыт дескриптор arg1?
- arg2 - это не "целое число", а код операции IOCTL для этого устройства, ... и именно этот код должен быть определён в тексте драйвера;
just_a_student писал(а): Проблема в том, что функция Ioctl(), описанная в коде драйвера при этом не вызывается. Это установлено точно, с помощью отладочных выводов. А вызов ioctl из тестовой программы возвращает -1 (при том что в коде драйвера в Ioctl() в принципе нет return -1;).
При этом, все остальные функции из file_operations успешно вызываются из тестовой программы (установлено так же с помощью отладочных выводов).
3. А в коде Ioctl() возврата -1 может и не быть - вызов туда просто не доходит.

P.S.
4. Не помещайте подобные темы в раздел программирования!
Это не вопросы программирования вообще, а вопросы структуры ядра Linux, для этого есть соответствующий раздел: Linux изнутри (Вопросы программного кода и архитектуры Linux).

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: не проходит вызов ioctl();

Непрочитанное сообщение Olej » 01 ноя 2013, 14:29

just_a_student писал(а): Проблема в том, что функция Ioctl(), описанная в коде драйвера при этом не вызывается. Это установлено точно, с помощью отладочных выводов.
А я вот слышал такое ;-) :
никогда не говори никогда
just_a_student писал(а): А вызов ioctl из тестовой программы возвращает -1 (при том что в коде драйвера в Ioctl() в принципе нет return -1;).
Отправьтесь в заголовочные файлы ядра, что-то типа: .../linux-headers-3.2.0-4-common/include/asm-generic/errno-base.h

Код: Выделить всё

#define EPERM            1      /* Operation not permitted */
Переводить надо? ;-) ... "нет такой операции" (т.е. вашей ioctl, нужно думать).

Вот как ларчик просто открывался ;-)

just_a_student
Писатель
Сообщения: 20
Зарегистрирован: 11 июл 2013, 20:57
Контактная информация:

Re: не проходит вызов ioctl();

Непрочитанное сообщение just_a_student » 01 ноя 2013, 14:56

Olej писал(а):Что-то мне подсказывает , что там должно быть:
    .ioctl = Ioctl
Таким образом не модуль не компилируется с ошибкой: "неизвестное поле «ioctl» в инициализаторе" Собственно, даже в вашей книге (стр 74 "Символьные устройства") в описании file_operations присутствуют только

Код: Выделить всё

 
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
но нет ioctl. Хотя в примерах используется .ioctl =

Версия ядра: 3.10.12
Olej писал(а):- arg2 - это не "целое число", а код операции IOCTL для этого устройства, ... и именно этот код должен быть определён в тексте драйвера;
Да, он определен следующим образом:

Код: Выделить всё

#define arg2  _IOR('Z', 1, void*)

just_a_student
Писатель
Сообщения: 20
Зарегистрирован: 11 июл 2013, 20:57
Контактная информация:

Re: не проходит вызов ioctl();

Непрочитанное сообщение just_a_student » 01 ноя 2013, 15:01

Olej писал(а):"нет такой операции" (т.е. вашей ioctl, нужно думать).
вот да, но ведь он же есть. Видимо вызов из тестовой программы не соотносится с ioctl в коде модуля. Но в чем причина?

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: не проходит вызов ioctl();

Непрочитанное сообщение Olej » 01 ноя 2013, 15:43

just_a_student писал(а):
Olej писал(а):Что-то мне подсказывает , что там должно быть:
    .ioctl = Ioctl
Таким образом не модуль не компилируется с ошибкой: "неизвестное поле «ioctl» в инициализаторе" Собственно, даже в вашей книге (стр 74 "Символьные устройства") в описании file_operations присутствуют только

Код: Выделить всё

 
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
но нет ioctl. Хотя в примерах используется .ioctl =

Версия ядра: 3.10.12
В принципе - да ;-)
Специально проверил примеры, которые все проверялись в более ранних версиях ядра:

Код: Выделить всё

olej@notebook:~/2013_WORK/OWN.BOOKS/BOOK.Kernel.org/Kexamples.BOOK/dev/ioctl$ make
make -C /lib/modules/3.2.0-4-486/build M=/home/olej/2013_WORK/OWN.BOOKS/BOOK.Kernel.org/Kexamples.BOOK/dev/ioctl modules
make[1]: Entering directory `/usr/src/linux-headers-3.2.0-4-486'
  CC [M]  /home/olej/2013_WORK/OWN.BOOKS/BOOK.Kernel.org/Kexamples.BOOK/dev/ioctl/ioctl_dev.o
/home/olej/2013_WORK/OWN.BOOKS/BOOK.Kernel.org/Kexamples.BOOK/dev/ioctl/ioctl_dev.c:33:4: error: unknown field ‘ioctl’ specified in initializer
/home/olej/2013_WORK/OWN.BOOKS/BOOK.Kernel.org/Kexamples.BOOK/dev/ioctl/ioctl_dev.c:34:1: warning: initialization from incompatible pointer type [enabled by default]
/home/olej/2013_WORK/OWN.BOOKS/BOOK.Kernel.org/Kexamples.BOOK/dev/ioctl/ioctl_dev.c:34:1: warning: (near initialization for ‘hello_fops.write’) [enabled by default]
...
В 3.0.4 уже нет поля с именем ioctl ...
Это обычная практика у разработчиков ядра.
Решается это просто: отправляетесь в заголовочные файлы своего ядра и смотрите там структуру файловых операций...
Иногда нужно позаглядывать ;-) и в файлы реализации ядра (относительно своих операций), это можете смотреть здесь:
Linux Cross Reference
LXR Welcome to lxr.linux.no -- the Linux Cross Reference

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: не проходит вызов ioctl();

Непрочитанное сообщение Olej » 01 ноя 2013, 15:46

just_a_student писал(а):
Olej писал(а):"нет такой операции" (т.е. вашей ioctl, нужно думать).
вот да, но ведь он же есть.
Это как с сусликом: "... а он есть" ;-)

Или как строгий доктор: "... сказал в морг - значит в морг!"

Вы привыкайте с младых лет: если компилятор (линковщик, загрузчик, и т.д. и т.п) сказал "нет" - значит "нет". ;-)

just_a_student
Писатель
Сообщения: 20
Зарегистрирован: 11 июл 2013, 20:57
Контактная информация:

Re: не проходит вызов ioctl();

Непрочитанное сообщение just_a_student » 01 ноя 2013, 15:52

Проблема решена, заменой .compat_ioctl на .unlocked_ioctl:
http://stackoverflow.com/questions/1562 ... g/15629429
Правда причина, почему .compat_ioctl не работал, а .unlocked_ioctl работает для меня так и осталась загадкой...

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: не проходит вызов ioctl();

Непрочитанное сообщение Olej » 01 ноя 2013, 15:55

Olej писал(а): В 3.0.4 уже нет поля с именем ioctl ...
Это обычная практика у разработчиков ядра.
Решается это просто: отправляетесь в заголовочные файлы своего ядра и смотрите там структуру файловых операций...
Вот <linux/fs.f> (3.0.4):

Код: Выделить всё

struct file_operations {
        struct module *owner;
        loff_t (*llseek) (struct file *, loff_t, int);
        ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
        ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
        ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
        int (*readdir) (struct file *, void *, filldir_t);
        unsigned int (*poll) (struct file *, struct poll_table_struct *);
        long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
        long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
...
Они разнесли вызов ioctl() в 2: unlocked_ioctl() + compat_ioctl() ...

Вам теперь осталось выяснить совсем немногое : чем они различаются ;-)

Аватара пользователя
Olej
Писатель
Сообщения: 21338
Зарегистрирован: 24 сен 2011, 14:22
Откуда: Харьков
Контактная информация:

Re: не проходит вызов ioctl();

Непрочитанное сообщение Olej » 01 ноя 2013, 16:00

just_a_student писал(а):Проблема решена, заменой .compat_ioctl на .unlocked_ioctl:
http://stackoverflow.com/questions/1562 ... g/15629429
Правда причина, почему .compat_ioctl не работал, а .unlocked_ioctl работает для меня так и осталась загадкой...
Не должно оставаться никаких загадок! ;-)

Там же в обсуждениях по вашей ссылке написано:
You need to use unlocked_ioctl instead of compat_ioctl. compat_ioctl is to allow 32-bit user space programs to invoke ioctl calls on a 64-bit kernel.
Теперь, в дополнение к версиям ядра, вы ещё разберитесь: какая у вас система - 32 или 64 бит, и с какими библиотеками и как вы компилируете свои приложения (пользовательского пространства).

Ответить

Вернуться в «Linux изнутри»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя