проект книги: "Модули ядра Linux"

Здесь будут размещаться ссылки и отзывы на интересные публикации по Linux

Модераторы: Olej, vikos

Правила форума
Запрещается помещать сообщения, не имеющие отношения к обсуждаемой статье. Все такие сообщения будут удаляться непосредствено после обнаружения.
bose
Писатель
Сообщения: 107
Зарегистрирован: 23 фев 2012, 14:41
Откуда: Киев
Контактная информация:

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение bose » 29 фев 2012, 22:31

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

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

Re: проект книги: "Модули ядра Linux"

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

bose писал(а):
Olej писал(а): но я не понимаю как (и не понимаю нужно ли) это как-то отмечать в тексте:
Нет, думаю в этом нет практического смысла (описывать все возможные варианты/платформы.).
Просто эта проблема натолкнула на мысль, что, полезно было бы посвятить отдельный пункт, такой не мало важной теме как.... даже не знаю как это обозвать.... что то вроде "конфигурация ядра и условная компиляция". Вот, например, The Kernel Configuration and Build Process - http://www.linuxjournal.com/article/6568?page=0,0 (хотя ресурс старый). Или здесь упомянуто - 7.1 Testing for CONFIG_FOO_BAR Documentation/kbuild/modules.txt .
Modules often need to check for certain CONFIG_ options to
decide if a specific feature is included in the module. In
kbuild this is done by referencing the CONFIG_ variable
directly.
Ну, смысл такой что б во время компиляции уже было понятно, что пытаешься пользоваться возможностями, которые target platform not supported :-)
mm/percpu-km.c:30

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

#if defined(CONFIG_SMP) && defined(CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK)
#error "contiguous percpu allocation is incompatible with paged first chunk"
#endif
Идея заманчивая, и на практике полезная бы...
Но прежде чем с ней разгребаться, как и с всякой новой задумкой, хотелось бы разобраться:

- где? где хранится набор значений конфиг-параметров, использовавшихся при сборке текущего конкретного ядра?

- понятно, что этот набор конфигураций присутствует в:

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

[olej@notebook ~]$ ls /boot/config*
/boot/config-2.6.32.26-175.fc12.i686.PAE  /boot/config-2.6.32.9-70.fc12.i686.PAE
[olej@notebook ~]$ cat /boot/config-2.6.32.9-70.fc12.i686.PAE | head -n10
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.32.9-70.fc12.i686.PAE
# Wed Mar  3 04:54:22 2010
#
# CONFIG_64BIT is not set
CONFIG_X86_32=y
# CONFIG_X86_64 is not set
CONFIG_X86=y
CONFIG_OUTPUT_FORMAT="elf32-i386"
...
но это чисто справочный файл, альтернативный, так сказать old-config для будущих итераций... он может быть просто вытерт пользователем за ненадобностью.
Откуда сценарий сборки вытащит эти данные?

- как может автономно собираемый модуль (даже не в дереве сборки модулей ядра) получать доступ к этому набору значений?

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

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение Olej » 01 мар 2012, 14:08

Olej писал(а): Но прежде чем с ней разгребаться, как и с всякой новой задумкой, хотелось бы разобраться:

- где? где хранится набор значений конфиг-параметров, использовавшихся при сборке текущего конкретного ядра?

- понятно, что этот набор конфигураций присутствует в:

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

[olej@notebook ~]$ ls /boot/config*
/boot/config-2.6.32.26-175.fc12.i686.PAE  /boot/config-2.6.32.9-70.fc12.i686.PAE
[olej@notebook ~]$ cat /boot/config-2.6.32.9-70.fc12.i686.PAE | head -n10
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.32.9-70.fc12.i686.PAE
# Wed Mar  3 04:54:22 2010
#
# CONFIG_64BIT is not set
CONFIG_X86_32=y
# CONFIG_X86_64 is not set
CONFIG_X86=y
CONFIG_OUTPUT_FORMAT="elf32-i386"
...
но это чисто справочный файл, альтернативный, так сказать old-config для будущих итераций... он может быть просто вытерт пользователем за ненадобностью.
Откуда сценарий сборки вытащит эти данные?

- как может автономно собираемый модуль (даже не в дереве сборки модулей ядра) получать доступ к этому набору значений?
тот же /boot/config* - он же в каталоге сборки модулей:

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

[olej@notebook build]$ pwd
/lib/modules/2.6.32.9-70.fc12.i686.PAE/build
[olej@notebook build]$ ls -l .config
-rw-r--r-- 1 root root 106746 Мар  3  2010 .config
[olej@notebook build]$ ls -l /boot/config-2.6.32.9-70.fc12.i686.PAE
-rw-r--r-- 1 root root 106746 Мар  3  2010 /boot/config-2.6.32.9-70.fc12.i686.PAE
это уже устойчивее.

но вот ещё вопрос - с этим понятно:

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

[olej@notebook build]$ cat .config | grep CONFIG_SMP
CONFIG_SMP=y
а с этими что они собираются делать:

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

[olej@notebook build]$ cat .config | grep CONFIG_SMP
CONFIG_SMP=y
[olej@notebook build]$ 
[olej@notebook build]$ cat .config | grep '=m' | head -n5
CONFIG_OPROFILE=m
CONFIG_TOSHIBA=m
CONFIG_I8K=m
CONFIG_MICROCODE=m
CONFIG_HWPOISON_INJECT=m
с этими понятно:

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

[olej@notebook build]$ cat .config | grep 'not set' | head -n5
# CONFIG_64BIT is not set
# CONFIG_X86_64 is not set
# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
# CONFIG_GENERIC_TIME_VSYSCALL is not set
# CONFIG_HAVE_CPUMASK_OF_CPU_MAP is not set
а с этими? :

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

[olej@notebook build]$ cat .config | grep '"' | head -n5
CONFIG_OUTPUT_FORMAT="elf32-i386"
CONFIG_ARCH_DEFCONFIG="arch/x86/configs/i386_defconfig"
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
CONFIG_LOCALVERSION=""
CONFIG_INITRAMFS_SOURCE=""

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

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение Olej » 01 мар 2012, 16:06

Olej писал(а): а с этими? :
Когда уже ничего не помогает, то, как утверждается: "самое время почитать документацию" ;) ... ну, или поспрошать саму систему:

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

#include <linux/module.h>

static int __init hello_init( void ) {
// CONFIG_SMP=y
#if defined(CONFIG_SMP)
   printk( "CONFIG_SMP = %d\n", CONFIG_SMP );
#else
   printk( "CONFIG_SMP не определено\n" );
#endif
// CONFIG_64BIT is not set
#if defined(CONFIG_64BIT)
   printk( "CONFIG_64BIT = %d\n", CONFIG_64BIT );
#else
   printk( "CONFIG_64BIT не определено\n" );
#endif
//CONFIG_MICROCODE=m
#if defined(CONFIG_MICROCODE)
   printk( "CONFIG_MICROCODE = %d\n", CONFIG_MICROCODE );
#else
   printk( "CONFIG_MICROCODE не определено\n" );
#endif
//CONFIG_OUTPUT_FORMAT="elf32-i386"
#if defined(CONFIG_OUTPUT_FORMAT)
   printk( "CONFIG_OUTPUT_FORMAT = %s\n", CONFIG_OUTPUT_FORMAT );
#else
   printk( "CONFIG_OUTPUT_FORMAT не определено\n" );
#endif
   return -1;
}

module_init( hello_init );

MODULE_LICENSE( "GPL" );
MODULE_AUTHOR( "Oleg Tsiliuric <olej@front.ru>" );

- вот такой модуль ядра.
Там есть CONFIG-параметры на любой вкус: определённые как y, как n, как m, и имеющие значение текстовой строки:

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

[olej@notebook config]$ sudo insmod config.ko
insmod: error inserting 'config.ko': -1 Operation not permitted
[olej@notebook config]$ dmesg | tail -n30 | grep CONF
CONFIG_SMP = 1
CONFIG_64BIT не определено
CONFIG_MICROCODE не определено
CONFIG_OUTPUT_FORMAT = elf32-i386
Если я не ошибся (это модуль "сырой" выпечки), то:
- параметры определявшиеся с n & y - не определены ... относительно m мне это не совсем понятно (?)
- параметры определявшиеся с y имеют целочисленное значение 1;
- параметры определявшиеся с значением символьной строки имеют строчное значение самой этой строки.
Откуда я узнал о типах? особенно о последнем? ... конечно, списал с подсказки самой системы:

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

[olej@notebook config]$ make
make -C /lib/modules/2.6.32.9-70.fc12.i686.PAE/build M=/home/olej/2012_WORK/OWN.BOOKS/examples.DRAFT/config modules
make[1]: Entering directory `/usr/src/kernels/2.6.32.9-70.fc12.i686.PAE'
  CC [M]  /home/olej/2012_WORK/OWN.BOOKS/examples.DRAFT/config/config.o
/home/olej/2012_WORK/OWN.BOOKS/examples.DRAFT/config/config.c: В функции ‘hello_init’:
/home/olej/2012_WORK/OWN.BOOKS/examples.DRAFT/config/config.c:24: предупреждение: формат ‘%d’ предполагает тип ‘int’, но аргумент 2 имеет тип ‘char *’
...
Но вот вопрос?!: откуда оно само (ядро) знает о типах своих конфигурационных параметров? и как узнать этот тип наперёд, динамически, а не нарываясь на сообщение о неверном типе?

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

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение Olej » 01 мар 2012, 17:02

Olej писал(а): Но вот вопрос?!: откуда оно само (ядро) знает о типах своих конфигурационных параметров? и как узнать этот тип наперёд, динамически, а не нарываясь на сообщение о неверном типе?
Теперь я могу ответить и на этот вопрос: файл <linux/autoconf.h> в заголовках ядра:

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

[olej@notebook linux]$ pwd
/lib/modules/2.6.32.9-70.fc12.i686.PAE/build/include/linux
[olej@notebook linux]$ cat autoconf.h | grep CONFIG_SMP
#define CONFIG_SMP 1
[olej@notebook linux]$ cat autoconf.h | grep CONFIG_MICROCODE
#define CONFIG_MICROCODE_INTEL 1
#define CONFIG_MICROCODE_MODULE 1
#define CONFIG_MICROCODE_OLD_INTERFACE 1
#define CONFIG_MICROCODE_AMD 1
[olej@notebook linux]$ cat autoconf.h | grep CONFIG_64BIT
[olej@notebook linux]$ cat autoconf.h | grep CONFIG_OUTPUT_FORMAT
#define CONFIG_OUTPUT_FORMAT "elf32-i386"

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

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение Olej » 01 мар 2012, 17:37

bose писал(а): Ну, смысл такой что б во время компиляции уже было понятно, что пытаешься пользоваться возможностями, которые target platform not supported :-)
Уже всё описал и внёс в "Модули ядра Linux".
Спасибо за подсказку.

bose
Писатель
Сообщения: 107
Зарегистрирован: 23 фев 2012, 14:41
Откуда: Киев
Контактная информация:

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение bose » 01 мар 2012, 18:13

А вы обратили внимание что всё что компилируется как модуль в конфигурацию идёт как CONFIG_<MODULE_NAME>_MODULE?

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

// CONFIG_SND_HDA_INTEL=y
#if defined(CONFIG_SND_HDA_INTEL)
   printk( "CONFIG_SND_HDA_INTEL = %d\n", CONFIG_SND_HDA_INTEL );
#else
   printk( "CONFIG_SND_HDA_INTEL not defined\n" );
#endif
// CONFIG_SND_HDA_INTEL=m
#if defined(CONFIG_SND_HDA_INTEL_MODULE)
   printk( "CONFIG_SND_HDA_INTEL_MODULE = %d\n", CONFIG_SND_HDA_INTEL_MODULE );
#else
   printk( "CONFIG_SND_HDA_INTEL_MODULE not defined\n" );
#endif
Т.е. в коде можно проверить

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

#if defined(CONFIG_SND_HDA_INTEL) || defined(CONFIG_SND_HDA_INTEL_MODULE)

bose
Писатель
Сообщения: 107
Зарегистрирован: 23 фев 2012, 14:41
Откуда: Киев
Контактная информация:

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение bose » 01 мар 2012, 18:16

Olej писал(а):
Olej писал(а): Теперь я могу ответить и на этот вопрос: файл <linux/autoconf.h> в заголовках ядра:
Странно у меня он здесь:
/lib/modules/3.0.0-16-generic/build/include/generated/autoconf.h
PS:
Есть вопрос по коду примеров. Сейчас спешу, вечером по возможности, отпишусь.

bose
Писатель
Сообщения: 107
Зарегистрирован: 23 фев 2012, 14:41
Откуда: Киев
Контактная информация:

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение bose » 01 мар 2012, 23:24

bose писал(а): Есть вопрос по коду примеров. Сейчас спешу, вечером по возможности, отпишусь.
Речь идёт о модуле mopen (файл Kexamples.BOOK/dev/mopen/mmopen.c)

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

static ssize_t mopen_read( struct file *f, char *buf, size_t count, loff_t *pos ) {
   static int odd = 0;
   char *buf_msg = get_buffer( f );
   LOG( "read - file: %p, read from %p bytes %d; refcount: %d",
        f, buf_msg, count, module_refcount( THIS_MODULE ) );
   if( 0 == odd ) {
      int res = copy_to_user( (void*)buf, buf_msg, strlen( buf_msg ) );
      odd = 1;
      put_user( '\n', buf + strlen( buf_msg ) );
      res = strlen( buf_msg ) + 1;
      LOG( "return bytes :  %d", res );
      return res;
   }
   odd = 0;
   LOG( "return : EOF" );
   return 0;
}
В функции mopen_read используется статическая переменная odd.
В случае mode=0 или mode=2 вполне допустима следующая ситуация:
1. поток А устанавливает odd в 1 и выходит из функции mopen_read (конца файла ещё нет)
2. поток Б проверяет odd (а она потоком А установлена в 1), устанавливает её в 0 (ничего не передав пользователю, но сказав что уже конец файла)
3. поток А вновь проверяет odd, она равна 0, и всё заново - копирование пользователю, повторный вызов функции.... конец файла
Т.е. - одному ничего, а другому 2 раза )))

Наверное в учебных целях этим можно пренебречь, но может лучше если используются приватные данные (мод=3), то туда запихнуть переменную

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

Re: проект книги: "Модули ядра Linux"

Непрочитанное сообщение Olej » 02 мар 2012, 02:05

bose писал(а):Наверное в учебных целях этим можно пренебречь, но может лучше если используются приватные данные (мод=3), то туда запихнуть переменную
Всё, что связано с переменной odd (во многих примерах, не только этот) связано с желанием использовать естественный тестер POSIX для операций read() - команду cat, которая 1-м запросом read() сосчитает весь объём данных (потому, что читает с запасом ;) - 32767 байт), а 2-м запросом должна получить EOF (читать больше нечего)...
И что делать на следующей команде cat? тупо торчать указателем за концом буфера и так же тупо возвращать EOF? (перезагружайте модуль для следующей операции)...

Поэтому, для простоты демонстраций, сделано, что после EOF состояние уже ранее открытого дескриптора восстанавливается в исходное состояние (откуда и имя переменной: odd - чёт-нечет, на 1-м, 3-м, 5-м .... обращении - возвращаем данные, на 2-м, 4-м, 6-м ... - возвращаем EOF).

Любое другое решение сильно усложняло код, оно, может, и сильно кошерно, но до безобразия противно читать, когда детали заслоняют суть обсуждаемого.

P.S. В этом смысле, я до безобразия не люблю книгу "Linux Device Drivers", ещё называемую в народе LDD3, на которую все ссылаются ... как будто других книг никто не видел.
Именно из-за того, о чём я написал, я считаю эту книгу очень неудачной, из-за того, что их примеры - бесполезны, а без примеров кода всё изложение становится голословным. Их изложение меня просто доводит до бешенства! Насколько лучше:
«Essential Linux Device Drivers», by Sreekrishnan Venkateswaran, Prentice Hall, 2008, p.714.
А уж особенно:
«Writing Linux Device Drivers», Jerry Cooperstein, 2009,
- там берёшь его 2-й том (примеры), и их можно читать без пояснений.
(эти книги есть детально в библиографии в конце текста + к каждой их них URL архивов кодов).

P.P.S. Я ещё раз пересмотрел пример, и понимаю, что это сразу бросилось вам в глаза. И, в принципе, в реале так делать не следует и т.д. - согласен. Но так сделано, мало того что для простоты, ещё и для того, чтобы это было единообразно с предыдущими примерами (довольно многими), чтобы ещё и эти детали не приходилось объяснять ... а читателю ковырять ;).
Так что пусть это место остаётся так, думаю.

Ответить

Вернуться в «Публикации, книги и обсуждения»

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

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