Страница 1 из 2
не проходит вызов ioctl();
Добавлено: 01 ноя 2013, 13:01
just_a_student
Здравствуйте!
Столкнулся с непонятной для меня ошибкой:
Есть драйвер, в котором объявлена структура file_operations:
Код: Выделить всё
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = Open,
.release = Close,
.compat_ioctl = Ioctl,
.mmap = Mmap,
};
Из кода тестовой программы происходит вызов:
где: arg1 = 3 (файловый дескриптор), arg2 - целое число, arg3 - указатель на первый элемент массива. Все аргументы корректные.
Проблема в том, что функция Ioctl(), описанная в коде драйвера при этом не вызывается. Это установлено точно, с помощью отладочных выводов. А вызов ioctl из тестовой программы возвращает -1 (при том что в коде драйвера в Ioctl() в принципе нет return -1;).
При этом, все остальные функции из file_operations успешно вызываются из тестовой программы (установлено так же с помощью отладочных выводов).
Подскажите пожалуйста, в чем может быть причина этой проблемы и как от нее избавится?
Заранее спасибо!
Re: не проходит вызов ioctl();
Добавлено: 01 ноя 2013, 13:45
Olej
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,
};
Что-то мне подсказывает
, что там должно быть:
И какая у вас версия ядра? ...
с чего всегда нужно начинать!
just_a_student писал(а):
Из кода тестовой программы происходит вызов:
где: arg1 = 3 (файловый дескриптор), arg2 - целое число, arg3 - указатель на первый элемент массива. Все аргументы корректные.
2. Я думаю, что вам это показалось (корректность аргументов)
- что это за вызов такой ::ioctl() ? ... вы что, на C++ тестовые программы пишете?
- действительно ли открыт дескриптор arg1?
- arg2 - это не "целое число", а
код операции IOCTL для этого устройства, ... и именно этот код должен быть определён в тексте драйвера;
just_a_student писал(а):
Проблема в том, что функция Ioctl(), описанная в коде драйвера при этом не вызывается. Это установлено точно, с помощью отладочных выводов. А вызов ioctl из тестовой программы возвращает -1 (при том что в коде драйвера в Ioctl() в принципе нет return -1;).
При этом, все остальные функции из file_operations успешно вызываются из тестовой программы (установлено так же с помощью отладочных выводов).
3. А в коде Ioctl() возврата -1 может и не быть - вызов туда просто не доходит.
P.S.
4. Не помещайте подобные темы в раздел программирования!
Это не вопросы программирования вообще, а вопросы структуры ядра Linux, для этого есть соответствующий раздел:
Linux изнутри (Вопросы программного кода и архитектуры Linux).
Re: не проходит вызов ioctl();
Добавлено: 01 ноя 2013, 14:29
Olej
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, нужно думать).
Вот как ларчик просто открывался
Re: не проходит вызов ioctl();
Добавлено: 01 ноя 2013, 14:56
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 писал(а):- arg2 - это не "целое число", а код операции IOCTL для этого устройства, ... и именно этот код должен быть определён в тексте драйвера;
Да, он определен следующим образом:
Re: не проходит вызов ioctl();
Добавлено: 01 ноя 2013, 15:01
just_a_student
Olej писал(а):"нет такой операции" (т.е. вашей ioctl, нужно думать).
вот да, но ведь он же есть. Видимо вызов из тестовой программы не соотносится с ioctl в коде модуля. Но в чем причина?
Re: не проходит вызов ioctl();
Добавлено: 01 ноя 2013, 15:43
Olej
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
Re: не проходит вызов ioctl();
Добавлено: 01 ноя 2013, 15:46
Olej
just_a_student писал(а):Olej писал(а):"нет такой операции" (т.е. вашей ioctl, нужно думать).
вот да, но ведь он же есть.
Это как с сусликом: "... а он есть"
Или как строгий доктор: "... сказал в морг - значит в морг!"
Вы привыкайте с младых лет: если компилятор (линковщик, загрузчик, и т.д. и т.п) сказал "нет" - значит "нет".
Re: не проходит вызов ioctl();
Добавлено: 01 ноя 2013, 15:52
just_a_student
Проблема решена, заменой .compat_ioctl на .unlocked_ioctl:
http://stackoverflow.com/questions/1562 ... g/15629429
Правда причина, почему .compat_ioctl не работал, а .unlocked_ioctl работает для меня так и осталась загадкой...
Re: не проходит вызов ioctl();
Добавлено: 01 ноя 2013, 15:55
Olej
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() ...
Вам теперь осталось выяснить совсем немногое : чем они различаются
Re: не проходит вызов ioctl();
Добавлено: 01 ноя 2013, 16:00
Olej
Не должно оставаться никаких загадок!
Там же в обсуждениях по вашей ссылке написано:
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 бит, и с какими библиотеками и как вы компилируете свои приложения (пользовательского пространства).